LISP: support for neighbor discovery 61/8361/4
authorFilip Tehlar <ftehlar@cisco.com>
Tue, 5 Sep 2017 13:46:09 +0000 (15:46 +0200)
committerFlorin Coras <florin.coras@gmail.com>
Tue, 19 Sep 2017 16:00:51 +0000 (16:00 +0000)
Change-Id: I0f1a051dd3b5786dc7c457bc6fc7ce4fcd0f530c
Signed-off-by: Filip Tehlar <ftehlar@cisco.com>
src/vat/api_format.c
src/vnet/lisp-cp/control.c
src/vnet/lisp-cp/control.h
src/vnet/lisp-cp/gid_dictionary.c
src/vnet/lisp-cp/gid_dictionary.h
src/vnet/lisp-cp/lisp_types.c
src/vnet/lisp-cp/lisp_types.h
src/vnet/lisp-cp/one_api.c
src/vnet/lisp-cp/one_cli.c

index ff3354c..520ae4f 100644 (file)
@@ -3392,6 +3392,71 @@ end:
   vam->result_ready = 1;
 }
 
+static void
+  vl_api_one_ndp_entries_get_reply_t_handler
+  (vl_api_one_ndp_entries_get_reply_t * mp)
+{
+  vat_main_t *vam = &vat_main;
+  u32 i, n;
+  int retval = clib_net_to_host_u32 (mp->retval);
+
+  if (retval)
+    goto end;
+
+  n = clib_net_to_host_u32 (mp->count);
+
+  for (i = 0; i < n; i++)
+    print (vam->ofp, "%U -> %U", format_ip6_address, &mp->entries[i].ip6,
+          format_ethernet_address, mp->entries[i].mac);
+
+end:
+  vam->retval = retval;
+  vam->result_ready = 1;
+}
+
+static void
+  vl_api_one_ndp_entries_get_reply_t_handler_json
+  (vl_api_one_ndp_entries_get_reply_t * mp)
+{
+  u8 *s = 0;
+  vat_main_t *vam = &vat_main;
+  vat_json_node_t *e = 0, root;
+  u32 i, n;
+  int retval = clib_net_to_host_u32 (mp->retval);
+  vl_api_one_ndp_entry_t *arp_entry;
+
+  if (retval)
+    goto end;
+
+  n = clib_net_to_host_u32 (mp->count);
+  vat_json_init_array (&root);
+
+  for (i = 0; i < n; i++)
+    {
+      e = vat_json_array_add (&root);
+      arp_entry = &mp->entries[i];
+
+      vat_json_init_object (e);
+      s = format (0, "%U", format_ethernet_address, arp_entry->mac);
+      vec_add1 (s, 0);
+
+      vat_json_object_add_string_copy (e, "mac", s);
+      vec_free (s);
+
+      s = format (0, "%U", format_ip6_address, &arp_entry->ip6);
+      vec_add1 (s, 0);
+      vat_json_object_add_string_copy (e, "ip6", s);
+      vec_free (s);
+    }
+
+  vat_json_print (vam->ofp, &root);
+  vat_json_free (&root);
+
+end:
+  vam->retval = retval;
+  vam->result_ready = 1;
+}
+
 static void
   vl_api_one_l2_arp_entries_get_reply_t_handler
   (vl_api_one_l2_arp_entries_get_reply_t * mp)
@@ -3457,6 +3522,57 @@ end:
   vam->result_ready = 1;
 }
 
+static void
+vl_api_one_ndp_bd_get_reply_t_handler (vl_api_one_ndp_bd_get_reply_t * mp)
+{
+  vat_main_t *vam = &vat_main;
+  u32 i, n;
+  int retval = clib_net_to_host_u32 (mp->retval);
+
+  if (retval)
+    goto end;
+
+  n = clib_net_to_host_u32 (mp->count);
+
+  for (i = 0; i < n; i++)
+    {
+      print (vam->ofp, "%d", clib_net_to_host_u32 (mp->bridge_domains[i]));
+    }
+
+end:
+  vam->retval = retval;
+  vam->result_ready = 1;
+}
+
+static void
+  vl_api_one_ndp_bd_get_reply_t_handler_json
+  (vl_api_one_ndp_bd_get_reply_t * mp)
+{
+  vat_main_t *vam = &vat_main;
+  vat_json_node_t root;
+  u32 i, n;
+  int retval = clib_net_to_host_u32 (mp->retval);
+
+  if (retval)
+    goto end;
+
+  n = clib_net_to_host_u32 (mp->count);
+  vat_json_init_array (&root);
+
+  for (i = 0; i < n; i++)
+    {
+      vat_json_array_add_uint (&root,
+                              clib_net_to_host_u32 (mp->bridge_domains[i]));
+    }
+
+  vat_json_print (vam->ofp, &root);
+  vat_json_free (&root);
+
+end:
+  vam->retval = retval;
+  vam->result_ready = 1;
+}
+
 static void
   vl_api_one_l2_arp_bd_get_reply_t_handler
   (vl_api_one_l2_arp_bd_get_reply_t * mp)
@@ -4590,6 +4706,10 @@ static void vl_api_flow_classify_details_t_handler_json
 #define vl_api_one_l2_arp_entries_get_reply_t_endian vl_noop_handler
 #define vl_api_one_l2_arp_entries_get_reply_t_print vl_noop_handler
 #define vl_api_one_l2_arp_bd_get_reply_t_endian vl_noop_handler
+#define vl_api_one_ndp_bd_get_reply_t_endian vl_noop_handler
+#define vl_api_one_ndp_bd_get_reply_t_print vl_noop_handler
+#define vl_api_one_ndp_entries_get_reply_t_print vl_noop_handler
+#define vl_api_one_ndp_entries_get_reply_t_endian vl_noop_handler
 
 /*
  * Generate boilerplate reply handlers, which
@@ -4706,6 +4826,7 @@ _(one_eid_table_add_del_map_reply)                      \
 _(one_use_petr_reply)                                   \
 _(one_stats_enable_disable_reply)                       \
 _(one_add_del_l2_arp_entry_reply)                       \
+_(one_add_del_ndp_entry_reply)                          \
 _(one_stats_flush_reply)                                \
 _(gpe_enable_disable_reply)                             \
 _(gpe_set_encap_mode_reply)                             \
@@ -4950,6 +5071,9 @@ _(ONE_STATS_FLUSH_REPLY, one_stats_flush_reply)                         \
 _(ONE_STATS_ENABLE_DISABLE_REPLY, one_stats_enable_disable_reply)       \
 _(SHOW_ONE_STATS_ENABLE_DISABLE_REPLY,                                  \
   show_one_stats_enable_disable_reply)                                  \
+_(ONE_ADD_DEL_NDP_ENTRY_REPLY, one_add_del_ndp_entry_reply)             \
+_(ONE_NDP_BD_GET_REPLY, one_ndp_bd_get_reply)                           \
+_(ONE_NDP_ENTRIES_GET_REPLY, one_ndp_entries_get_reply)                 \
 _(ONE_ADD_DEL_L2_ARP_ENTRY_REPLY, one_add_del_l2_arp_entry_reply)       \
 _(ONE_L2_ARP_BD_GET_REPLY, one_l2_arp_bd_get_reply)                     \
 _(ONE_L2_ARP_ENTRIES_GET_REPLY, one_l2_arp_entries_get_reply)           \
@@ -15413,6 +15537,58 @@ api_show_one_rloc_probe_state (vat_main_t * vam)
 
 #define api_show_lisp_rloc_probe_state api_show_one_rloc_probe_state
 
+static int
+api_one_add_del_ndp_entry (vat_main_t * vam)
+{
+  vl_api_one_add_del_ndp_entry_t *mp;
+  unformat_input_t *input = vam->input;
+  u8 is_add = 1;
+  u8 mac_set = 0;
+  u8 bd_set = 0;
+  u8 ip_set = 0;
+  u8 mac[6] = { 0, };
+  u8 ip6[16] = { 0, };
+  u32 bd = ~0;
+  int ret;
+
+  /* Parse args required to build the message */
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "del"))
+       is_add = 0;
+      else if (unformat (input, "mac %U", unformat_ethernet_address, mac))
+       mac_set = 1;
+      else if (unformat (input, "ip %U", unformat_ip6_address, ip6))
+       ip_set = 1;
+      else if (unformat (input, "bd %d", &bd))
+       bd_set = 1;
+      else
+       {
+         errmsg ("parse error '%U'", format_unformat_error, input);
+         return -99;
+       }
+    }
+
+  if (!bd_set || !ip_set || (!mac_set && is_add))
+    {
+      errmsg ("Missing BD, IP or MAC!");
+      return -99;
+    }
+
+  M (ONE_ADD_DEL_NDP_ENTRY, mp);
+  mp->is_add = is_add;
+  clib_memcpy (mp->mac, mac, 6);
+  mp->bd = clib_host_to_net_u32 (bd);
+  clib_memcpy (mp->ip6, ip6, sizeof (mp->ip6));
+
+  /* send */
+  S (mp);
+
+  /* wait for reply */
+  W (ret);
+  return ret;
+}
+
 static int
 api_one_add_del_l2_arp_entry (vat_main_t * vam)
 {
@@ -15464,6 +15640,60 @@ api_one_add_del_l2_arp_entry (vat_main_t * vam)
   return ret;
 }
 
+static int
+api_one_ndp_bd_get (vat_main_t * vam)
+{
+  vl_api_one_ndp_bd_get_t *mp;
+  int ret;
+
+  M (ONE_NDP_BD_GET, mp);
+
+  /* send */
+  S (mp);
+
+  /* wait for reply */
+  W (ret);
+  return ret;
+}
+
+static int
+api_one_ndp_entries_get (vat_main_t * vam)
+{
+  vl_api_one_ndp_entries_get_t *mp;
+  unformat_input_t *input = vam->input;
+  u8 bd_set = 0;
+  u32 bd = ~0;
+  int ret;
+
+  /* Parse args required to build the message */
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "bd %d", &bd))
+       bd_set = 1;
+      else
+       {
+         errmsg ("parse error '%U'", format_unformat_error, input);
+         return -99;
+       }
+    }
+
+  if (!bd_set)
+    {
+      errmsg ("Expected bridge domain!");
+      return -99;
+    }
+
+  M (ONE_NDP_ENTRIES_GET, mp);
+  mp->bd = clib_host_to_net_u32 (bd);
+
+  /* send */
+  S (mp);
+
+  /* wait for reply */
+  W (ret);
+  return ret;
+}
+
 static int
 api_one_l2_arp_bd_get (vat_main_t * vam)
 {
@@ -20411,6 +20641,9 @@ _(one_locator_set_dump, "[local | remote]")                             \
 _(one_locator_dump, "ls_index <index> | ls_name <name>")                \
 _(one_eid_table_dump, "[eid <ipv4|ipv6>/<prefix> | <mac>] [vni] "       \
                        "[local] | [remote]")                            \
+_(one_add_del_ndp_entry, "[del] mac <mac> bd <bd> ip6 <ip6>")           \
+_(one_ndp_bd_get, "")                                                   \
+_(one_ndp_entries_get, "bd <bridge-domain>")                            \
 _(one_add_del_l2_arp_entry, "[del] mac <mac> bd <bd> ip4 <ip4>")        \
 _(one_l2_arp_bd_get, "")                                                \
 _(one_l2_arp_entries_get, "bd <bridge-domain>")                         \
index 74597a6..7aa3b41 100644 (file)
@@ -908,7 +908,11 @@ static void
 add_l2_arp_bd (BVT (clib_bihash_kv) * kvp, void *arg)
 {
   u32 **ht = arg;
-  u32 bd = (u32) kvp->key[0];
+  u32 version = (u32) kvp->key[0];
+  if (IP6 == version)
+    return;
+
+  u32 bd = (u32) (kvp->key[0] >> 32);
   hash_set (ht[0], bd, 0);
 }
 
@@ -918,8 +922,31 @@ vnet_lisp_l2_arp_bds_get (void)
   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
   u32 *bds = 0;
 
-  gid_dict_foreach_l2_arp_entry (&lcm->mapping_index_by_gid,
-                                add_l2_arp_bd, &bds);
+  gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid,
+                                    add_l2_arp_bd, &bds);
+  return bds;
+}
+
+static void
+add_ndp_bd (BVT (clib_bihash_kv) * kvp, void *arg)
+{
+  u32 **ht = arg;
+  u32 version = (u32) kvp->key[0];
+  if (IP4 == version)
+    return;
+
+  u32 bd = (u32) (kvp->key[0] >> 32);
+  hash_set (ht[0], bd, 0);
+}
+
+u32 *
+vnet_lisp_ndp_bds_get (void)
+{
+  lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
+  u32 *bds = 0;
+
+  gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid,
+                                    add_ndp_bd, &bds);
   return bds;
 }
 
@@ -927,15 +954,21 @@ typedef struct
 {
   void *vector;
   u32 bd;
-} lisp_add_l2_arp_args_t;
+} lisp_add_l2_arp_ndp_args_t;
 
 static void
 add_l2_arp_entry (BVT (clib_bihash_kv) * kvp, void *arg)
 {
-  lisp_add_l2_arp_args_t *a = arg;
+  lisp_add_l2_arp_ndp_args_t *a = arg;
   lisp_api_l2_arp_entry_t **vector = a->vector, e;
 
-  if ((u32) kvp->key[0] == a->bd)
+  u32 version = (u32) kvp->key[0];
+  if (IP6 == version)
+    return;
+
+  u32 bd = (u32) (kvp->key[0] >> 32);
+
+  if (bd == a->bd)
     {
       mac_copy (e.mac, (void *) &kvp->value);
       e.ip4 = (u32) kvp->key[1];
@@ -948,13 +981,48 @@ vnet_lisp_l2_arp_entries_get_by_bd (u32 bd)
 {
   lisp_api_l2_arp_entry_t *entries = 0;
   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
-  lisp_add_l2_arp_args_t a;
+  lisp_add_l2_arp_ndp_args_t a;
+
+  a.vector = &entries;
+  a.bd = bd;
+
+  gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid,
+                                    add_l2_arp_entry, &a);
+  return entries;
+}
+
+static void
+add_ndp_entry (BVT (clib_bihash_kv) * kvp, void *arg)
+{
+  lisp_add_l2_arp_ndp_args_t *a = arg;
+  lisp_api_ndp_entry_t **vector = a->vector, e;
+
+  u32 version = (u32) kvp->key[0];
+  if (IP4 == version)
+    return;
+
+  u32 bd = (u32) (kvp->key[0] >> 32);
+
+  if (bd == a->bd)
+    {
+      mac_copy (e.mac, (void *) &kvp->value);
+      clib_memcpy (e.ip6, &kvp->key[1], 16);
+      vec_add1 (vector[0], e);
+    }
+}
+
+lisp_api_ndp_entry_t *
+vnet_lisp_ndp_entries_get_by_bd (u32 bd)
+{
+  lisp_api_ndp_entry_t *entries = 0;
+  lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
+  lisp_add_l2_arp_ndp_args_t a;
 
   a.vector = &entries;
   a.bd = bd;
 
-  gid_dict_foreach_l2_arp_entry (&lcm->mapping_index_by_gid,
-                                add_l2_arp_entry, &a);
+  gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid,
+                                    add_ndp_entry, &a);
   return entries;
 }
 
@@ -2236,7 +2304,9 @@ vnet_lisp_add_del_mreq_itr_rlocs (vnet_lisp_add_del_mreq_itr_rloc_args_t * a)
 #define foreach_lisp_cp_lookup_error           \
 _(DROP, "drop")                                \
 _(MAP_REQUESTS_SENT, "map-request sent")       \
-_(ARP_REPLY_TX, "ARP replies sent")
+_(ARP_REPLY_TX, "ARP replies sent")            \
+_(NDP_NEIGHBOR_ADVERTISEMENT_TX,               \
+  "neighbor advertisement sent")
 
 static char *lisp_cp_lookup_error_strings[] = {
 #define _(sym,string) string,
@@ -2255,7 +2325,7 @@ typedef enum
 typedef enum
 {
   LISP_CP_LOOKUP_NEXT_DROP,
-  LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX,
+  LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX,
   LISP_CP_LOOKUP_N_NEXT,
 } lisp_cp_lookup_next_t;
 
@@ -3069,6 +3139,7 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b,
 {
   ethernet_header_t *eh;
   u32 vni = 0;
+  icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *opt;
 
   memset (src, 0, sizeof (*src));
   memset (dst, 0, sizeof (*dst));
@@ -3116,6 +3187,33 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b,
        }
       else
        {
+         if (clib_net_to_host_u16 (eh->type) == ETHERNET_TYPE_IP6)
+           {
+             ip6_header_t *ip;
+             ip = (ip6_header_t *) (eh + 1);
+
+             if (IP_PROTOCOL_ICMP6 == ip->protocol)
+               {
+                 icmp6_neighbor_solicitation_or_advertisement_header_t *ndh;
+                 ndh = ip6_next_header (ip);
+                 if (ndh->icmp.type == ICMP6_neighbor_solicitation)
+                   {
+                     opt = (void *) (ndh + 1);
+                     if ((opt->header.type !=
+                          ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address)
+                         || (opt->header.n_data_u64s != 1))
+                       return; /* source link layer address option not present */
+
+                     gid_address_type (dst) = GID_ADDR_NDP;
+                     gid_address_ndp_bd (dst) =
+                       lisp_get_bd_from_buffer_eth (b);
+                     ip_address_set (&gid_address_arp_ndp_ip (dst),
+                                     &ndh->target_address, IP6);
+                     return;
+                   }
+               }
+           }
+
          gid_address_type (src) = GID_ADDR_MAC;
          gid_address_type (dst) = GID_ADDR_MAC;
          mac_copy (&gid_address_mac (src), eh->src_address);
@@ -3151,6 +3249,7 @@ lisp_cp_lookup_inline (vlib_main_t * vm,
                       vlib_node_runtime_t * node,
                       vlib_frame_t * from_frame, int overlay)
 {
+  icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *opt;
   u32 *from, *to_next, di, si;
   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
   u32 pkts_mapped = 0, next_index;
@@ -3174,6 +3273,9 @@ lisp_cp_lookup_inline (vlib_main_t * vm,
          ethernet_arp_header_t *arp0;
          ethernet_header_t *eth0;
          vnet_hw_interface_t *hw_if0;
+         ethernet_header_t *eh0;
+         icmp6_neighbor_solicitation_or_advertisement_header_t *ndh;
+         ip6_header_t *ip0;
 
          pi0 = from[0];
          from += 1;
@@ -3190,41 +3292,70 @@ lisp_cp_lookup_inline (vlib_main_t * vm,
          if (gid_address_type (&dst) == GID_ADDR_ARP)
            {
              mac0 = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst);
-             if (GID_LOOKUP_MISS_L2 != mac0)
-               {
-                 /* send ARP reply */
-
-                 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
-                 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
-
-                 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
-
-                 eth0 = vlib_buffer_get_current (b0);
-                 arp0 = (ethernet_arp_header_t *) (((u8 *) eth0)
-                                                   + sizeof (*eth0));
-                 arp0->opcode =
-                   clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
-                 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
-                 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet,
-                              (u8 *) & mac0, 6);
-                 clib_memcpy (&arp0->ip4_over_ethernet[0].ip4,
-                              &gid_address_arp_ip4 (&dst), 4);
-
-                 /* Hardware must be ethernet-like. */
-                 ASSERT (vec_len (hw_if0->hw_address) == 6);
-
-                 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
-                 clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
-
-                 b0->error = node->errors[LISP_CP_LOOKUP_ERROR_ARP_REPLY_TX];
-                 next0 = LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX;
-                 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
-                                                  to_next,
-                                                  n_left_to_next, pi0,
-                                                  next0);
-                 continue;
-               }
-             goto done;
+             if (GID_LOOKUP_MISS_L2 == mac0)
+               goto drop;
+
+             /* send ARP reply */
+             sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+             vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
+
+             hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
+
+             eth0 = vlib_buffer_get_current (b0);
+             arp0 = (ethernet_arp_header_t *) (((u8 *) eth0)
+                                               + sizeof (*eth0));
+             arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
+             arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
+             clib_memcpy (arp0->ip4_over_ethernet[0].ethernet,
+                          (u8 *) & mac0, 6);
+             clib_memcpy (&arp0->ip4_over_ethernet[0].ip4,
+                          &gid_address_arp_ip4 (&dst), 4);
+
+             /* Hardware must be ethernet-like. */
+             ASSERT (vec_len (hw_if0->hw_address) == 6);
+
+             clib_memcpy (eth0->dst_address, eth0->src_address, 6);
+             clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
+
+             b0->error = node->errors[LISP_CP_LOOKUP_ERROR_ARP_REPLY_TX];
+             next0 = LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX;
+             goto enqueue;
+           }
+         else if (gid_address_type (&dst) == GID_ADDR_NDP)
+           {
+             mac0 = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst);
+             if (GID_LOOKUP_MISS_L2 == mac0)
+               goto drop;
+
+             sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+             vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
+
+             eh0 = vlib_buffer_get_current (b0);
+             ip0 = (ip6_header_t *) (eh0 + 1);
+             ndh = ip6_next_header (ip0);
+             int bogus_length;
+             ip0->dst_address = ip0->src_address;
+             ip0->src_address = ndh->target_address;
+             ip0->hop_limit = 255;
+             opt = (void *) (ndh + 1);
+             opt->header.type =
+               ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
+             clib_memcpy (opt->ethernet_address, (u8 *) & mac0, 6);
+             ndh->icmp.type = ICMP6_neighbor_advertisement;
+             ndh->advertisement_flags = clib_host_to_net_u32
+               (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED |
+                ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE);
+             ndh->icmp.checksum = 0;
+             ndh->icmp.checksum =
+               ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0,
+                                                  &bogus_length);
+             clib_memcpy (eh0->dst_address, eh0->src_address, 6);
+             clib_memcpy (eh0->src_address, (u8 *) & mac0, 6);
+             b0->error =
+               node->errors
+               [LISP_CP_LOOKUP_ERROR_NDP_NEIGHBOR_ADVERTISEMENT_TX];
+             next0 = LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX;
+             goto enqueue;
            }
 
          /* if we have remote mapping for destination already in map-chache
@@ -3267,8 +3398,10 @@ lisp_cp_lookup_inline (vlib_main_t * vm,
              pkts_mapped++;
            }
 
-       done:
+       drop:
          b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP];
+         next0 = LISP_CP_LOOKUP_NEXT_DROP;
+       enqueue:
          if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
            {
              lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, b0,
@@ -3281,7 +3414,6 @@ lisp_cp_lookup_inline (vlib_main_t * vm,
            }
          gid_address_free (&dst);
          gid_address_free (&src);
-         next0 = LISP_CP_LOOKUP_NEXT_DROP;
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
                                           to_next,
                                           n_left_to_next, pi0, next0);
@@ -3339,7 +3471,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_ip4_node) = {
 
   .next_nodes = {
       [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
-      [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output",
+      [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output",
   },
 };
 /* *INDENT-ON* */
@@ -3359,7 +3491,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_ip6_node) = {
 
   .next_nodes = {
       [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
-      [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output",
+      [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output",
   },
 };
 /* *INDENT-ON* */
@@ -3379,7 +3511,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_l2_node) = {
 
   .next_nodes = {
       [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
-      [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output",
+      [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output",
   },
 };
 /* *INDENT-ON* */
@@ -3399,7 +3531,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_nsh_node) = {
 
   .next_nodes = {
       [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
-      [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output",
+      [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output",
   },
 };
 /* *INDENT-ON* */
index 12bfcb5..d40f6f5 100644 (file)
@@ -103,6 +103,12 @@ typedef struct
   u32 ip4;
 } lisp_api_l2_arp_entry_t;
 
+typedef struct
+{
+  u8 mac[6];
+  u8 ip6[16];
+} lisp_api_ndp_entry_t;
+
 typedef enum
 {
   MR_MODE_DST_ONLY = 0,
@@ -395,6 +401,8 @@ int vnet_lisp_map_register_set_ttl (u32 ttl);
 u32 vnet_lisp_map_register_get_ttl (void);
 int vnet_lisp_map_register_fallback_threshold_set (u32 value);
 u32 vnet_lisp_map_register_fallback_threshold_get (void);
+u32 *vnet_lisp_ndp_bds_get (void);
+lisp_api_ndp_entry_t *vnet_lisp_ndp_entries_get_by_bd (u32 bd);
 
 map_records_arg_t *parse_map_reply (vlib_buffer_t * b);
 
index cf9a741..c3b9330 100644 (file)
@@ -139,12 +139,13 @@ gid_dict_foreach_subprefix (gid_dictionary_t * db, gid_address_t * eid,
 }
 
 void
-gid_dict_foreach_l2_arp_entry (gid_dictionary_t * db, void (*cb)
-                              (BVT (clib_bihash_kv) * kvp, void *arg),
-                              void *ht)
+gid_dict_foreach_l2_arp_ndp_entry (gid_dictionary_t * db, void (*cb)
+                                  (BVT (clib_bihash_kv) * kvp, void *arg),
+                                  void *ht)
 {
-  gid_l2_arp_table_t *tab = &db->arp_table;
-  BV (clib_bihash_foreach_key_value_pair) (&tab->arp_lookup_table, cb, ht);
+  gid_l2_arp_ndp_table_t *tab = &db->arp_ndp_table;
+  BV (clib_bihash_foreach_key_value_pair) (&tab->arp_ndp_lookup_table, cb,
+                                          ht);
 }
 
 static void
@@ -338,11 +339,19 @@ ip_sd_lookup (gid_dictionary_t * db, u32 vni, ip_prefix_t * dst,
 }
 
 static void
-make_arp_key (BVT (clib_bihash_kv) * kv, u32 bd, ip4_address_t * addr)
+make_arp_ndp_key (BVT (clib_bihash_kv) * kv, u32 bd, ip_address_t * addr)
 {
-  kv->key[0] = (u64) bd;
-  kv->key[1] = (u64) addr->as_u32;
-  kv->key[2] = (u64) 0;
+  kv->key[0] = ((u64) bd << 32) | (u32) ip_addr_version (addr);
+  if (ip_addr_version (addr) == IP4)
+    {
+      kv->key[1] = (u64) addr->ip.v4.as_u32;
+      kv->key[2] = (u64) 0;
+    }
+  else
+    {
+      kv->key[1] = (u64) addr->ip.v6.as_u64[0];
+      kv->key[2] = (u64) addr->ip.v6.as_u64[1];
+    }
 }
 
 static void
@@ -354,13 +363,14 @@ make_nsh_key (BVT (clib_bihash_kv) * kv, u32 vni, u32 spi, u8 si)
 }
 
 static u64
-arp_lookup (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key)
+arp_ndp_lookup (gid_l2_arp_ndp_table_t * db, u32 bd, ip_address_t * key)
 {
   int rv;
   BVT (clib_bihash_kv) kv, value;
 
-  make_arp_key (&kv, bd, key);
-  rv = BV (clib_bihash_search_inline_2) (&db->arp_lookup_table, &kv, &value);
+  make_arp_ndp_key (&kv, bd, key);
+  rv = BV (clib_bihash_search_inline_2) (&db->arp_ndp_lookup_table, &kv,
+                                        &value);
 
   if (rv == 0)
     return value.value;
@@ -414,8 +424,9 @@ gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key)
        }
       break;
     case GID_ADDR_ARP:
-      return arp_lookup (&db->arp_table, gid_address_arp_bd (key),
-                        &gid_address_arp_ip4 (key));
+    case GID_ADDR_NDP:
+      return arp_ndp_lookup (&db->arp_ndp_table, gid_address_arp_ndp_bd (key),
+                            &gid_address_arp_ndp_ip (key));
     case GID_ADDR_NSH:
       return nsh_lookup (&db->nsh_table, gid_address_vni (key),
                         gid_address_nsh_spi (key), gid_address_nsh_si (key));
@@ -890,25 +901,27 @@ add_del_sd (gid_dictionary_t * db, u32 vni, source_dest_t * key, u32 value,
 }
 
 static u64
-add_del_arp (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key, u64 value,
-            u8 is_add)
+add_del_arp_ndp (gid_l2_arp_ndp_table_t * db, u32 bd, ip_address_t * key,
+                u64 value, u8 is_add)
 {
   BVT (clib_bihash_kv) kv, result;
   u32 old_val = ~0;
 
-  make_arp_key (&kv, bd, key);
-  if (BV (clib_bihash_search) (&db->arp_lookup_table, &kv, &result) == 0)
+  make_arp_ndp_key (&kv, bd, key);
+  if (BV (clib_bihash_search) (&db->arp_ndp_lookup_table, &kv, &result) == 0)
     old_val = result.value;
 
   if (is_add)
     {
       kv.value = value;
-      BV (clib_bihash_add_del) (&db->arp_lookup_table, &kv, 1 /* is_add */ );
+      BV (clib_bihash_add_del) (&db->arp_ndp_lookup_table, &kv,
+                               1 /* is_add */ );
       db->count++;
     }
   else
     {
-      BV (clib_bihash_add_del) (&db->arp_lookup_table, &kv, 0 /* is_add */ );
+      BV (clib_bihash_add_del) (&db->arp_ndp_lookup_table, &kv,
+                               0 /* is_add */ );
       db->count--;
     }
   return old_val;
@@ -955,8 +968,10 @@ gid_dictionary_add_del (gid_dictionary_t * db, gid_address_t * key, u64 value,
       return add_del_sd (db, gid_address_vni (key), &gid_address_sd (key),
                         (u32) value, is_add);
     case GID_ADDR_ARP:
-      return add_del_arp (&db->arp_table, gid_address_arp_bd (key),
-                         &gid_address_arp_ip4 (key), value, is_add);
+    case GID_ADDR_NDP:
+      return add_del_arp_ndp (&db->arp_ndp_table,
+                             gid_address_arp_ndp_bd (key),
+                             &gid_address_arp_ndp_ip (key), value, is_add);
     case GID_ADDR_NSH:
       return add_del_nsh (&db->nsh_table, gid_address_vni (key),
                          gid_address_nsh_spi (key), gid_address_nsh_si (key),
@@ -987,20 +1002,21 @@ mac_lookup_init (gid_mac_table_t * db)
 }
 
 static void
-arp_lookup_init (gid_l2_arp_table_t * db)
+arp_ndp_lookup_init (gid_l2_arp_ndp_table_t * db)
 {
-  if (db->arp_lookup_table_nbuckets == 0)
-    db->arp_lookup_table_nbuckets = ARP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS;
+  if (db->arp_ndp_lookup_table_nbuckets == 0)
+    db->arp_ndp_lookup_table_nbuckets =
+      ARP_NDP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS;
 
-  db->arp_lookup_table_nbuckets =
-    1 << max_log2 (db->arp_lookup_table_nbuckets);
+  db->arp_ndp_lookup_table_nbuckets =
+    1 << max_log2 (db->arp_ndp_lookup_table_nbuckets);
 
-  if (db->arp_lookup_table_size == 0)
-    db->arp_lookup_table_size = ARP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE;
+  if (db->arp_ndp_lookup_table_size == 0)
+    db->arp_ndp_lookup_table_size = ARP_NDP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE;
 
-  BV (clib_bihash_init) (&db->arp_lookup_table, "arp lookup table",
-                        db->arp_lookup_table_nbuckets,
-                        db->arp_lookup_table_size);
+  BV (clib_bihash_init) (&db->arp_ndp_lookup_table, "arp ndp lookup table",
+                        db->arp_ndp_lookup_table_nbuckets,
+                        db->arp_ndp_lookup_table_size);
 }
 
 static void
@@ -1026,7 +1042,7 @@ gid_dictionary_init (gid_dictionary_t * db)
   ip4_lookup_init (&db->dst_ip4_table);
   ip6_lookup_init (&db->dst_ip6_table);
   mac_lookup_init (&db->sd_mac_table);
-  arp_lookup_init (&db->arp_table);
+  arp_ndp_lookup_init (&db->arp_ndp_table);
   nsh_lookup_init (&db->nsh_table);
 }
 
index 51806bd..3f8500e 100644 (file)
@@ -36,9 +36,9 @@
 #define MAC_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024)
 #define MAC_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20)
 
-/* Default size of the ARP hash table */
-#define ARP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024)
-#define ARP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20)
+/* Default size of the ARP/NDP hash table */
+#define ARP_NDP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024)
+#define ARP_NDP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20)
 
 /* Default size of the NSH hash table */
 #define NSH_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024)
@@ -100,16 +100,16 @@ typedef struct gid_nsh_table
 
 typedef struct
 {
-  BVT (clib_bihash) arp_lookup_table;
-  u32 arp_lookup_table_nbuckets;
-  uword arp_lookup_table_size;
+  BVT (clib_bihash) arp_ndp_lookup_table;
+  u32 arp_ndp_lookup_table_nbuckets;
+  uword arp_ndp_lookup_table_size;
   u64 count;
-} gid_l2_arp_table_t;
+} gid_l2_arp_ndp_table_t;
 
 typedef struct
 {
-  /** L2 ARP table */
-  gid_l2_arp_table_t arp_table;
+  /** L2 ARP/NDP table */
+  gid_l2_arp_ndp_table_t arp_ndp_table;
 
   /** NSH lookup table */
   gid_nsh_table_t nsh_table;
@@ -146,9 +146,9 @@ gid_dict_foreach_subprefix (gid_dictionary_t * db, gid_address_t * eid,
                            foreach_subprefix_match_cb_t cb, void *arg);
 
 void
-gid_dict_foreach_l2_arp_entry (gid_dictionary_t * db, void (*cb)
-                              (BVT (clib_bihash_kv) * kvp, void *arg),
-                              void *ht);
+gid_dict_foreach_l2_arp_ndp_entry (gid_dictionary_t * db, void (*cb)
+                                  (BVT (clib_bihash_kv) * kvp, void *arg),
+                                  void *ht);
 
 #endif /* VNET_LISP_GPE_GID_DICTIONARY_H_ */
 
index 622f39a..05f046f 100644 (file)
@@ -279,8 +279,9 @@ format_gid_address (u8 * s, va_list * args)
       return format (s, "[%d] %U", gid_address_vni (a), format_mac_address,
                     &gid_address_mac (a));
     case GID_ADDR_ARP:
-      return format (s, "[%d, %U]", gid_address_arp_bd (a),
-                    format_ip4_address, &gid_address_arp_ip4 (a));
+    case GID_ADDR_NDP:
+      return format (s, "[%d, %U]", gid_address_arp_ndp_bd (a),
+                    format_ip_address, &gid_address_arp_ndp_ip (a));
     case GID_ADDR_NSH:
       return format (s, "%U", format_nsh_address, &gid_address_nsh (a));
 
index b17110f..4a919e7 100644 (file)
@@ -91,6 +91,7 @@ typedef enum
   GID_ADDR_SRC_DST,
   GID_ADDR_NSH,
   GID_ADDR_ARP,
+  GID_ADDR_NDP,
   GID_ADDR_NO_ADDRESS,
   GID_ADDR_TYPES
 } gid_address_type_t;
@@ -172,12 +173,15 @@ typedef struct
 
 typedef struct
 {
-  ip4_address_t addr;
+  ip_address_t addr;
   u32 bd;
-} lcaf_arp_t;
+} lcaf_arp_ndp_t;
 
-#define lcaf_arp_ip4(_a) (_a)->addr
-#define lcaf_arp_bd(_a) (_a)->bd
+#define lcaf_arp_ndp_ip(_a) (_a)->addr
+#define lcaf_arp_ndp_ip_ver(_a) ip_addr_version(&lcaf_arp_ndp_ip(_a))
+#define lcaf_arp_ndp_ip4(_a) ip_addr_v4(&lcaf_arp_ndp_ip(_a))
+#define lcaf_arp_ndp_ip6(_a) ip_addr_v6(&lcaf_arp_ndp_ip(_a))
+#define lcaf_arp_ndp_bd(_a) (_a)->bd
 
 typedef struct
 {
@@ -185,7 +189,7 @@ typedef struct
   union
   {
     source_dest_t sd;
-    lcaf_arp_t arp;
+    lcaf_arp_ndp_t arp_ndp;
     vni_t uni;
   };
   u8 type;
@@ -204,7 +208,7 @@ typedef struct _gid_address_t
     lcaf_t lcaf;
     u8 mac[6];
     source_dest_t sd;
-    lcaf_arp_t arp;
+    lcaf_arp_ndp_t arp_ndp;
     nsh_t nsh;
   };
   u8 type;
@@ -275,9 +279,13 @@ void gid_address_ip_set (gid_address_t * dst, void *src, u8 version);
 #define gid_address_sd_dst(_a) sd_dst(&gid_address_sd(_a))
 #define gid_address_sd_src_type(_a) sd_src_type(&gid_address_sd(_a))
 #define gid_address_sd_dst_type(_a) sd_dst_type(&gid_address_sd(_a))
-#define gid_address_arp(_a) (_a)->arp
-#define gid_address_arp_ip4(_a) lcaf_arp_ip4(&gid_address_arp (_a))
-#define gid_address_arp_bd(_a) lcaf_arp_bd(&gid_address_arp (_a))
+#define gid_address_arp_ndp(_a) (_a)->arp_ndp
+#define gid_address_arp_ndp_bd(_a) lcaf_arp_ndp_bd(&gid_address_arp_ndp(_a))
+#define gid_address_arp_ndp_ip(_a) lcaf_arp_ndp_ip(&gid_address_arp_ndp(_a))
+#define gid_address_arp_ip4(_a) lcaf_arp_ndp_ip4(&gid_address_arp_ndp(_a))
+#define gid_address_ndp_ip6(_a) lcaf_arp_ndp_ip6(&gid_address_arp_ndp(_a))
+#define gid_address_ndp_bd gid_address_arp_ndp_bd
+#define gid_address_arp_bd gid_address_arp_ndp_bd
 
 /* 'sub'address functions */
 #define foreach_gid_address_type_fcns  \
index 7c8ba63..96b3d2c 100644 (file)
@@ -130,7 +130,9 @@ _(ONE_STATS_FLUSH, one_stats_flush)                                     \
 _(ONE_L2_ARP_BD_GET, one_l2_arp_bd_get)                                 \
 _(ONE_L2_ARP_ENTRIES_GET, one_l2_arp_entries_get)                       \
 _(ONE_ADD_DEL_L2_ARP_ENTRY, one_add_del_l2_arp_entry)                   \
-
+_(ONE_ADD_DEL_NDP_ENTRY, one_add_del_ndp_entry)                         \
+_(ONE_NDP_BD_GET, one_ndp_bd_get)                                       \
+_(ONE_NDP_ENTRIES_GET, one_ndp_entries_get)                             \
 
 static locator_t *
 unformat_one_locs (vl_api_one_remote_locator_t * rmt_locs, u32 rloc_num)
@@ -1563,13 +1565,55 @@ static void
   gid_address_arp_bd (arp) = clib_net_to_host_u32 (mp->bd);
 
   /* vpp keeps ip4 addresses in network byte order */
-  clib_memcpy (&gid_address_arp_ip4 (arp), &mp->ip4, 4);
+  ip_address_set (&gid_address_arp_ndp_ip (arp), &mp->ip4, IP4);
 
   rv = vnet_lisp_add_del_l2_arp_entry (arp, mp->mac, mp->is_add);
 
   REPLY_MACRO (VL_API_ONE_ADD_DEL_L2_ARP_ENTRY_REPLY);
 }
 
+static void
+vl_api_one_add_del_ndp_entry_t_handler (vl_api_one_add_del_ndp_entry_t * mp)
+{
+  vl_api_one_add_del_ndp_entry_reply_t *rmp;
+  int rv = 0;
+  gid_address_t _g, *g = &_g;
+  memset (g, 0, sizeof (*g));
+
+  gid_address_type (g) = GID_ADDR_NDP;
+  gid_address_ndp_bd (g) = clib_net_to_host_u32 (mp->bd);
+  ip_address_set (&gid_address_arp_ndp_ip (g), mp->ip6, IP6);
+
+  rv = vnet_lisp_add_del_l2_arp_entry (g, mp->mac, mp->is_add);
+
+  REPLY_MACRO (VL_API_ONE_ADD_DEL_NDP_ENTRY_REPLY);
+}
+
+static void
+vl_api_one_ndp_bd_get_t_handler (vl_api_one_ndp_bd_get_t * mp)
+{
+  vl_api_one_ndp_bd_get_reply_t *rmp;
+  int rv = 0;
+  u32 i = 0;
+  hash_pair_t *p;
+
+  u32 *bds = vnet_lisp_ndp_bds_get ();
+  u32 size = hash_elts (bds) * sizeof (u32);
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO4 (VL_API_ONE_NDP_BD_GET_REPLY, size,
+  {
+    rmp->count = clib_host_to_net_u32 (hash_elts (bds));
+    hash_foreach_pair (p, bds,
+    ({
+      rmp->bridge_domains[i++] = clib_host_to_net_u32 (p->key);
+    }));
+  });
+  /* *INDENT-ON* */
+
+  hash_free (bds);
+}
+
 static void
 vl_api_one_l2_arp_bd_get_t_handler (vl_api_one_l2_arp_bd_get_t * mp)
 {
@@ -1653,6 +1697,35 @@ static void
   /* *INDENT-ON* */
 }
 
+static void
+vl_api_one_ndp_entries_get_t_handler (vl_api_one_ndp_entries_get_t * mp)
+{
+  vl_api_one_ndp_entries_get_reply_t *rmp = 0;
+  lisp_api_ndp_entry_t *entries = 0, *e;
+  u32 i = 0;
+  int rv = 0;
+
+  u32 bd = clib_net_to_host_u32 (mp->bd);
+
+  entries = vnet_lisp_ndp_entries_get_by_bd (bd);
+  u32 size = vec_len (entries) * sizeof (vl_api_one_ndp_entry_t);
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO4 (VL_API_ONE_NDP_ENTRIES_GET_REPLY, size,
+  {
+    rmp->count = clib_host_to_net_u32 (vec_len (entries));
+    vec_foreach (e, entries)
+      {
+        mac_copy (rmp->entries[i].mac, e->mac);
+        clib_memcpy (rmp->entries[i].ip6, e->ip6, 16);
+        i++;
+      }
+  });
+  /* *INDENT-ON* */
+
+  vec_free (entries);
+}
+
 /*
  * one_api_hookup
  * Add vpe's API message handlers to the table.
index 3e0c4c0..1e52c9a 100644 (file)
@@ -376,6 +376,42 @@ VLIB_CLI_COMMAND (one_show_l2_arp_entries_command) = {
 };
 /* *INDENT-ON* */
 
+static clib_error_t *
+lisp_show_ndp_entries_command_fn (vlib_main_t * vm,
+                                 unformat_input_t * input,
+                                 vlib_cli_command_t * cmd)
+{
+  u32 *ht = vnet_lisp_ndp_bds_get ();
+  lisp_api_ndp_entry_t *entries, *e;
+  hash_pair_t *p;
+
+  /* *INDENT-OFF* */
+  hash_foreach_pair (p, ht,
+  ({
+    entries = vnet_lisp_ndp_entries_get_by_bd (p->key);
+    vlib_cli_output (vm, "Table: %d", p->key);
+
+    vec_foreach (e, entries)
+      {
+        vlib_cli_output (vm, "\t%U -> %U", format_ip6_address, &e->ip6,
+                         format_mac_address, e->mac);
+      }
+    vec_free (entries);
+  }));
+  /* *INDENT-ON* */
+
+  hash_free (ht);
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (one_show_ndp_entries_command) = {
+    .path = "show one ndp entries",
+    .short_help = "Show ONE NDP entries",
+    .function = lisp_show_ndp_entries_command_fn,
+};
+/* *INDENT-ON* */
+
 /**
  * Handler for add/del remote mapping CLI.
  *