IP-MAC,ND:wildcard events,fix sending multiple events 71/8471/3
authorEyal Bari <ebari@cisco.com>
Wed, 20 Sep 2017 08:29:17 +0000 (11:29 +0300)
committerJohn Lo <loj@cisco.com>
Fri, 22 Sep 2017 01:55:33 +0000 (01:55 +0000)
wildcard ND events publisher was sending the last event mutiple times

Change-Id: I6c30f2de03fa825e79df9005a3cfaaf68ff7ea2f
Signed-off-by: Eyal Bari <ebari@cisco.com>
src/vlibapi/api_helper_macros.h
src/vnet/ethernet/arp.c
src/vnet/ethernet/ethernet.h
src/vnet/ip/ip6_neighbor.c
src/vnet/ip/ip6_neighbor.h
src/vpp/api/api.c
test/test_l2bd_arp_term.py
test/vpp_papi_provider.py

index 1373489..052cc6e 100644 (file)
@@ -216,6 +216,7 @@ _(to_netconf_client)                            \
 _(from_netconf_client)                          \
 _(oam_events)                                   \
 _(bfd_events)                                   \
+_(wc_ip6_nd_events)                             \
 _(wc_ip4_arp_events)
 
 typedef struct
index 2f3aa6c..e974d25 100644 (file)
@@ -94,6 +94,7 @@ typedef struct
   ethernet_proxy_arp_t *proxy_arps;
 
   uword wc_ip4_arp_publisher_node;
+  uword wc_ip4_arp_publisher_et;
 } ethernet_arp_main_t;
 
 static ethernet_arp_main_t ethernet_arp_main;
@@ -1536,21 +1537,24 @@ vnet_arp_wc_publish_internal (vnet_main_t * vnm,
 {
   vlib_main_t *vm = vlib_get_main ();
   ethernet_arp_main_t *am = &ethernet_arp_main;
-  if (am->wc_ip4_arp_publisher_node == (uword) ~ 0)
+  uword ni = am->wc_ip4_arp_publisher_node;
+  uword et = am->wc_ip4_arp_publisher_et;
+
+  if (ni == (uword) ~ 0)
     return;
   wc_arp_report_t *r =
-    vlib_process_signal_event_data (vm, am->wc_ip4_arp_publisher_node, 1, 1,
-                                   sizeof *r);
+    vlib_process_signal_event_data (vm, ni, et, 1, sizeof *r);
   r->ip4 = args->a.ip4.as_u32;
   r->sw_if_index = args->sw_if_index;
   memcpy (r->mac, args->a.ethernet, sizeof r->mac);
 }
 
 void
-wc_arp_set_publisher_node (uword node_index)
+wc_arp_set_publisher_node (uword node_index, uword event_type)
 {
   ethernet_arp_main_t *am = &ethernet_arp_main;
   am->wc_ip4_arp_publisher_node = node_index;
+  am->wc_ip4_arp_publisher_et = event_type;
 }
 
 /*
index 1a9e979..a6846b1 100644 (file)
@@ -543,7 +543,7 @@ int vnet_add_del_ip4_arp_change_event (vnet_main_t * vnm,
                                       uword type_opaque,
                                       uword data, int is_add);
 
-void wc_arp_set_publisher_node (uword inode_index);
+void wc_arp_set_publisher_node (uword inode_index, uword event_type);
 
 void ethernet_arp_change_mac (u32 sw_if_index);
 void ethernet_ndp_change_mac (u32 sw_if_index);
index 345ebd3..1908a67 100644 (file)
@@ -195,6 +195,9 @@ typedef struct
   u32 limit_neighbor_cache_size;
   u32 neighbor_delete_rotor;
 
+  /* Wildcard nd report publisher */
+  uword wc_ip6_nd_publisher_node;
+  uword wc_ip6_nd_publisher_et;
 } ip6_neighbor_main_t;
 
 /* ipv6 neighbor discovery - timer/event types */
@@ -216,6 +219,50 @@ typedef union
 static ip6_neighbor_main_t ip6_neighbor_main;
 static ip6_address_t ip6a_zero;        /* ip6 address 0 */
 
+static void wc_nd_signal_report (wc_nd_report_t * r);
+
+/**
+ * @brief publish wildcard arp event
+ * @param sw_if_index The interface on which the ARP entires are acted
+ */
+static int
+vnet_nd_wc_publish (u32 sw_if_index, u8 * mac, ip6_address_t * ip6)
+{
+  wc_nd_report_t r = {
+    .sw_if_index = sw_if_index,
+    .ip6 = *ip6,
+  };
+  memcpy (r.mac, mac, sizeof r.mac);
+
+  void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
+  vl_api_rpc_call_main_thread (wc_nd_signal_report, (u8 *) & r, sizeof r);
+  return 0;
+}
+
+static void
+wc_nd_signal_report (wc_nd_report_t * r)
+{
+  vlib_main_t *vm = vlib_get_main ();
+  ip6_neighbor_main_t *nm = &ip6_neighbor_main;
+  uword ni = nm->wc_ip6_nd_publisher_node;
+  uword et = nm->wc_ip6_nd_publisher_et;
+
+  if (ni == (uword) ~ 0)
+    return;
+  wc_nd_report_t *q =
+    vlib_process_signal_event_data (vm, ni, et, 1, sizeof *q);
+
+  *q = *r;
+}
+
+void
+wc_nd_set_publisher_node (uword node_index, uword event_type)
+{
+  ip6_neighbor_main_t *nm = &ip6_neighbor_main;
+  nm->wc_ip6_nd_publisher_node = node_index;
+  nm->wc_ip6_nd_publisher_et = event_type;
+}
+
 static u8 *
 format_ip6_neighbor_ip6_entry (u8 * s, va_list * va)
 {
@@ -3931,6 +3978,8 @@ ip6_neighbor_init (vlib_main_t * vm)
   /* default, configurable */
   nm->limit_neighbor_cache_size = 50000;
 
+  nm->wc_ip6_nd_publisher_node = (uword) ~ 0;
+
 #if 0
   /* $$$$ Hack fix for today */
   vec_validate_init_empty
@@ -4047,7 +4096,6 @@ vnet_ip6_nd_term (vlib_main_t * vm,
 {
   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
   icmp6_neighbor_solicitation_or_advertisement_header_t *ndh;
-  pending_resolution_t *mc;
 
   ndh = ip6_next_header (ip);
   if (ndh->icmp.type != ICMP6_neighbor_solicitation &&
@@ -4063,26 +4111,11 @@ vnet_ip6_nd_term (vlib_main_t * vm,
     }
 
   /* Check if anyone want ND events for L2 BDs */
-  uword *p = mhash_get (&nm->mac_changes_by_address, &ip6a_zero);
-  if (p && !ip6_address_is_link_local_unicast (&ip->src_address))
+  if (PREDICT_FALSE
+      (nm->wc_ip6_nd_publisher_node != (uword) ~ 0
+       && !ip6_address_is_link_local_unicast (&ip->src_address)))
     {
-      u32 next_index = p[0];
-      while (next_index != (u32) ~ 0)
-       {
-         int (*fp) (u32, u8 *, u32, ip6_address_t *);
-         int rv = 1;
-         mc = pool_elt_at_index (nm->mac_changes, next_index);
-         fp = mc->data_callback;
-         /* Call the callback, return 1 to suppress dup events */
-         if (fp)
-           rv = (*fp) (mc->data,
-                       eth->src_address, sw_if_index, &ip->src_address);
-         /* Signal the resolver process */
-         if (rv == 0)
-           vlib_process_signal_event (vm, mc->node_index,
-                                      mc->type_opaque, mc->data);
-         next_index = mc->next_index;
-       }
+      vnet_nd_wc_publish (sw_if_index, eth->src_address, &ip->src_address);
     }
 
   /* Check if MAC entry exsist for solicited target IP */
index 0e302ed..ed80381 100644 (file)
@@ -89,6 +89,14 @@ extern int ip6_neighbor_proxy_add_del (u32 sw_if_index,
 
 u32 ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index,
                                       u32 is_add);
+typedef struct
+{
+  u32 sw_if_index;
+  ip6_address_t ip6;
+  u8 mac[6];
+} wc_nd_report_t;
+
+void wc_nd_set_publisher_node (uword node_index, uword event_type);
 
 #endif /* included_ip6_neighbor_h */
 
index e229a5e..d020314 100644 (file)
@@ -1345,8 +1345,6 @@ arp_change_data_callback (u32 pool_index, u8 * new_mac,
   vpe_api_main_t *am = &vpe_api_main;
   vlib_main_t *vm = am->vlib_main;
   vl_api_ip4_arp_event_t *event;
-  static f64 arp_event_last_time;
-  f64 now = vlib_time_now (vm);
 
   if (pool_is_free_index (am->arp_events, pool_index))
     return 1;
@@ -1360,7 +1358,6 @@ arp_change_data_callback (u32 pool_index, u8 * new_mac,
 
   clib_memcpy (event->new_mac, new_mac, sizeof (event->new_mac));
   event->sw_if_index = htonl (sw_if_index);
-  arp_event_last_time = now;
   return 0;
 }
 
@@ -1371,35 +1368,19 @@ nd_change_data_callback (u32 pool_index, u8 * new_mac,
   vpe_api_main_t *am = &vpe_api_main;
   vlib_main_t *vm = am->vlib_main;
   vl_api_ip6_nd_event_t *event;
-  static f64 nd_event_last_time;
-  f64 now = vlib_time_now (vm);
 
   if (pool_is_free_index (am->nd_events, pool_index))
     return 1;
 
   event = pool_elt_at_index (am->nd_events, pool_index);
-
-  /* *INDENT-OFF* */
-  if (memcmp (event->new_mac, new_mac, sizeof (event->new_mac)))
+  if (eth_mac_equal (event->new_mac, new_mac) &&
+      sw_if_index == ntohl (event->sw_if_index))
     {
-      clib_memcpy (event->new_mac, new_mac, sizeof (event->new_mac));
-    }
-  else
-    {                          /* same mac */
-      if (sw_if_index == ntohl(event->sw_if_index) &&
-         (!event->mac_ip ||
-          /* for BD case, also check IP address with 10 sec timeout */
-          (ip6_address_is_equal (address,
-                                 (ip6_address_t *) event->address) &&
-           (now - nd_event_last_time) < 10.0)))
-       return 1;
+      return 1;
     }
-  /* *INDENT-ON* */
 
-  nd_event_last_time = now;
+  clib_memcpy (event->new_mac, new_mac, sizeof (event->new_mac));
   event->sw_if_index = htonl (sw_if_index);
-  if (event->mac_ip)
-    clib_memcpy (event->address, address, sizeof (event->address));
   return 0;
 }
 
@@ -1427,61 +1408,107 @@ nd_change_delete_callback (u32 pool_index, u8 * notused)
   return 0;
 }
 
-static vlib_node_registration_t wc_ip4_arp_process_node;
+static vlib_node_registration_t wc_arp_process_node;
+
+enum
+{ WC_ARP_REPORT, WC_ND_REPORT };
 
 static uword
-wc_ip4_arp_process (vlib_main_t * vm,
-                   vlib_node_runtime_t * rt, vlib_frame_t * f)
+wc_arp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
 {
   /* These cross the longjmp  boundry (vlib_process_wait_for_event)
    * and need to be volatile - to prevent them from being optimized into
    * a register - which could change during suspension */
 
-  volatile wc_arp_report_t prev = { 0 };
-  volatile f64 last = vlib_time_now (vm);
+  volatile wc_arp_report_t arp_prev = { 0 };
+  volatile wc_nd_report_t nd_prev = { 0 };
+  volatile f64 last_arp = vlib_time_now (vm);
+  volatile f64 last_nd = vlib_time_now (vm);
 
   while (1)
     {
       vlib_process_wait_for_event (vm);
       uword event_type;
-      wc_arp_report_t *event_data =
-       vlib_process_get_event_data (vm, &event_type);
+      void *event_data = vlib_process_get_event_data (vm, &event_type);
 
       f64 now = vlib_time_now (vm);
       int i;
-      for (i = 0; i < vec_len (event_data); i++)
+      if (event_type == WC_ARP_REPORT)
+       {
+         wc_arp_report_t *arp_events = event_data;
+         for (i = 0; i < vec_len (arp_events); i++)
+           {
+             /* discard dup event */
+             if (arp_prev.ip4 == arp_events[i].ip4 &&
+                 eth_mac_equal ((u8 *) arp_prev.mac, arp_events[i].mac) &&
+                 arp_prev.sw_if_index == arp_events[i].sw_if_index &&
+                 (now - last_arp) < 10.0)
+               {
+                 continue;
+               }
+             arp_prev = arp_events[i];
+             last_arp = now;
+             vpe_client_registration_t *reg;
+            /* *INDENT-OFF* */
+            pool_foreach(reg, vpe_api_main.wc_ip4_arp_events_registrations,
+            ({
+             unix_shared_memory_queue_t *q;
+              q = vl_api_client_index_to_input_queue (reg->client_index);
+             if (q && q->cursize < q->maxsize)
+               {
+                 vl_api_ip4_arp_event_t * event = vl_msg_api_alloc (sizeof *event);
+                 memset (event, 0, sizeof *event);
+                 event->_vl_msg_id = htons (VL_API_IP4_ARP_EVENT);
+                 event->client_index = reg->client_index;
+                 event->pid = reg->client_pid;
+                 event->mac_ip = 1;
+                 event->address = arp_events[i].ip4;
+                 event->sw_if_index = htonl(arp_events[i].sw_if_index);
+                 memcpy(event->new_mac, arp_events[i].mac, sizeof event->new_mac);
+                 vl_msg_api_send_shmem (q, (u8 *) &event);
+               }
+            }));
+            /* *INDENT-ON* */
+           }
+       }
+      else if (event_type == WC_ND_REPORT)
        {
-         /* discard dup event */
-         if (prev.ip4 == event_data[i].ip4 &&
-             eth_mac_equal ((u8 *) prev.mac, event_data[i].mac) &&
-             prev.sw_if_index == event_data[i].sw_if_index &&
-             (now - last) < 10.0)
+         wc_nd_report_t *nd_events = event_data;
+         for (i = 0; i < vec_len (nd_events); i++)
            {
-             continue;
+             /* discard dup event */
+             if (ip6_address_is_equal
+                 ((ip6_address_t *) & nd_prev.ip6, &nd_events[i].ip6)
+                 && eth_mac_equal ((u8 *) nd_prev.mac, nd_events[i].mac)
+                 && nd_prev.sw_if_index == nd_events[i].sw_if_index
+                 && (now - last_nd) < 10.0)
+               {
+                 continue;
+               }
+             nd_prev = nd_events[i];
+             last_nd = now;
+             vpe_client_registration_t *reg;
+              /* *INDENT-OFF* */
+              pool_foreach(reg, vpe_api_main.wc_ip6_nd_events_registrations,
+              ({
+               unix_shared_memory_queue_t *q;
+                q = vl_api_client_index_to_input_queue (reg->client_index);
+               if (q && q->cursize < q->maxsize)
+                 {
+                   vl_api_ip6_nd_event_t * event = vl_msg_api_alloc (sizeof *event);
+                   memset (event, 0, sizeof *event);
+                   event->_vl_msg_id = htons (VL_API_IP6_ND_EVENT);
+                   event->client_index = reg->client_index;
+                   event->pid = reg->client_pid;
+                   event->mac_ip = 1;
+                   memcpy(event->address, nd_events[i].ip6.as_u8, sizeof event->address);
+                   event->sw_if_index = htonl(nd_events[i].sw_if_index);
+                   memcpy(event->new_mac, nd_events[i].mac, sizeof event->new_mac);
+                   vl_msg_api_send_shmem (q, (u8 *) &event);
+                 }
+              }));
+            /* *INDENT-ON* */
            }
-         prev = event_data[i];
-         last = now;
-         vpe_client_registration_t *reg;
-          /* *INDENT-OFF* */
-          pool_foreach(reg, vpe_api_main.wc_ip4_arp_events_registrations,
-          ({
-           unix_shared_memory_queue_t *q;
-            q = vl_api_client_index_to_input_queue (reg->client_index);
-           if (q && q->cursize < q->maxsize)
-             {
-               vl_api_ip4_arp_event_t * event = vl_msg_api_alloc (sizeof *event);
-               memset (event, 0, sizeof *event);
-               event->_vl_msg_id = htons (VL_API_IP4_ARP_EVENT);
-               event->client_index = reg->client_index;
-               event->pid = reg->client_pid;
-               event->mac_ip = 1;
-               event->address = event_data[i].ip4;
-               event->sw_if_index = htonl(event_data[i].sw_if_index);
-               memcpy(event->new_mac, event_data[i].mac, sizeof event->new_mac);
-               vl_msg_api_send_shmem (q, (u8 *) &event);
-             }
-          }));
-          /* *INDENT-ON* */
        }
       vlib_process_put_event_data (vm, event_data);
     }
@@ -1490,8 +1517,8 @@ wc_ip4_arp_process (vlib_main_t * vm,
 }
 
 /* *INDENT-OFF* */
-VLIB_REGISTER_NODE (wc_ip4_arp_process_node,static) = {
-  .function = wc_ip4_arp_process,
+VLIB_REGISTER_NODE (wc_arp_process_node,static) = {
+  .function = wc_arp_process,
   .type = VLIB_NODE_TYPE_PROCESS,
   .name = "wildcard-ip4-arp-publisher-process",
 };
@@ -1526,7 +1553,7 @@ vl_api_want_ip4_arp_events_t_handler (vl_api_want_ip4_arp_events_t * mp)
              hash_unset (am->wc_ip4_arp_events_registration_hash,
                          mp->client_index);
              if (pool_elts (am->wc_ip4_arp_events_registrations) == 0)
-               wc_arp_set_publisher_node (~0);
+               wc_arp_set_publisher_node (~0, WC_ARP_REPORT);
              goto reply;
            }
        }
@@ -1541,7 +1568,7 @@ vl_api_want_ip4_arp_events_t_handler (vl_api_want_ip4_arp_events_t * mp)
       rp->client_pid = mp->pid;
       hash_set (am->wc_ip4_arp_events_registration_hash, rp->client_index,
                rp - am->wc_ip4_arp_events_registrations);
-      wc_arp_set_publisher_node (wc_ip4_arp_process_node.index);
+      wc_arp_set_publisher_node (wc_arp_process_node.index, WC_ARP_REPORT);
       goto reply;
     }
 
@@ -1588,7 +1615,47 @@ vl_api_want_ip6_nd_events_t_handler (vl_api_want_ip6_nd_events_t * mp)
   vpe_api_main_t *am = &vpe_api_main;
   vnet_main_t *vnm = vnet_get_main ();
   vl_api_want_ip6_nd_events_reply_t *rmp;
-  int rv;
+  int rv = 0;
+
+  if (ip6_address_is_zero ((ip6_address_t *) mp->address))
+    {
+      uword *p =
+       hash_get (am->wc_ip6_nd_events_registration_hash, mp->client_index);
+      vpe_client_registration_t *rp;
+      if (p)
+       {
+         if (mp->enable_disable)
+           {
+             clib_warning ("pid %d: already enabled...", mp->pid);
+             rv = VNET_API_ERROR_INVALID_REGISTRATION;
+             goto reply;
+           }
+         else
+           {
+             rp =
+               pool_elt_at_index (am->wc_ip6_nd_events_registrations, p[0]);
+             pool_put (am->wc_ip6_nd_events_registrations, rp);
+             hash_unset (am->wc_ip6_nd_events_registration_hash,
+                         mp->client_index);
+             if (pool_elts (am->wc_ip6_nd_events_registrations) == 0)
+               wc_nd_set_publisher_node (~0, 2);
+             goto reply;
+           }
+       }
+      if (mp->enable_disable == 0)
+       {
+         clib_warning ("pid %d: already disabled...", mp->pid);
+         rv = VNET_API_ERROR_INVALID_REGISTRATION;
+         goto reply;
+       }
+      pool_get (am->wc_ip6_nd_events_registrations, rp);
+      rp->client_index = mp->client_index;
+      rp->client_pid = mp->pid;
+      hash_set (am->wc_ip6_nd_events_registration_hash, rp->client_index,
+               rp - am->wc_ip6_nd_events_registrations);
+      wc_nd_set_publisher_node (wc_arp_process_node.index, WC_ND_REPORT);
+      goto reply;
+    }
 
   if (mp->enable_disable)
     {
@@ -1604,17 +1671,14 @@ vl_api_want_ip6_nd_events_t_handler (vl_api_want_ip6_nd_events_t * mp)
       if (rv)
        {
          pool_put (am->nd_events, event);
-         goto out;
+         goto reply;
        }
       memset (event, 0, sizeof (*event));
 
       event->_vl_msg_id = ntohs (VL_API_IP6_ND_EVENT);
       event->client_index = mp->client_index;
-      clib_memcpy (event->address, mp->address, 16);
+      clib_memcpy (event->address, mp->address, sizeof event->address);
       event->pid = mp->pid;
-      if (ip6_address_is_zero ((ip6_address_t *) mp->address))
-       event->mac_ip = 1;
-
     }
   else
     {
@@ -1624,7 +1688,7 @@ vl_api_want_ip6_nd_events_t_handler (vl_api_want_ip6_nd_events_t * mp)
         vpe_resolver_process_node.index,
         IP6_ND_EVENT, ~0 /* pool index */ , 0 /* is_add */ );
     }
-out:
+reply:
   REPLY_MACRO (VL_API_WANT_IP6_ND_EVENTS_REPLY);
 }
 
@@ -2325,10 +2389,7 @@ format_nd_event (u8 * s, va_list * args)
   vl_api_ip6_nd_event_t *event = va_arg (*args, vl_api_ip6_nd_event_t *);
 
   s = format (s, "pid %d: ", ntohl (event->pid));
-  if (event->mac_ip)
-    s = format (s, "bd mac/ip6 binding events");
-  else
-    s = format (s, "resolution for %U", format_ip6_address, event->address);
+  s = format (s, "resolution for %U", format_ip6_address, event->address);
   return s;
 }
 
@@ -2340,7 +2401,9 @@ show_ip_arp_nd_events_fn (vlib_main_t * vm,
   vl_api_ip4_arp_event_t *arp_event;
   vl_api_ip6_nd_event_t *nd_event;
 
-  if ((pool_elts (am->arp_events) == 0) && (pool_elts (am->nd_events) == 0))
+  if (pool_elts (am->arp_events) == 0 && pool_elts (am->nd_events) == 0 &&
+      pool_elts (am->wc_ip4_arp_events_registrations) == 0 &&
+      pool_elts (am->wc_ip6_nd_events_registrations) == 0)
     {
       vlib_cli_output (vm, "No active arp or nd event registrations");
       return 0;
@@ -2363,6 +2426,12 @@ show_ip_arp_nd_events_fn (vlib_main_t * vm,
   ({
     vlib_cli_output (vm, "%U", format_nd_event, nd_event);
   }));
+
+  pool_foreach(reg, am->wc_ip6_nd_events_registrations,
+  ({
+    vlib_cli_output (vm, "pid %d: bd mac/ip6 binding events",
+                     ntohl (reg->client_pid));
+  }));
   /* *INDENT-ON* */
 
   return 0;
index 20885f8..20cc537 100644 (file)
@@ -168,6 +168,13 @@ class TestL2bdArpTerm(VppTestCase):
     def arp_event_hosts(self, evs):
         return {self.arp_event_host(e) for e in evs}
 
+    def nd_event_host(self, e):
+        return Host(mac=':'.join(['%02x' % ord(char) for char in e.new_mac]),
+                    ip6=inet_ntop(AF_INET6, e.address))
+
+    def nd_event_hosts(self, evs):
+        return {self.nd_event_host(e) for e in evs}
+
     @classmethod
     def ns_req(cls, src_host, host):
         nsma = in6_getnsma(inet_pton(AF_INET6, "fd10::ffff"))
@@ -178,7 +185,11 @@ class TestL2bdArpTerm(VppTestCase):
                 ICMPv6NDOptSrcLLAddr(lladdr=src_host.mac))
 
     @classmethod
-    def ns_reqs(cls, src_host, entries):
+    def ns_reqs_dst(cls, entries, dst_host):
+        return [cls.ns_req(e, dst_host) for e in entries]
+
+    @classmethod
+    def ns_reqs_src(cls, src_host, entries):
         return [cls.ns_req(src_host, e) for e in entries]
 
     def na_resp_host(self, src_host, rx):
@@ -237,7 +248,7 @@ class TestL2bdArpTerm(VppTestCase):
             self.assertEqual(len(resps ^ resp_hosts), 0)
 
     def verify_nd(self, src_host, req_hosts, resp_hosts, bd_id=1):
-        reqs = self.ns_reqs(src_host, req_hosts)
+        reqs = self.ns_reqs_src(src_host, req_hosts)
 
         for swif in self.bd_swifs(bd_id):
             swif.add_stream(reqs)
@@ -423,6 +434,59 @@ class TestL2bdArpTerm(VppTestCase):
         self.assertEqual(len(self.vapi.collect_events()), 0)
         self.bd_add_del(1, is_add=0)
 
+    def test_l2bd_arp_term_12(self):
+        """ L2BD ND term - send NS packets verify reports
+        """
+        self.vapi.want_ip6_nd_events(address=inet_pton(AF_INET6, "::0"))
+        dst_host = self.ip6_host(50, 50, "00:00:11:22:33:44")
+        self.bd_add_del(1, is_add=1)
+        self.set_bd_flags(1, arp_term=True, flood=False,
+                          uu_flood=False, learn=False)
+        macs = self.mac_list(range(10, 15))
+        hosts = self.ip6_hosts(5, 1, macs)
+        reqs = self.ns_reqs_dst(hosts, dst_host)
+        self.bd_swifs(1)[0].add_stream(reqs)
+
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        evs = [self.vapi.wait_for_event(2, "ip6_nd_event")
+               for i in range(len(hosts))]
+        ev_hosts = self.nd_event_hosts(evs)
+        self.assertEqual(len(ev_hosts ^ hosts), 0)
+
+    def test_l2bd_arp_term_13(self):
+        """ L2BD ND term - send duplicate ns, verify suppression
+        """
+        dst_host = self.ip6_host(50, 50, "00:00:11:22:33:44")
+        macs = self.mac_list(range(10, 11))
+        hosts = self.ip6_hosts(5, 1, macs)
+        reqs = self.ns_reqs_dst(hosts, dst_host) * 5
+        self.bd_swifs(1)[0].add_stream(reqs)
+
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        evs = [self.vapi.wait_for_event(2, "ip6_nd_event")
+               for i in range(len(hosts))]
+        ev_hosts = self.nd_event_hosts(evs)
+        self.assertEqual(len(ev_hosts ^ hosts), 0)
+
+    def test_l2bd_arp_term_14(self):
+        """ L2BD ND term - disable ip4 arp events,send ns, verify no events
+        """
+        self.vapi.want_ip6_nd_events(enable_disable=0,
+                                     address=inet_pton(AF_INET6, "::0"))
+        dst_host = self.ip6_host(50, 50, "00:00:11:22:33:44")
+        macs = self.mac_list(range(10, 15))
+        hosts = self.ip6_hosts(5, 1, macs)
+        reqs = self.ns_reqs_dst(hosts, dst_host)
+        self.bd_swifs(1)[0].add_stream(reqs)
+
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        self.sleep(1)
+        self.assertEqual(len(self.vapi.collect_events()), 0)
+        self.bd_add_del(1, is_add=0)
+
 
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)
index fcc6784..71e7aea 100644 (file)
@@ -425,6 +425,12 @@ class VppPapiProvider(object):
                          'address': address,
                          'pid': os.getpid(), })
 
+    def want_ip6_nd_events(self, enable_disable=1, address=0):
+        return self.api(self.papi.want_ip6_nd_events,
+                        {'enable_disable': enable_disable,
+                         'address': address,
+                         'pid': os.getpid(), })
+
     def l2fib_add_del(self, mac, bd_id, sw_if_index, is_add=1, static_mac=0,
                       filter_mac=0, bvi_mac=0):
         """Create/delete L2 FIB entry.