Port glean neighbor entry support to IPv6
[vpp.git] / vnet / vnet / ethernet / arp.c
index 79ff44f..aa37f25 100644 (file)
@@ -35,8 +35,11 @@ typedef struct {
 
   u16 flags;
 #define ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC (1 << 0)
+#define ETHERNET_ARP_IP4_ENTRY_FLAG_GLEAN  (2 << 0)
 
   u64 cpu_time_last_updated;
+
+  u32 * adjacencies;
 } ethernet_arp_ip4_entry_t;
 
 typedef struct {
@@ -67,8 +70,6 @@ typedef struct {
   uword * mac_changes_by_address;
   pending_resolution_t * mac_changes;
 
-  u32 * arp_input_next_index_by_hw_if_index;
-
   ethernet_arp_ip4_entry_t * ip4_entry_pool;
 
   mhash_t ip4_entry_by_key;
@@ -210,22 +211,31 @@ static u8 * format_ethernet_arp_ip4_entry (u8 * s, va_list * va)
   ethernet_arp_ip4_entry_t * e = va_arg (*va, ethernet_arp_ip4_entry_t *);
   vnet_sw_interface_t * si;
   ip4_fib_t * fib;
+  u8 * flags = 0;
 
   if (! e)
-    return format (s, "%=12s%=6s%=16s%=4s%=20s%=24s", "Time", "FIB", "IP4", 
-                   "Static", "Ethernet", "Interface");
+    return format (s, "%=12s%=6s%=16s%=6s%=20s%=24s", "Time", "FIB", "IP4",
+                   "Flags", "Ethernet", "Interface");
 
   fib = find_ip4_fib_by_table_index_or_id (&ip4_main, e->key.fib_index,
                                            IP4_ROUTE_FLAG_FIB_INDEX);
   si = vnet_get_sw_interface (vnm, e->key.sw_if_index);
-  s = format (s, "%=12U%=6u%=16U%=4s%=20U%=25U",
+
+  if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_GLEAN)
+    flags = format(flags, "G");
+
+  if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC)
+    flags = format(flags, "S");
+
+  s = format (s, "%=12U%=6u%=16U%=6s%=20U%=24U",
              format_vlib_cpu_time, vnm->vlib_main, e->cpu_time_last_updated,
               fib->table_id,
              format_ip4_address, &e->key.ip4_address,
-              (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC) ? "S" : "",
+             flags ? (char *) flags : "",
              format_ethernet_address, e->ethernet_address,
              format_vnet_sw_interface_name, vnm, si);
 
+  vec_free(flags);
   return s;
 }
 
@@ -268,7 +278,7 @@ ethernet_arp_sw_interface_up_down (vnet_main_t * vnm,
           ethernet_arp_ip4_over_ethernet_address_t delme;
          e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
 
-          memcpy (&delme.ethernet, e->ethernet_address, 6);
+          clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
           delme.ip4.as_u32 = e->key.ip4_address.as_u32;
 
           vnet_arp_unset_ip4_over_ethernet (vnm, e->key.sw_if_index,
@@ -337,7 +347,7 @@ vnet_arp_set_ip4_over_ethernet (vnet_main_t * vnm,
   args.fib_index = fib_index;
   args.is_static = is_static;
   args.is_remove = 0;
-  memcpy (&args.a, a, sizeof (*a));
+  clib_memcpy (&args.a, a, sizeof (*a));
 
   vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback, 
                                (u8 *) &args, sizeof (args));
@@ -357,13 +367,15 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
   ethernet_arp_ip4_over_ethernet_address_t * a = a_arg;
   vlib_main_t * vm = vlib_get_main();
   ip4_main_t * im = &ip4_main;
+  ip_lookup_main_t * lm = &im->lookup_main;
   int make_new_arp_cache_entry=1;
   uword * p;
   ip4_add_del_route_args_t args;
-  ip_adjacency_t adj;
+  ip_adjacency_t adj, * existing_adj;
   pending_resolution_t * pr, * mc;
   
   u32 next_index;
+  u32 adj_index;
 
   fib_index = (fib_index != (u32)~0) 
     ? fib_index : im->fib_index_by_sw_if_index[sw_if_index];
@@ -378,7 +390,8 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
       e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
 
       /* Refuse to over-write static arp. */
-      if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC)
+      if (!is_static &&
+          (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC))
        return -2;
       make_new_arp_cache_entry = 0;
     }
@@ -396,15 +409,40 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
      &adj.rewrite_header,
      sizeof (adj.rewrite_data));
 
-  args.table_index_or_table_id = fib_index;
-  args.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_ADD | IP4_ROUTE_FLAG_NEIGHBOR;
-  args.dst_address = a->ip4;
-  args.dst_address_length = 32;
-  args.adj_index = ~0;
-  args.add_adj = &adj;
-  args.n_add_adj = 1;
+  /* result of this lookup should be next-hop adjacency */
+  adj_index = ip4_fib_lookup_with_table (im, fib_index, &a->ip4, 0);
+  existing_adj = ip_get_adjacency(lm, adj_index);
+
+  if (existing_adj->lookup_next_index == IP_LOOKUP_NEXT_ARP &&
+      existing_adj->arp.next_hop.ip4.as_u32 == a->ip4.as_u32)
+    {
+      u32 * ai;
+      u32 * adjs = vec_dup(e->adjacencies);
+      /* Update all adj assigned to this arp entry */
+      vec_foreach(ai, adjs)
+       {
+         int i;
+         ip_adjacency_t * uadj = ip_get_adjacency(lm, *ai);
+         for (i = 0; i < uadj->n_adj; i++)
+           if (uadj[i].lookup_next_index == IP_LOOKUP_NEXT_ARP &&
+               uadj[i].arp.next_hop.ip4.as_u32 == a->ip4.as_u32)
+             ip_update_adjacency (lm, *ai + i, &adj);
+       }
+      vec_free(adjs);
+    }
+  else
+    {
+      /* create new adj */
+      args.table_index_or_table_id = fib_index;
+      args.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_ADD | IP4_ROUTE_FLAG_NEIGHBOR;
+      args.dst_address = a->ip4;
+      args.dst_address_length = 32;
+      args.adj_index = ~0;
+      args.add_adj = &adj;
+      args.n_add_adj = 1;
+      ip4_add_del_route (im, &args);
+    }
 
-  ip4_add_del_route (im, &args);
   if (make_new_arp_cache_entry)
     {
       pool_get (am->ip4_entry_pool, e);
@@ -415,7 +453,7 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
     }
 
   /* Update time stamp and ethernet address. */
-  memcpy (e->ethernet_address, a->ethernet, sizeof (e->ethernet_address));
+  clib_memcpy (e->ethernet_address, a->ethernet, sizeof (e->ethernet_address));
   e->cpu_time_last_updated = clib_cpu_time_now ();
   if (is_static)
     e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC;
@@ -588,6 +626,7 @@ int vnet_add_del_ip4_arp_change_event (vnet_main_t * vnm,
 /* Either we drop the packet or we send a reply to the sender. */
 typedef enum {
   ARP_INPUT_NEXT_DROP,
+  ARP_INPUT_NEXT_REPLY_TX,
   ARP_INPUT_N_NEXT,
 } arp_input_next_t;
 
@@ -658,19 +697,18 @@ static void unset_random_arp_entry (void)
 
   e = pool_elt_at_index (am->ip4_entry_pool, index);
   
-  memcpy (&delme.ethernet, e->ethernet_address, 6);
+  clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
   delme.ip4.as_u32 = e->key.ip4_address.as_u32;
   
   vnet_arp_unset_ip4_over_ethernet (vnm, e->key.sw_if_index,
                                     e->key.fib_index, &delme);
 }
   
-static u32 arp_unnumbered (vlib_buffer_t * p0, 
-                           u32 pi0,
-                           ethernet_header_t * eth0,
-                           ip_interface_address_t * ifa0)
+static void arp_unnumbered (vlib_buffer_t * p0, 
+                      u32 pi0,
+                      ethernet_header_t * eth0,
+                      ip_interface_address_t * ifa0)
 {
-  ethernet_arp_main_t * am = &ethernet_arp_main;
   vlib_main_t * vm = vlib_get_main();
   vnet_main_t * vnm = vnet_get_main();
   vnet_interface_main_t * vim = &vnm->interface_main;
@@ -687,7 +725,7 @@ static u32 arp_unnumbered (vlib_buffer_t * p0,
   ethernet_arp_header_t * arp0;
 
   /* Save the dst mac address */
-  memcpy(dst_mac_address, eth0->dst_address, sizeof (dst_mac_address));
+  clib_memcpy(dst_mac_address, eth0->dst_address, sizeof (dst_mac_address));
 
   /* Figure out which sw_if_index supplied the address */
   unnum_src_sw_if_index = ifa0->sw_if_index;
@@ -716,7 +754,7 @@ static u32 arp_unnumbered (vlib_buffer_t * p0,
           b0 = vlib_get_buffer (vm, buffers[i]);
 
           /* xerox (partially built) ARP pkt */
-          memcpy (b0->data, p0->data, p0->current_length + p0->current_data);
+          clib_memcpy (b0->data, p0->data, p0->current_length + p0->current_data);
           b0->current_data = p0->current_data;
           b0->current_length = p0->current_length;
           vnet_buffer(b0)->sw_if_index[VLIB_RX] =
@@ -739,7 +777,7 @@ static u32 arp_unnumbered (vlib_buffer_t * p0,
       vnet_buffer(b0)->sw_if_index[VLIB_TX] = hi->sw_if_index;
 
       /* Fix ARP pkt src address */
-      memcpy (arp0->ip4_over_ethernet[0].ethernet, hi->hw_address, 6);
+      clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, hi->hw_address, 6);
 
       /* Build L2 encaps for this swif */
       header_size = sizeof (ethernet_header_t);
@@ -780,8 +818,8 @@ static u32 arp_unnumbered (vlib_buffer_t * p0,
       }
       
       /* Restore the original dst address, set src address */
-      memcpy (eth0->dst_address, dst_mac_address, sizeof (eth0->dst_address));
-      memcpy (eth0->src_address, hi->hw_address, sizeof (eth0->src_address));
+      clib_memcpy (eth0->dst_address, dst_mac_address, sizeof (eth0->dst_address));
+      clib_memcpy (eth0->src_address, hi->hw_address, sizeof (eth0->src_address));
       
       /* Transmit replicas */
       if (i > 0)
@@ -794,13 +832,11 @@ static u32 arp_unnumbered (vlib_buffer_t * p0,
         }
     }
 
-  hi = vnet_get_sup_hw_interface (vnm, broadcast_swifs[0]);
+  /* The regular path outputs the original pkt.. */
+  vnet_buffer (p0)->sw_if_index[VLIB_TX] = broadcast_swifs[0];
 
   vec_free (broadcast_swifs);
   vec_free (buffers);
-
-  /* The regular path outputs the original pkt.. */
-  return vec_elt (am->arp_input_next_index_by_hw_if_index, hi->hw_if_index);
 }
 
 static uword
@@ -943,27 +979,22 @@ arp_input (vlib_main_t * vm,
          vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
          hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
 
-          /* Can happen in a multi-core env. */
-          if (PREDICT_FALSE(hw_if0->hw_if_index >= vec_len (am->arp_input_next_index_by_hw_if_index)))
-            {
-              error0 = ETHERNET_ARP_ERROR_missing_interface_address;
-              goto drop2;
-            }
-
-         next0 = vec_elt (am->arp_input_next_index_by_hw_if_index, hw_if0->hw_if_index);
+         /* Send reply back through input interface */
+         vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
+         next0 = ARP_INPUT_NEXT_REPLY_TX;
 
          arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
 
          arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
 
-         memcpy (arp0->ip4_over_ethernet[0].ethernet, hw_if0->hw_address, 6);
+         clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, hw_if0->hw_address, 6);
          clib_mem_unaligned (&arp0->ip4_over_ethernet[0].ip4.data_u32, u32) = if_addr0->data_u32;
 
          /* Hardware must be ethernet-like. */
          ASSERT (vec_len (hw_if0->hw_address) == 6);
 
-         memcpy (eth0->dst_address, eth0->src_address, 6);
-         memcpy (eth0->src_address, hw_if0->hw_address, 6);
+         clib_memcpy (eth0->dst_address, eth0->src_address, 6);
+         clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
 
          /* Figure out how much to rewind current data from adjacency. */
           if (ifa0)
@@ -976,7 +1007,7 @@ arp_input (vlib_main_t * vm,
                   goto drop2;
                 }
               if (is_unnum0)
-                next0 = arp_unnumbered (p0, pi0, eth0, ifa0);
+                arp_unnumbered (p0, pi0, eth0, ifa0);
               else
                 vlib_buffer_advance (p0, -adj0->rewrite_header.data_bytes);
             }
@@ -1078,32 +1109,13 @@ VLIB_REGISTER_NODE (arp_input_node,static) = {
   .n_next_nodes = ARP_INPUT_N_NEXT,
   .next_nodes = {
     [ARP_INPUT_NEXT_DROP] = "error-drop",
+    [ARP_INPUT_NEXT_REPLY_TX] = "interface-output",
   },
 
   .format_buffer = format_ethernet_arp_header,
   .format_trace = format_ethernet_arp_input_trace,
 };
 
-clib_error_t *
-ethernet_arp_hw_interface_link_up_down (vnet_main_t * vnm,
-                                       u32 hw_if_index,
-                                       u32 flags)
-{
-  ethernet_arp_main_t * am = &ethernet_arp_main;
-  vnet_hw_interface_t * hw_if;
-
-  hw_if = vnet_get_hw_interface (vnm, hw_if_index);
-
-  /* Fill in lookup tables with default table (0). */
-  vec_validate_init_empty (am->arp_input_next_index_by_hw_if_index, hw_if_index, ~0);
-  am->arp_input_next_index_by_hw_if_index[hw_if_index]
-    = vlib_node_add_next (vnm->vlib_main, arp_input_node.index, hw_if->output_node_index);
-
-  return 0;
-}
-
-VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (ethernet_arp_hw_interface_link_up_down);
-
 static int
 ip4_arp_entry_sort (void *a1, void *a2)
 {
@@ -1138,14 +1150,17 @@ show_ip4_arp (vlib_main_t * vm,
 
   es = 0;
   pool_foreach (e, am->ip4_entry_pool, ({ vec_add1 (es, e[0]); }));
-  vec_sort_with_function (es, ip4_arp_entry_sort);
-  vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, 0);
-  vec_foreach (e, es) {
-    if (sw_if_index != ~0 && e->key.sw_if_index != sw_if_index)
-      continue;
-    vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, e);
-  }
-  vec_free (es);
+  if ( es )
+    {
+      vec_sort_with_function (es, ip4_arp_entry_sort);
+      vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, 0);
+      vec_foreach (e, es) {
+        if (sw_if_index != ~0 && e->key.sw_if_index != sw_if_index)
+          continue;
+        vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, e);
+      }
+      vec_free (es);
+    }
 
   if (vec_len (am->proxy_arps))
     {
@@ -1239,10 +1254,91 @@ clib_error_t *ip4_set_arp_limit (u32 arp_limit)
   return 0;
 }
 
+static void
+arp_ip4_entry_del_adj(ethernet_arp_ip4_entry_t *e, u32 adj_index)
+{
+  int done = 0;
+  int i;
+
+  while (!done)
+    {
+      vec_foreach_index(i, e->adjacencies)
+       if (vec_elt(e->adjacencies, i) == adj_index)
+         {
+           vec_del1(e->adjacencies, i);
+           continue;
+         }
+      done = 1;
+    }
+}
+
+static void
+arp_ip4_entry_add_adj(ethernet_arp_ip4_entry_t *e, u32 adj_index)
+{
+  int i;
+  vec_foreach_index(i, e->adjacencies)
+    if (vec_elt(e->adjacencies, i) == adj_index)
+      return;
+  vec_add1(e->adjacencies, adj_index);
+}
+
+static void
+arp_add_del_adj_cb (struct ip_lookup_main_t * lm,
+                   u32 adj_index,
+                   ip_adjacency_t * adj,
+                   u32 is_del)
+{
+  ethernet_arp_main_t * am = &ethernet_arp_main;
+  ip4_main_t * im = &ip4_main;
+  ethernet_arp_ip4_key_t k;
+  ethernet_arp_ip4_entry_t * e = 0;
+  uword * p;
+  u32 ai;
+
+  for(ai = adj->heap_handle; ai < adj->heap_handle + adj->n_adj ; ai++)
+    {
+      adj = ip_get_adjacency (lm, ai);
+      if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP && adj->arp.next_hop.ip4.as_u32)
+       {
+         k.sw_if_index = adj->rewrite_header.sw_if_index;
+         k.ip4_address.as_u32 = adj->arp.next_hop.ip4.as_u32;
+         k.fib_index = im->fib_index_by_sw_if_index[adj->rewrite_header.sw_if_index];
+         p = mhash_get (&am->ip4_entry_by_key, &k);
+         if (p)
+           e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
+       }
+      else
+       continue;
+
+      if (is_del)
+       {
+         if (!e)
+           clib_warning("Adjacency contains unknown ARP next hop %U (del)",
+                        format_ip46_address, &adj->arp.next_hop);
+         else
+           arp_ip4_entry_del_adj(e, adj->heap_handle);
+       }
+      else /* add */
+       {
+         if (!e)
+           clib_warning("Adjacency contains unknown ARP next hop %U (add)",
+                        format_ip46_address, &adj->arp.next_hop);
+         else
+           arp_ip4_entry_add_adj(e, adj->heap_handle);
+       }
+    }
+}
+
 static clib_error_t * ethernet_arp_init (vlib_main_t * vm)
 {
   ethernet_arp_main_t * am = &ethernet_arp_main;
   pg_node_t * pn;
+  clib_error_t * error;
+  ip4_main_t * im = &ip4_main;
+  ip_lookup_main_t * lm = &im->lookup_main;
+
+  if ((error = vlib_call_init_function (vm, ethernet_init)))
+    return error;
 
   ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
 
@@ -1276,7 +1372,9 @@ static clib_error_t * ethernet_arp_init (vlib_main_t * vm)
     foreach_ethernet_arp_error
 #undef _
   }
-  
+
+  ip_register_add_del_adjacency_callback(lm, arp_add_del_adj_cb);
+
   return 0;
 }
 
@@ -1293,7 +1391,7 @@ vnet_arp_unset_ip4_over_ethernet (vnet_main_t * vnm,
   args.sw_if_index = sw_if_index;
   args.fib_index = fib_index;
   args.is_remove = 1;
-  memcpy (&args.a, a, sizeof (*a));
+  clib_memcpy (&args.a, a, sizeof (*a));
 
   vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback, 
                                (u8 *) &args, sizeof (args));
@@ -1467,6 +1565,55 @@ int vnet_proxy_arp_fib_reset (u32 fib_id)
    return 0;
 }
 
+u32
+vnet_arp_glean_add(u32 fib_index, void * next_hop_arg)
+{
+  ethernet_arp_main_t * am = &ethernet_arp_main;
+  ip4_main_t * im = &ip4_main;
+  ip_lookup_main_t * lm = &im->lookup_main;
+  ip4_address_t * next_hop = next_hop_arg;
+  ip_adjacency_t add_adj, *adj;
+  ip4_add_del_route_args_t args;
+  ethernet_arp_ip4_entry_t * e;
+  ethernet_arp_ip4_key_t k;
+  u32 adj_index;
+
+  adj_index = ip4_fib_lookup_with_table(im, fib_index, next_hop, 0);
+  adj = ip_get_adjacency(lm, adj_index);
+
+  if (!adj || adj->lookup_next_index != IP_LOOKUP_NEXT_ARP)
+    return ~0;
+
+  if (adj->arp.next_hop.ip4.as_u32 != 0)
+    return adj_index;
+
+  k.sw_if_index = adj->rewrite_header.sw_if_index;
+  k.fib_index = fib_index;
+  k.ip4_address.as_u32 = next_hop->as_u32;
+
+  if (mhash_get (&am->ip4_entry_by_key, &k))
+    return adj_index;
+
+  pool_get (am->ip4_entry_pool, e);
+  mhash_set (&am->ip4_entry_by_key, &k, e - am->ip4_entry_pool, /* old value */ 0);
+  e->key = k;
+  e->cpu_time_last_updated = clib_cpu_time_now ();
+  e->flags = ETHERNET_ARP_IP4_ENTRY_FLAG_GLEAN;
+
+  memset(&args, 0, sizeof(args));
+  clib_memcpy(&add_adj, adj, sizeof(add_adj));
+  ip46_address_set_ip4(&add_adj.arp.next_hop, next_hop); /* install neighbor /32 route */
+  args.table_index_or_table_id = fib_index;
+  args.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_ADD| IP4_ROUTE_FLAG_NEIGHBOR;
+  args.dst_address.as_u32 = next_hop->as_u32;
+  args.dst_address_length = 32;
+  args.adj_index = ~0;
+  args.add_adj = &add_adj;
+  args.n_add_adj = 1;
+  ip4_add_del_route (im, &args);
+  return ip4_fib_lookup_with_table (im, fib_index, next_hop, 0);
+}
+
 static clib_error_t *
 ip_arp_add_del_command_fn (vlib_main_t * vm,
                 unformat_input_t * input,
@@ -1568,7 +1715,7 @@ ip_arp_add_del_command_fn (vlib_main_t * vm,
 
 VLIB_CLI_COMMAND (ip_arp_add_del_command, static) = {
     .path = "set ip arp",
-    .short_help = "set ip arp [del] <intfc> <ip-address> <mac-address>",
+    .short_help = "set ip arp [del] <intfc> <ip-address> <mac-address> [static] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
     .function = ip_arp_add_del_command_fn,
 };
 
@@ -1682,7 +1829,7 @@ arp_term_l2bd (vlib_main_t * vm,
            {
              u8 *t0 = vlib_add_trace (
                  vm, node, p0, sizeof(ethernet_arp_input_trace_t));
-             memcpy (t0, l3h0, sizeof(ethernet_arp_input_trace_t));
+             clib_memcpy (t0, l3h0, sizeof(ethernet_arp_input_trace_t));
            }
 
          if (PREDICT_FALSE  (
@@ -1761,9 +1908,9 @@ arp_term_l2bd (vlib_main_t * vm,
          arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
          arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
          arp0->ip4_over_ethernet[0].ip4.as_u32 = ip0;
-         memcpy (arp0->ip4_over_ethernet[0].ethernet, macp0, 6);
-         memcpy (eth0->dst_address, eth0->src_address, 6);
-         memcpy (eth0->src_address, macp0, 6);
+         clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, macp0, 6);
+         clib_memcpy (eth0->dst_address, eth0->src_address, 6);
+         clib_memcpy (eth0->src_address, macp0, 6);
          n_replies_sent += 1;
 
          // For BVI, need to use l2-fwd node to send ARP reply as