aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFilip Tehlar <ftehlar@cisco.com>2017-09-05 15:46:09 +0200
committerFlorin Coras <florin.coras@gmail.com>2017-09-19 16:00:51 +0000
commit058799951d062bbbe4df8df101b4db5bc7797b8f (patch)
treee723fcadfdfbf47d5887503843babe98779dd863
parent02e14b526dc6f30c534e483c8e4a77678e27352e (diff)
LISP: support for neighbor discovery
Change-Id: I0f1a051dd3b5786dc7c457bc6fc7ce4fcd0f530c Signed-off-by: Filip Tehlar <ftehlar@cisco.com>
-rw-r--r--src/vat/api_format.c233
-rw-r--r--src/vnet/lisp-cp/control.c236
-rw-r--r--src/vnet/lisp-cp/control.h8
-rw-r--r--src/vnet/lisp-cp/gid_dictionary.c82
-rw-r--r--src/vnet/lisp-cp/gid_dictionary.h24
-rw-r--r--src/vnet/lisp-cp/lisp_types.c5
-rw-r--r--src/vnet/lisp-cp/lisp_types.h26
-rw-r--r--src/vnet/lisp-cp/one_api.c77
-rw-r--r--src/vnet/lisp-cp/one_cli.c36
9 files changed, 617 insertions, 110 deletions
diff --git a/src/vat/api_format.c b/src/vat/api_format.c
index ff3354c9..520ae4f6 100644
--- a/src/vat/api_format.c
+++ b/src/vat/api_format.c
@@ -3393,6 +3393,71 @@ end:
}
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)
{
@@ -3458,6 +3523,57 @@ end:
}
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) \
@@ -15414,6 +15538,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)
{
vl_api_one_add_del_l2_arp_entry_t *mp;
@@ -15465,6 +15641,60 @@ api_one_add_del_l2_arp_entry (vat_main_t * vam)
}
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)
{
vl_api_one_l2_arp_bd_get_t *mp;
@@ -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>") \
diff --git a/src/vnet/lisp-cp/control.c b/src/vnet/lisp-cp/control.c
index 74597a6b..7aa3b419 100644
--- a/src/vnet/lisp-cp/control.c
+++ b/src/vnet/lisp-cp/control.c
@@ -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* */
diff --git a/src/vnet/lisp-cp/control.h b/src/vnet/lisp-cp/control.h
index 12bfcb51..d40f6f53 100644
--- a/src/vnet/lisp-cp/control.h
+++ b/src/vnet/lisp-cp/control.h
@@ -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);
diff --git a/src/vnet/lisp-cp/gid_dictionary.c b/src/vnet/lisp-cp/gid_dictionary.c
index cf9a741a..c3b93301 100644
--- a/src/vnet/lisp-cp/gid_dictionary.c
+++ b/src/vnet/lisp-cp/gid_dictionary.c
@@ -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);
}
diff --git a/src/vnet/lisp-cp/gid_dictionary.h b/src/vnet/lisp-cp/gid_dictionary.h
index 51806bd6..3f8500e5 100644
--- a/src/vnet/lisp-cp/gid_dictionary.h
+++ b/src/vnet/lisp-cp/gid_dictionary.h
@@ -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_ */
diff --git a/src/vnet/lisp-cp/lisp_types.c b/src/vnet/lisp-cp/lisp_types.c
index 622f39af..05f046fa 100644
--- a/src/vnet/lisp-cp/lisp_types.c
+++ b/src/vnet/lisp-cp/lisp_types.c
@@ -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));
diff --git a/src/vnet/lisp-cp/lisp_types.h b/src/vnet/lisp-cp/lisp_types.h
index b17110f6..4a919e79 100644
--- a/src/vnet/lisp-cp/lisp_types.h
+++ b/src/vnet/lisp-cp/lisp_types.h
@@ -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 \
diff --git a/src/vnet/lisp-cp/one_api.c b/src/vnet/lisp-cp/one_api.c
index 7c8ba63f..96b3d2c0 100644
--- a/src/vnet/lisp-cp/one_api.c
+++ b/src/vnet/lisp-cp/one_api.c
@@ -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,7 +1565,7 @@ 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);
@@ -1571,6 +1573,48 @@ static void
}
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)
{
vl_api_one_l2_arp_bd_get_reply_t *rmp;
@@ -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.
diff --git a/src/vnet/lisp-cp/one_cli.c b/src/vnet/lisp-cp/one_cli.c
index 3e0c4c0a..1e52c9af 100644
--- a/src/vnet/lisp-cp/one_cli.c
+++ b/src/vnet/lisp-cp/one_cli.c
@@ -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.
*