IP-MAC,ND:wildcard events,fix sending multiple events
[vpp.git] / src / vpp / api / api.c
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;