Allow interface types to override glean adjacency behaivour
[vpp.git] / src / vnet / ethernet / arp.c
index 08e9137..da56c2b 100644 (file)
@@ -92,6 +92,9 @@ typedef struct
 
   /* Proxy arp vector */
   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;
@@ -106,6 +109,7 @@ typedef struct
 #define ETHERNET_ARP_ARGS_REMOVE (1<<0)
 #define ETHERNET_ARP_ARGS_FLUSH  (1<<1)
 #define ETHERNET_ARP_ARGS_POPULATE  (1<<2)
+#define ETHERNET_ARP_ARGS_WC_PUB  (1<<3)
 } vnet_arp_set_ip4_over_ethernet_rpc_args_t;
 
 static const u8 vrrp_prefix[] = { 0x00, 0x00, 0x5E, 0x00, 0x01 };
@@ -199,7 +203,7 @@ format_ethernet_arp_header (u8 * s, va_list * va)
 {
   ethernet_arp_header_t *a = va_arg (*va, ethernet_arp_header_t *);
   u32 max_header_bytes = va_arg (*va, u32);
-  uword indent;
+  u32 indent;
   u16 l2_type, l3_type;
 
   if (max_header_bytes != 0 && sizeof (a[0]) > max_header_bytes)
@@ -451,8 +455,10 @@ arp_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
 
   switch (adj->lookup_next_index)
     {
-    case IP_LOOKUP_NEXT_ARP:
     case IP_LOOKUP_NEXT_GLEAN:
+      adj_glean_update_rewrite (ai);
+      break;
+    case IP_LOOKUP_NEXT_ARP:
       if (NULL != e)
        {
          adj_nbr_walk_nh4 (sw_if_index,
@@ -523,7 +529,7 @@ arp_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
 }
 
 static void
-arp_adj_fib_add (ethernet_arp_ip4_entry_t * e, uint32_t fib_index)
+arp_adj_fib_add (ethernet_arp_ip4_entry_t * e, u32 fib_index)
 {
   fib_prefix_t pfx = {
     .fp_len = 32,
@@ -540,7 +546,7 @@ arp_adj_fib_add (ethernet_arp_ip4_entry_t * e, uint32_t fib_index)
   fib_table_lock (fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_ADJ);
 }
 
-int
+static int
 vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
                                         vnet_arp_set_ip4_over_ethernet_rpc_args_t
                                         * args)
@@ -611,7 +617,7 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
        */
       if (0 == memcmp (e->ethernet_address,
                       a->ethernet, sizeof (e->ethernet_address)))
-       return -1;
+       goto check_customers;
 
       /* Update time stamp and ethernet address. */
       clib_memcpy (e->ethernet_address, a->ethernet,
@@ -626,6 +632,7 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
 
   adj_nbr_walk_nh4 (sw_if_index, &e->ip4_address, arp_mk_complete_walk, e);
 
+check_customers:
   /* Customer(s) waiting for this address to be resolved? */
   p = hash_get (am->pending_resolutions_by_address, a->ip4.as_u32);
   if (p)
@@ -1118,6 +1125,12 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
                                  &arp0->ip4_over_ethernet[0]);
              goto drop1;
            }
+         else if (arp0->opcode ==
+                  clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request) &&
+                  (dst_is_local0 == 0))
+           {
+             goto drop1;
+           }
 
        send_reply:
          /* Send a reply.
@@ -1507,6 +1520,52 @@ vnet_arp_populate_ip4_over_ethernet (vnet_main_t * vnm,
   return 0;
 }
 
+/**
+ * @brief publish wildcard arp event
+ * @param sw_if_index The interface on which the ARP entires are acted
+ */
+static int
+vnet_arp_wc_publish (u32 sw_if_index, void *a_arg)
+{
+  ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
+  vnet_arp_set_ip4_over_ethernet_rpc_args_t args = {
+    .flags = ETHERNET_ARP_ARGS_WC_PUB,
+    .sw_if_index = sw_if_index,
+    .a = *a
+  };
+
+  vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
+                              (u8 *) & args, sizeof (args));
+  return 0;
+}
+
+static void
+vnet_arp_wc_publish_internal (vnet_main_t * vnm,
+                             vnet_arp_set_ip4_over_ethernet_rpc_args_t *
+                             args)
+{
+  vlib_main_t *vm = vlib_get_main ();
+  ethernet_arp_main_t *am = &ethernet_arp_main;
+  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, 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, 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;
+}
+
 /*
  * arp_add_del_interface_address
  *
@@ -1568,7 +1627,7 @@ arp_add_del_interface_address (ip4_main_t * im,
 }
 
 void
-arp_adj_fib_remove (ethernet_arp_ip4_entry_t * e, uint32_t fib_index)
+arp_adj_fib_remove (ethernet_arp_ip4_entry_t * e, u32 fib_index)
 {
   if (FIB_NODE_INDEX_INVALID != e->fib_entry_index)
     {
@@ -1652,6 +1711,7 @@ ethernet_arp_init (vlib_main_t * vm)
 
   am->pending_resolutions_by_address = hash_create (0, sizeof (uword));
   am->mac_changes_by_address = hash_create (0, sizeof (uword));
+  am->wc_ip4_arp_publisher_node = (uword) ~ 0;
 
   /* don't trace ARP error packets */
   {
@@ -1795,6 +1855,8 @@ set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t
     vnet_arp_flush_ip4_over_ethernet_internal (vm, a);
   else if (a->flags & ETHERNET_ARP_ARGS_POPULATE)
     vnet_arp_populate_ip4_over_ethernet_internal (vm, a);
+  else if (a->flags & ETHERNET_ARP_ARGS_WC_PUB)
+    vnet_arp_wc_publish_internal (vm, a);
   else
     vnet_arp_set_ip4_over_ethernet_internal (vm, a);
 }
@@ -2277,31 +2339,9 @@ arp_term_l2bd (vlib_main_t * vm,
 
          /* Check if anyone want ARP request events for L2 BDs */
          {
-           pending_resolution_t *mc;
            ethernet_arp_main_t *am = &ethernet_arp_main;
-           uword *p = hash_get (am->mac_changes_by_address, 0);
-           if (p)
-             {
-               u32 next_index = p[0];
-               while (next_index != (u32) ~ 0)
-                 {
-                   int (*fp) (u32, u8 *, u32, u32);
-                   int rv = 1;
-                   mc = pool_elt_at_index (am->mac_changes, next_index);
-                   fp = mc->data_callback;
-                   /* Call the callback, return 1 to suppress dup events */
-                   if (fp)
-                     rv = (*fp) (mc->data,
-                                 arp0->ip4_over_ethernet[0].ethernet,
-                                 sw_if_index0,
-                                 arp0->ip4_over_ethernet[0].ip4.as_u32);
-                   /* 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;
-                 }
-             }
+           if (am->wc_ip4_arp_publisher_node != (uword) ~ 0)
+             vnet_arp_wc_publish (sw_if_index0, &arp0->ip4_over_ethernet[0]);
          }
 
          /* lookup BD mac_by_ip4 hash table for MAC entry */
@@ -2449,9 +2489,11 @@ ethernet_arp_change_mac (u32 sw_if_index)
     change_arp_mac (sw_if_index, e);
   }));
   /* *INDENT-ON* */
+
+  adj_glean_update_rewrite (adj_glean_get (FIB_PROTOCOL_IP4, sw_if_index));
 }
 
-void static
+void
 send_ip4_garp (vlib_main_t * vm, vnet_hw_interface_t * hi)
 {
   ip4_main_t *i4m = &ip4_main;
@@ -2495,42 +2537,6 @@ send_ip4_garp (vlib_main_t * vm, vnet_hw_interface_t * hi)
     }
 }
 
-static vlib_node_registration_t send_garp_na_proc_node;
-
-static uword
-send_garp_na_process (vlib_main_t * vm,
-                     vlib_node_runtime_t * rt, vlib_frame_t * f)
-{
-  vnet_main_t *vnm = vnet_get_main ();
-  uword event_type, *event_data = 0;
-
-  send_garp_na_process_node_index = send_garp_na_proc_node.index;
-
-  while (1)
-    {
-      vlib_process_wait_for_event (vm);
-      event_type = vlib_process_get_events (vm, &event_data);
-      if ((event_type == SEND_GARP_NA) && (vec_len (event_data) >= 1))
-       {
-         u32 hw_if_index = event_data[0];
-         vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
-         send_ip4_garp (vm, hi);
-         send_ip6_na (vm, hi);
-       }
-      vec_reset_length (event_data);
-    }
-  return 0;
-}
-
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (send_garp_na_proc_node, static) = {
-    .function = send_garp_na_process,
-    .type = VLIB_NODE_TYPE_PROCESS,
-    .name = "send-garp-na-process",
-};
-/* *INDENT-ON* */
-
 /*
  * fd.io coding-style-patch-verification: ON
  *