stats: add /if/<n>/<n>/state for lacp interface state

Add /if/lacp/<bond-sw_if_index>/<slave-sw_if_index>/state

<bond-sw_if_index> is a vector of the bond sw_if_index
<slave-sw_if_index> is a vector of the slave sw_if_index
Content is the integer value of the lacp actor state. The state is actually
a bitfield as described in the lacp protocol spec.

Type: feature

Signed-off-by: Steven Luong <sluong@cisco.com>
Change-Id: Ic6eca8ce2a1acd2d858e4e50b7eac1d000ea08e5
Signed-off-by: Ole Troan <ot@cisco.com>
diff --git a/src/vnet/bonding/cli.c b/src/vnet/bonding/cli.c
index f45a31c..4e0d30a 100644
--- a/src/vnet/bonding/cli.c
+++ b/src/vnet/bonding/cli.c
@@ -20,6 +20,7 @@
 #include <vlib/unix/unix.h>
 #include <vnet/ethernet/ethernet.h>
 #include <vnet/bonding/node.h>
+#include <vpp/stats/stat_segment.h>
 
 void
 bond_disable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
@@ -96,7 +97,9 @@
     }
   clib_spinlock_unlock_if_init (&bif->lockp);
 
-  return;
+  if (bif->mode == BOND_MODE_LACP)
+    stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
+				    [sif->sw_if_index], sif->actor.state);
 }
 
 void
@@ -165,7 +168,9 @@
     }
   clib_spinlock_unlock_if_init (&bif->lockp);
 
-  return;
+  if (bif->mode == BOND_MODE_LACP)
+    stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
+				    [sif->sw_if_index], sif->actor.state);
 }
 
 int
@@ -278,6 +283,10 @@
   if ((bif->mode == BOND_MODE_LACP) && bm->lacp_enable_disable)
     (*bm->lacp_enable_disable) (vm, bif, sif, 0);
 
+  if (bif->mode == BOND_MODE_LACP)
+    stat_segment_deregister_state_counter
+      (bm->stats[bif->sw_if_index][sif->sw_if_index]);
+
   pool_put (bm->neighbors, sif);
 }
 
@@ -573,6 +582,24 @@
 	clib_error_return (0, "bond interface cannot be enslaved");
       return;
     }
+  if (bif->mode == BOND_MODE_LACP)
+    {
+      u8 *name = format (0, "/if/lacp/%u/%u/state", bif->sw_if_index,
+			 args->slave);
+
+      vec_validate (bm->stats, bif->sw_if_index);
+      vec_validate (bm->stats[bif->sw_if_index], args->slave);
+
+      args->error = stat_segment_register_state_counter
+	(name, &bm->stats[bif->sw_if_index][args->slave]);
+      vec_free (name);
+      if (args->error != 0)
+	{
+	  args->rv = VNET_API_ERROR_INVALID_INTERFACE;
+	  return;
+	}
+    }
+
   pool_get (bm->neighbors, sif);
   clib_memset (sif, 0, sizeof (*sif));
   sw = pool_elt_at_index (im->sw_interfaces, args->slave);