lacp: passive mode support [VPP-1551] 35/18035/4
authorSteven Luong <sluong@cisco.com>
Tue, 5 Mar 2019 17:38:33 +0000 (09:38 -0800)
committerDamjan Marion <dmarion@me.com>
Wed, 3 Apr 2019 16:32:37 +0000 (16:32 +0000)
By definition, passive mode means the node does not start sending lacp pdu until
it first hears from the partner or remote.

- Rename ptx machine's BEGIN state to NO_PERIODIC state.
- Put periodic machine in NO_PERIDOIC state when the interface is enabled for
lacp. ptx machine will transition out of NO_PERIODIC state when the local node
hears from the remote or when the local node is configured for active mode.
- Also add send and receive statistics for debugging.

Change-Id: I747953b9595ed31328b2f4f3e7a8d15d01e04d7f
Signed-off-by: Steven Luong <sluong@cisco.com>
src/plugins/lacp/cli.c
src/plugins/lacp/input.c
src/plugins/lacp/lacp.c
src/plugins/lacp/ptx_machine.c
src/plugins/lacp/ptx_machine.h
src/plugins/lacp/rx_machine.c
src/plugins/lacp/tx_machine.c
src/vnet/bonding/node.h

index d210139..d188db6 100644 (file)
@@ -159,6 +159,29 @@ show_lacp_details (vlib_main_t * vm, u32 * sw_if_indices)
        continue;
       vlib_cli_output (vm, "  %U", format_vnet_sw_if_index_name,
                       vnet_get_main (), sif->sw_if_index);
+      vlib_cli_output (vm, "    Good LACP PDUs received: %llu",
+                      sif->pdu_received);
+      vlib_cli_output (vm, "    Bad LACP PDUs received: %llu",
+                      sif->bad_pdu_received);
+      vlib_cli_output (vm, "    LACP PDUs sent: %llu", sif->pdu_sent);
+      if (lacp_timer_is_running (sif->last_lacpdu_recd_time))
+       vlib_cli_output (vm,
+                        "    last LACP PDU received: %10.2f seconds ago",
+                        now - sif->last_lacpdu_recd_time);
+      if (lacp_timer_is_running (sif->last_lacpdu_sent_time))
+       vlib_cli_output (vm, "    last LACP PDU sent: %10.2f seconds ago",
+                        now - sif->last_lacpdu_sent_time);
+      vlib_cli_output (vm, "    Good Marker PDUs received: %llu",
+                      sif->marker_pdu_received);
+      vlib_cli_output (vm, "    Bad Marker PDUs received: %llu",
+                      sif->marker_bad_pdu_received);
+      if (lacp_timer_is_running (sif->last_marker_pdu_recd_time))
+       vlib_cli_output (vm,
+                        "    last Marker PDU received: %10.2f seconds ago",
+                        now - sif->last_marker_pdu_recd_time);
+      if (lacp_timer_is_running (sif->last_marker_pdu_sent_time))
+       vlib_cli_output (vm, "    last Marker PDU sent: %10.2f seconds ago",
+                        now - sif->last_marker_pdu_sent_time);
       vlib_cli_output (vm, "    debug: %d", sif->debug);
       vlib_cli_output (vm, "    loopback port: %d", sif->loopback_port);
       vlib_cli_output (vm, "    port moved: %d", sif->port_moved);
@@ -209,17 +232,17 @@ show_lacp_details (vlib_main_t * vm, u32 * sw_if_indices)
       if (!lacp_timer_is_running (sif->wait_while_timer))
        vlib_cli_output (vm, "      wait while timer: not running");
       else
-       vlib_cli_output (vm, "      wait while timer: %=10.2f seconds",
+       vlib_cli_output (vm, "      wait while timer: %10.2f seconds",
                         sif->wait_while_timer - now);
       if (!lacp_timer_is_running (sif->current_while_timer))
        vlib_cli_output (vm, "      current while timer: not running");
       else
-       vlib_cli_output (vm, "      current while timer: %=10.2f seconds",
+       vlib_cli_output (vm, "      current while timer: %10.2f seconds",
                         sif->current_while_timer - now);
       if (!lacp_timer_is_running (sif->periodic_timer))
        vlib_cli_output (vm, "      periodic timer: not running");
       else
-       vlib_cli_output (vm, "      periodic timer: %=10.2f seconds",
+       vlib_cli_output (vm, "      periodic timer: %10.2f seconds",
                         sif->periodic_timer - now);
       vlib_cli_output (vm, "    RX-state: %U", format_rx_sm_state,
                       sif->rx_state);
index 9b1f3b6..8212b11 100644 (file)
@@ -108,6 +108,8 @@ send_ethernet_marker_response_pdu (slave_if_t * sif)
   f->n_vectors = 1;
 
   vlib_put_frame_to_node (vm, hw->output_node_index, f);
+  sif->last_marker_pdu_sent_time = vlib_time_now (lm->vlib_main);
+  sif->marker_pdu_sent++;
 }
 
 static int
@@ -153,6 +155,7 @@ lacp_input (vlib_main_t * vm, vlib_buffer_t * b0, u32 bi0)
   marker = (marker_pdu_t *) (b0->data + b0->current_data);
   if (marker->subtype == MARKER_SUBTYPE)
     {
+      sif->last_marker_pdu_recd_time = vlib_time_now (lm->vlib_main);
       if (sif->last_marker_pkt)
        _vec_len (sif->last_marker_pkt) = 0;
       vec_validate (sif->last_marker_pkt,
@@ -160,8 +163,13 @@ lacp_input (vlib_main_t * vm, vlib_buffer_t * b0, u32 bi0)
       nbytes = vlib_buffer_contents (vm, bi0, sif->last_marker_pkt);
       ASSERT (nbytes <= vec_len (sif->last_marker_pkt));
       if (nbytes < sizeof (lacp_pdu_t))
-       return LACP_ERROR_TOO_SMALL;
-      return (handle_marker_protocol (vm, sif));
+       {
+         sif->marker_bad_pdu_received++;
+         return LACP_ERROR_TOO_SMALL;
+       }
+      e = handle_marker_protocol (vm, sif);
+      sif->marker_pdu_received++;
+      return e;
     }
 
   /*
@@ -185,8 +193,10 @@ lacp_input (vlib_main_t * vm, vlib_buffer_t * b0, u32 bi0)
   nbytes = vlib_buffer_contents (vm, bi0, sif->last_rx_pkt);
   ASSERT (nbytes <= vec_len (sif->last_rx_pkt));
 
+  sif->last_lacpdu_recd_time = vlib_time_now (lm->vlib_main);
   if (nbytes < sizeof (lacp_pdu_t))
     {
+      sif->bad_pdu_received++;
       return LACP_ERROR_TOO_SMALL;
     }
 
@@ -209,6 +219,7 @@ lacp_input (vlib_main_t * vm, vlib_buffer_t * b0, u32 bi0)
       sif->last_packet_signature_valid = 1;
       sif->last_packet_signature = last_packet_signature;
     }
+  sif->pdu_received++;
 
   if (sif->last_rx_pkt)
     _vec_len (sif->last_rx_pkt) = 0;
index 473458a..0ecb1df 100644 (file)
@@ -89,7 +89,8 @@ lacp_send_ethernet_lacp_pdu (slave_if_t * sif)
 
   vlib_put_frame_to_node (vm, hw->output_node_index, f);
 
-  sif->last_lacpdu_time = vlib_time_now (lm->vlib_main);
+  sif->last_lacpdu_sent_time = vlib_time_now (lm->vlib_main);
+  sif->pdu_sent++;
 }
 
 /*
@@ -307,7 +308,10 @@ lacp_init_neighbor (slave_if_t * sif, u8 * hw_address, u16 port_number,
   lacp_stop_timer (&sif->actor_churn_timer);
   lacp_stop_timer (&sif->partner_churn_timer);
   lacp_stop_timer (&sif->periodic_timer);
-  lacp_stop_timer (&sif->last_lacpdu_time);
+  lacp_stop_timer (&sif->last_lacpdu_sent_time);
+  lacp_stop_timer (&sif->last_lacpdu_recd_time);
+  lacp_stop_timer (&sif->last_marker_pdu_sent_time);
+  lacp_stop_timer (&sif->last_marker_pdu_recd_time);
   sif->lacp_enabled = 1;
   sif->loopback_port = 0;
   sif->ready = 0;
@@ -331,7 +335,7 @@ lacp_init_neighbor (slave_if_t * sif, u8 * hw_address, u16 port_number,
   sif->partner.port_number = htons (port_number);
   sif->partner.port_priority = htons (LACP_DEFAULT_PORT_PRIORITY);
   sif->partner.key = htons (group);
-  sif->partner.state = LACP_STATE_LACP_ACTIVITY;
+  sif->partner.state = 0;
 
   sif->actor_admin = sif->actor;
   sif->partner_admin = sif->partner;
index 5a1c6d8..7e604cc 100644 (file)
  *  LACP State = NO_PERIODIC
  */
 static lacp_fsm_state_t lacp_ptx_state_no_periodic[] = {
-  {LACP_ACTION_NO_PERIODIC, LACP_PTX_STATE_FAST_PERIODIC},     // event 0 BEGIN
-  {LACP_NOACTION, LACP_PTX_STATE_NO_PERIODIC}, // event 1 LONG_TIMEOUT
-  {LACP_NOACTION, LACP_PTX_STATE_NO_PERIODIC}, // event 2 TIMER_EXPIRED
-  {LACP_NOACTION, LACP_PTX_STATE_NO_PERIODIC}, // event 3 SHORT_TIMEOUT
+  {LACP_ACTION_NO_PERIODIC, LACP_PTX_STATE_NO_PERIODIC},       // event 0 NO_PERIODIC
+  {LACP_ACTION_SLOW_PERIODIC, LACP_PTX_STATE_SLOW_PERIODIC},   // event 1 LONG_TIMEOUT
+  {LACP_ACTION_NO_PERIODIC, LACP_PTX_STATE_NO_PERIODIC},       // event 2 TIMER_EXPIRED
+  {LACP_ACTION_FAST_PERIODIC, LACP_PTX_STATE_FAST_PERIODIC},   // event 3 SHORT_TIMEOUT
 };
 
 /*
  *  LACP State = FAST_PERIODIC
  */
 static lacp_fsm_state_t lacp_ptx_state_fast_periodic[] = {
-  {LACP_ACTION_FAST_PERIODIC, LACP_PTX_STATE_FAST_PERIODIC},   // event 0 BEGIN
+  {LACP_ACTION_NO_PERIODIC, LACP_PTX_STATE_NO_PERIODIC},       // event 0 NO_PERIODIC
   {LACP_ACTION_SLOW_PERIODIC, LACP_PTX_STATE_SLOW_PERIODIC},   // event 1 LONG_TIMEOUT
   {LACP_ACTION_TIMER_EXPIRED, LACP_PTX_STATE_PERIODIC_TX},     // event 2 TIMER_EXPIRED
   {LACP_ACTION_FAST_PERIODIC, LACP_PTX_STATE_FAST_PERIODIC},   // event 3 SHORT_TIMEOUT
@@ -42,7 +42,7 @@ static lacp_fsm_state_t lacp_ptx_state_fast_periodic[] = {
  *  LACP State = SLOW_PERIODIC
  */
 static lacp_fsm_state_t lacp_ptx_state_slow_periodic[] = {
-  {LACP_ACTION_NO_PERIODIC, LACP_PTX_STATE_NO_PERIODIC},       // event 0 BEGIN
+  {LACP_ACTION_NO_PERIODIC, LACP_PTX_STATE_NO_PERIODIC},       // event 0 NO_PERIODIC
   {LACP_ACTION_SLOW_PERIODIC, LACP_PTX_STATE_SLOW_PERIODIC},   // event 1 LONG_TIMEOUT
   {LACP_ACTION_TIMER_EXPIRED, LACP_PTX_STATE_PERIODIC_TX},     // event 2 TIMER_EXPIRED
   {LACP_ACTION_FAST_PERIODIC, LACP_PTX_STATE_FAST_PERIODIC},   // event 3 SHORT_TIMEOUT
@@ -52,7 +52,7 @@ static lacp_fsm_state_t lacp_ptx_state_slow_periodic[] = {
  *  LACP State = PERIODIC_TX
  */
 static lacp_fsm_state_t lacp_ptx_state_periodic_tx[] = {
-  {LACP_ACTION_NO_PERIODIC, LACP_PTX_STATE_NO_PERIODIC},       // event 0 BEGIN
+  {LACP_ACTION_NO_PERIODIC, LACP_PTX_STATE_NO_PERIODIC},       // event 0 NO_PERIODIC
   {LACP_NOACTION, LACP_PTX_STATE_PERIODIC_TX}, // event 1 LONG_TIMEOUT
   {LACP_ACTION_TIMER_EXPIRED, LACP_PTX_STATE_PERIODIC_TX},     // event 2 TIMER_EXPIRED
   {LACP_NOACTION, LACP_PTX_STATE_PERIODIC_TX}, // event 3 SHORT_TIMEOUT
@@ -78,10 +78,7 @@ lacp_ptx_action_no_periodic (void *p1, void *p2)
   slave_if_t *sif = (slave_if_t *) p2;
 
   lacp_stop_timer (&sif->periodic_timer);
-
-  lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
-                        LACP_PTX_EVENT_BEGIN, &sif->ptx_state);
-
+  lacp_ptx_post_short_timeout_event (vm, sif);
   return 0;
 }
 
@@ -93,17 +90,24 @@ lacp_ptx_action_slow_periodic (void *p1, void *p2)
   u8 timer_expired;
   lacp_main_t *lm = &lacp_main;
 
-  if (lacp_timer_is_running (sif->periodic_timer) &&
-      lacp_timer_is_expired (lm->vlib_main, sif->periodic_timer))
-    timer_expired = 1;
+  if (!(sif->partner.state & LACP_STATE_LACP_ACTIVITY) &&
+      !(sif->actor.state & LACP_STATE_LACP_ACTIVITY))
+    lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
+                          LACP_PTX_EVENT_NO_PERIODIC, &sif->ptx_state);
   else
-    timer_expired = 0;
+    {
+      if (lacp_timer_is_running (sif->periodic_timer) &&
+         lacp_timer_is_expired (lm->vlib_main, sif->periodic_timer))
+       timer_expired = 1;
+      else
+       timer_expired = 0;
 
-  lacp_schedule_periodic_timer (lm->vlib_main, sif);
+      lacp_schedule_periodic_timer (lm->vlib_main, sif);
 
-  if (timer_expired || (sif->partner.state & LACP_STATE_LACP_TIMEOUT))
-    lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
-                          LACP_PTX_EVENT_TIMER_EXPIRED, &sif->ptx_state);
+      if (timer_expired || (sif->partner.state & LACP_STATE_LACP_TIMEOUT))
+       lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
+                              LACP_PTX_EVENT_TIMER_EXPIRED, &sif->ptx_state);
+    }
 
   return 0;
 }
@@ -116,21 +120,29 @@ lacp_ptx_action_fast_periodic (void *p1, void *p2)
   u8 timer_expired;
   lacp_main_t *lm = &lacp_main;
 
-  if (lacp_timer_is_running (sif->periodic_timer) &&
-      lacp_timer_is_expired (lm->vlib_main, sif->periodic_timer))
-    timer_expired = 1;
+  if (!(sif->partner.state & LACP_STATE_LACP_ACTIVITY) &&
+      !(sif->actor.state & LACP_STATE_LACP_ACTIVITY))
+    lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
+                          LACP_PTX_EVENT_NO_PERIODIC, &sif->ptx_state);
   else
-    timer_expired = 0;
+    {
+      if (lacp_timer_is_running (sif->periodic_timer) &&
+         lacp_timer_is_expired (lm->vlib_main, sif->periodic_timer))
+       timer_expired = 1;
+      else
+       timer_expired = 0;
 
-  lacp_start_periodic_timer (lm->vlib_main, sif, LACP_FAST_PERIODIC_TIMER);
+      lacp_start_periodic_timer (lm->vlib_main, sif,
+                                LACP_FAST_PERIODIC_TIMER);
 
-  if (timer_expired)
-    lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
-                          LACP_PTX_EVENT_TIMER_EXPIRED, &sif->ptx_state);
+      if (timer_expired)
+       lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
+                              LACP_PTX_EVENT_TIMER_EXPIRED, &sif->ptx_state);
 
-  if (!(sif->partner.state & LACP_STATE_LACP_TIMEOUT))
-    lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
-                          LACP_PTX_EVENT_LONG_TIMEOUT, &sif->ptx_state);
+      if (!(sif->partner.state & LACP_STATE_LACP_TIMEOUT))
+       lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
+                              LACP_PTX_EVENT_LONG_TIMEOUT, &sif->ptx_state);
+    }
 
   return 0;
 }
@@ -141,15 +153,22 @@ lacp_ptx_action_timer_expired (void *p1, void *p2)
   vlib_main_t *vm = (vlib_main_t *) p1;
   slave_if_t *sif = (slave_if_t *) p2;
 
-  sif->ntt = 1;
-  lacp_machine_dispatch (&lacp_tx_machine, vm, sif, LACP_TX_EVENT_NTT,
-                        &sif->tx_state);
-  if (sif->partner.state & LACP_STATE_LACP_TIMEOUT)
+  if (!(sif->partner.state & LACP_STATE_LACP_ACTIVITY) &&
+      !(sif->actor.state & LACP_STATE_LACP_ACTIVITY))
     lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
-                          LACP_PTX_EVENT_SHORT_TIMEOUT, &sif->ptx_state);
+                          LACP_PTX_EVENT_NO_PERIODIC, &sif->ptx_state);
   else
-    lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
-                          LACP_PTX_EVENT_LONG_TIMEOUT, &sif->ptx_state);
+    {
+      sif->ntt = 1;
+      lacp_machine_dispatch (&lacp_tx_machine, vm, sif, LACP_TX_EVENT_NTT,
+                            &sif->tx_state);
+      if (sif->partner.state & LACP_STATE_LACP_TIMEOUT)
+       lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
+                              LACP_PTX_EVENT_SHORT_TIMEOUT, &sif->ptx_state);
+      else
+       lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
+                              LACP_PTX_EVENT_LONG_TIMEOUT, &sif->ptx_state);
+    }
 
   return 0;
 }
@@ -189,8 +208,8 @@ lacp_ptx_debug_func (slave_if_t * sif, int event, int state,
 void
 lacp_init_ptx_machine (vlib_main_t * vm, slave_if_t * sif)
 {
-  lacp_machine_dispatch (&lacp_ptx_machine, vm, sif, LACP_PTX_EVENT_BEGIN,
-                        &sif->ptx_state);
+  lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
+                        LACP_PTX_EVENT_NO_PERIODIC, &sif->ptx_state);
 }
 
 /*
index 9b4f280..4b4f413 100644 (file)
@@ -20,7 +20,7 @@
 #include <lacp/machine.h>
 
 #define foreach_lacp_ptx_event          \
-  _(0, BEGIN, "begin")                  \
+  _(0, NO_PERIODIC, "no periodic")      \
   _(1, LONG_TIMEOUT, "long tiemout")    \
   _(2, TIMER_EXPIRED, "timer expired")  \
   _(3, SHORT_TIMEOUT, "short timeout")
@@ -86,6 +86,16 @@ lacp_schedule_periodic_timer (vlib_main_t * vm, slave_if_t * sif)
     lacp_start_periodic_timer (vm, sif, LACP_SLOW_PERIODIC_TIMER);
 }
 
+static inline void
+lacp_ptx_post_short_timeout_event (vlib_main_t * vm, slave_if_t * sif)
+{
+  if (sif->lacp_enabled && sif->port_enabled &&
+      ((sif->partner.state & LACP_STATE_LACP_ACTIVITY) ||
+       (sif->actor.state & LACP_STATE_LACP_ACTIVITY)))
+    lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
+                          LACP_PTX_EVENT_SHORT_TIMEOUT, &sif->ptx_state);
+}
+
 #endif /* __LACP_PTX_MACHINE_H__ */
 
 /*
index fd65aa3..070b908 100644 (file)
@@ -206,11 +206,15 @@ lacp_compare_partner (slave_if_t * sif)
 }
 
 static void
-lacp_record_pdu (slave_if_t * sif)
+lacp_record_pdu (vlib_main_t * vm, slave_if_t * sif)
 {
   lacp_pdu_t *lacpdu = (lacp_pdu_t *) sif->last_rx_pkt;
   u8 match;
 
+  /* Transition PTX out of NO_PERIODIC if needed */
+  if (!(sif->partner.state & LACP_STATE_LACP_ACTIVITY) &&
+      (lacpdu->actor.port_info.state & LACP_STATE_LACP_ACTIVITY))
+    lacp_ptx_post_short_timeout_event (vm, sif);
   match = lacp_compare_partner (sif);
   sif->partner = lacpdu->actor.port_info;
   sif->actor.state &= ~LACP_STATE_DEFAULTED;
@@ -285,8 +289,7 @@ lacp_rx_action_expired (void *p1, void *p2)
 
   sif->partner.state &= ~LACP_STATE_SYNCHRONIZATION;
   sif->partner.state |= LACP_STATE_LACP_TIMEOUT;
-  lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
-                        LACP_PTX_EVENT_SHORT_TIMEOUT, &sif->ptx_state);
+  lacp_ptx_post_short_timeout_event (vm, sif);
   if (lacp_timer_is_running (sif->current_while_timer) &&
       lacp_timer_is_expired (lm->vlib_main, sif->current_while_timer))
     timer_expired = 1;
@@ -324,6 +327,7 @@ lacp_rx_action_defaulted (void *p1, void *p2)
   vlib_main_t *vm = (vlib_main_t *) p1;
   slave_if_t *sif = (slave_if_t *) p2;
 
+  lacp_stop_timer (&sif->current_while_timer);
   lacp_update_default_selected (vm, sif);
   lacp_record_default (sif);
   sif->actor.state &= ~LACP_STATE_EXPIRED;
@@ -365,7 +369,7 @@ lacp_rx_action_current (void *p1, void *p2)
 
   lacp_update_selected (vm, sif);
   lacp_update_ntt (vm, sif);
-  lacp_record_pdu (sif);
+  lacp_record_pdu (vm, sif);
   lacp_start_current_while_timer (lm->vlib_main, sif, sif->ttl_in_seconds);
   sif->actor.state &= ~LACP_STATE_EXPIRED;
   if (lacp_port_is_moved (vm, sif))
index 21b767c..4cc4e68 100644 (file)
@@ -47,7 +47,7 @@ lacp_tx_action_transmit (void *p1, void *p2)
     return 0;
 
   // No more than 3 LACPDUs per fast interval
-  if (now <= (sif->last_lacpdu_time + 0.333))
+  if (now <= (sif->last_lacpdu_sent_time + 0.333))
     return 0;
 
   if (sif->ntt)
@@ -97,9 +97,6 @@ lacp_init_tx_machine (vlib_main_t * vm, slave_if_t * sif)
 {
   lacp_machine_dispatch (&lacp_tx_machine, vm, sif, LACP_TX_EVENT_BEGIN,
                         &sif->tx_state);
-  if (sif->is_passive == 0)
-    lacp_machine_dispatch (&lacp_tx_machine, vm, sif, LACP_TX_EVENT_NTT,
-                          &sif->tx_state);
 }
 
 /*
index 9a194b8..41e945a 100644 (file)
@@ -266,7 +266,16 @@ typedef struct
   f64 actor_churn_timer;
 
   /* time last lacpdu was sent */
-  f64 last_lacpdu_time;
+  f64 last_lacpdu_sent_time;
+
+  /* time last lacpdu was received */
+  f64 last_lacpdu_recd_time;
+
+  /* time last marker pdu was sent */
+  f64 last_marker_pdu_sent_time;
+
+  /* time last marker pdu was received */
+  f64 last_marker_pdu_recd_time;
 
   /* timer used to generate periodic transmission */
   f64 periodic_timer;
@@ -294,6 +303,24 @@ typedef struct
 
   /* bond mode */
   u8 mode;
+
+  /* good lacp pdu received */
+  u64 pdu_received;
+
+  /* bad lacp pdu received */
+  u64 bad_pdu_received;
+
+  /* pdu sent */
+  u64 pdu_sent;
+
+  /* good marker pdu received */
+  u64 marker_pdu_received;
+
+  /* bad marker pdu received */
+  u64 marker_bad_pdu_received;
+
+  /* pdu sent */
+  u64 marker_pdu_sent;
 } slave_if_t;
 
 typedef void (*lacp_enable_disable_func) (vlib_main_t * vm, bond_if_t * bif,