Bugfix in routing logic to avoid null groups; Improvement in group handling.

Two main changes for the bug-fix:
    - avoid doing a full-reroute in the event of link failure as this will leave behind stale state in stores
      if event has been preceded by mastership change leading to the nuking of the ecmpSpg for one of the
      link's devices; instead do a rehash
    - when full-reroute is attempted, do it only once, with a complete nuke of the next-obj store

Improvement in group handling allows for a max number of retries for a group that failed to be added.
Earlier behavior was to try only once, and if it fails, it gets removed from the group-store. Now it
is removed after a couple of retries - so total 3 attempts to program the group.

Change-Id: I54ca8203cef779463522b01353540d12f8be3c91
diff --git a/core/api/src/main/java/org/onosproject/net/group/DefaultGroup.java b/core/api/src/main/java/org/onosproject/net/group/DefaultGroup.java
index 90da929..d0777ec 100644
--- a/core/api/src/main/java/org/onosproject/net/group/DefaultGroup.java
+++ b/core/api/src/main/java/org/onosproject/net/group/DefaultGroup.java
@@ -36,6 +36,7 @@
     private long referenceCount;
     private GroupId id;
     private int age;
+    private int failedRetryCount;
 
     /**
      * Initializes default values.
@@ -50,6 +51,7 @@
         bytes = 0;
         referenceCount = 0;
         age = 0;
+        failedRetryCount = 0;
     }
 
     /**
@@ -135,6 +137,11 @@
         return age;
     }
 
+    @Override
+    public int failedRetryCount() {
+        return failedRetryCount;
+    }
+
     /**
      * Sets the new state for this entry.
      *
@@ -190,6 +197,16 @@
         return referenceCount;
     }
 
+    @Override
+    public void incrFailedRetryCount() {
+        failedRetryCount++;
+    }
+
+    @Override
+    public void setFailedRetryCount(int failedRetryCount) {
+        this.failedRetryCount = failedRetryCount;
+    }
+
     /*
      * The deviceId, type and buckets are used for hash.
      *
diff --git a/core/api/src/main/java/org/onosproject/net/group/Group.java b/core/api/src/main/java/org/onosproject/net/group/Group.java
index 39c6a3d..dd2aa63 100644
--- a/core/api/src/main/java/org/onosproject/net/group/Group.java
+++ b/core/api/src/main/java/org/onosproject/net/group/Group.java
@@ -105,4 +105,12 @@
      * @return the age of the group as an integer
      */
     int age();
+
+    /**
+     * Returns the count for the number of attempts at programming a failed
+     * group.
+     *
+     * @return the count for the number of failed attempts at programming this group
+     */
+    int failedRetryCount();
 }
diff --git a/core/api/src/main/java/org/onosproject/net/group/StoredGroupEntry.java b/core/api/src/main/java/org/onosproject/net/group/StoredGroupEntry.java
index 6d22fa7..760fc5a 100644
--- a/core/api/src/main/java/org/onosproject/net/group/StoredGroupEntry.java
+++ b/core/api/src/main/java/org/onosproject/net/group/StoredGroupEntry.java
@@ -72,4 +72,20 @@
      * @param referenceCount reference count
      */
     void setReferenceCount(long referenceCount);
+
+    /**
+     * Increments the count for the number of failed attempts in programming
+     * this group.
+     *
+     */
+    void incrFailedRetryCount();
+
+    /**
+     * Sets the count for the number of failed attempts in programming this
+     * group.
+     *
+     * @param failedRetryCount count for number of failed attempts in
+     *            programming this group
+     */
+    void setFailedRetryCount(int failedRetryCount);
 }
diff --git a/core/api/src/test/java/org/onosproject/net/group/DefaultGroupTest.java b/core/api/src/test/java/org/onosproject/net/group/DefaultGroupTest.java
index 0c7df81..e8fb7b3 100644
--- a/core/api/src/test/java/org/onosproject/net/group/DefaultGroupTest.java
+++ b/core/api/src/test/java/org/onosproject/net/group/DefaultGroupTest.java
@@ -85,6 +85,7 @@
         assertThat(group1.referenceCount(), is(0L));
         assertThat(group1.buckets(), is(groupBuckets));
         assertThat(group1.state(), is(Group.GroupState.PENDING_ADD));
+        assertThat(group1.failedRetryCount(), is(0));
     }
 
     /**
@@ -101,5 +102,22 @@
         assertThat(group.referenceCount(), is(0L));
         assertThat(group.deviceId(), is(NetTestTools.did("1")));
         assertThat(group.buckets(), is(groupBuckets));
+        assertThat(group.failedRetryCount(), is(0));
+    }
+
+    /**
+     * Test failedRetryCount field.
+     */
+    @Test
+    public void checkFailedRetyCount() {
+        assertThat(group1.failedRetryCount(), is(0));
+        group1.incrFailedRetryCount();
+        assertThat(group1.failedRetryCount(), is(1));
+        group1.setFailedRetryCount(3);
+        assertThat(group1.failedRetryCount(), is(3));
+        group1.incrFailedRetryCount();
+        assertThat(group1.failedRetryCount(), is(4));
+        group1.setFailedRetryCount(0);
+        assertThat(group1.failedRetryCount(), is(0));
     }
 }