LISP: improve updating the dataplne when locators change
[vpp.git] / src / vnet / lisp-cp / control.c
index 74597a6..907e9a0 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,18 +981,53 @@ 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_entry (&lcm->mapping_index_by_gid,
-                                add_l2_arp_entry, &a);
+  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_ndp_entry (&lcm->mapping_index_by_gid,
+                                    add_ndp_entry, &a);
   return entries;
 }
 
 int
-vnet_lisp_add_del_l2_arp_entry (gid_address_t * key, u8 * mac, u8 is_add)
+vnet_lisp_add_del_l2_arp_ndp_entry (gid_address_t * key, u8 * mac, u8 is_add)
 {
   if (vnet_lisp_enable_disable_status () == 0)
     {
@@ -986,7 +1054,7 @@ vnet_lisp_add_del_l2_arp_entry (gid_address_t * key, u8 * mac, u8 is_add)
     {
       if (res == GID_LOOKUP_MISS_L2)
        {
-         clib_warning ("ONE ARP entry %U not found - cannot delete!",
+         clib_warning ("ONE entry %U not found - cannot delete!",
                        format_gid_address, key);
          return -1;
        }
@@ -1276,6 +1344,8 @@ vnet_lisp_add_mapping (vnet_lisp_add_del_mapping_args_t * a,
   /* new mapping */
   else
     {
+      if (is_updated)
+       is_updated[0] = 1;
       remove_overlapping_sub_prefixes (lcm, &a->eid, 0 == ls_args->locators);
 
       ls_args->is_add = 1;
@@ -1312,6 +1382,7 @@ vnet_lisp_del_mapping (gid_address_t * eid, u32 * res_map_index)
   mapping_t *old_map;
   u32 mi;
 
+  memset (ls_args, 0, sizeof (ls_args[0]));
   memset (m_args, 0, sizeof (m_args[0]));
   if (res_map_index)
     res_map_index[0] = ~0;
@@ -1716,6 +1787,7 @@ get_locator_set_index (vnet_lisp_add_del_locator_set_args_t * a, uword * p)
   /* find locator-set */
   if (a->local)
     {
+      ASSERT (a->name);
       p = hash_get_mem (lcm->locator_set_index_by_name, a->name);
     }
   else
@@ -1751,39 +1823,70 @@ is_locator_in_locator_set (lisp_cp_main_t * lcm, locator_set_t * ls,
 }
 
 static void
-update_adjacencies_by_map_index (lisp_cp_main_t * lcm, u8 is_local,
+update_adjacencies_by_map_index (lisp_cp_main_t * lcm,
                                 u32 mapping_index, u8 remove_only)
 {
   fwd_entry_t *fwd;
   mapping_t *map;
+  uword *fei = 0, *rmts_idxp = 0;
+  u32 **rmts = 0, *remote_idxp = 0, *rmts_copy = 0;
   vnet_lisp_add_del_adjacency_args_t _a, *a = &_a;
+  memset (a, 0, sizeof (*a));
 
   map = pool_elt_at_index (lcm->mapping_pool, mapping_index);
 
-  /* *INDENT-OFF* */
-  pool_foreach(fwd, lcm->fwd_entry_pool,
-  ({
-    if ((is_local && 0 == gid_address_cmp (&map->eid, &fwd->leid)) ||
-        (!is_local && 0 == gid_address_cmp (&map->eid, &fwd->reid)))
-      {
-        a->is_add = 0;
-        gid_address_copy (&a->leid, &fwd->leid);
-        gid_address_copy (&a->reid, &fwd->reid);
+  if (map->local)
+    {
+      rmts_idxp = hash_get (lcm->lcl_to_rmt_adjs_by_lcl_idx, mapping_index);
+      if (rmts_idxp)
+       {
+         rmts =
+           pool_elt_at_index (lcm->lcl_to_rmt_adjacencies, rmts_idxp[0]);
+         rmts_copy = vec_dup (rmts[0]);
 
-        vnet_lisp_add_del_adjacency (a);
+         vec_foreach (remote_idxp, rmts_copy)
+         {
+           fei = hash_get (lcm->fwd_entry_by_mapping_index, remote_idxp[0]);
+           if (!fei)
+             continue;
 
-        if (!remove_only)
-          {
-            a->is_add = 1;
-            vnet_lisp_add_del_adjacency (a);
-          }
-      }
-    }));
-  /* *INDENT-ON* */
+           fwd = pool_elt_at_index (lcm->fwd_entry_pool, fei[0]);
+           a->is_add = 0;
+           gid_address_copy (&a->leid, &fwd->leid);
+           gid_address_copy (&a->reid, &fwd->reid);
+           vnet_lisp_add_del_adjacency (a);
+
+           if (!remove_only)
+             {
+               a->is_add = 1;
+               vnet_lisp_add_del_adjacency (a);
+             }
+         }
+         vec_free (rmts_copy);
+       }
+    }
+  else
+    {
+      fei = hash_get (lcm->fwd_entry_by_mapping_index, mapping_index);
+      if (!fei)
+       return;
+
+      fwd = pool_elt_at_index (lcm->fwd_entry_pool, fei[0]);
+      a->is_add = 0;
+      gid_address_copy (&a->leid, &fwd->leid);
+      gid_address_copy (&a->reid, &fwd->reid);
+      vnet_lisp_add_del_adjacency (a);
+
+      if (!remove_only)
+       {
+         a->is_add = 1;
+         vnet_lisp_add_del_adjacency (a);
+       }
+    }
 }
 
 static void
-update_fwd_entries_by_locator_set (lisp_cp_main_t * lcm, u8 is_local,
+update_fwd_entries_by_locator_set (lisp_cp_main_t * lcm,
                                   u32 ls_index, u8 remove_only)
 {
   u32 i, *map_indexp;
@@ -1797,8 +1900,7 @@ update_fwd_entries_by_locator_set (lisp_cp_main_t * lcm, u8 is_local,
   for (i = 0; i < vec_len (eid_indexes[0]); i++)
     {
       map_indexp = vec_elt_at_index (eid_indexes[0], i);
-      update_adjacencies_by_map_index (lcm, is_local, map_indexp[0],
-                                      remove_only);
+      update_adjacencies_by_map_index (lcm, map_indexp[0], remove_only);
     }
 }
 
@@ -1909,7 +2011,7 @@ vnet_lisp_add_del_locator (vnet_lisp_add_del_locator_set_args_t * a,
          if (removed)
            {
              /* update fwd entries using this locator in DP */
-             update_fwd_entries_by_locator_set (lcm, loc->local, ls_index,
+             update_fwd_entries_by_locator_set (lcm, ls_index,
                                                 vec_len (ls->locator_indices)
                                                 == 0);
            }
@@ -2236,7 +2338,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 +2359,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;
 
@@ -2630,6 +2734,7 @@ foreach_msmr
 /* CP output statistics */
 #define foreach_lisp_cp_output_error                  \
 _(MAP_REGISTERS_SENT, "map-registers sent")           \
+_(MAP_REQUESTS_SENT, "map-requests sent")             \
 _(RLOC_PROBES_SENT, "rloc-probes sent")
 static char *lisp_cp_output_error_strings[] = {
 #define _(sym,string) string,
@@ -2955,6 +3060,9 @@ _send_encapsulated_map_request (lisp_cp_main_t * lcm,
   f->n_vectors = 1;
   vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
 
+  vlib_node_increment_counter (vlib_get_main (), lisp_cp_output_node.index,
+                              LISP_CP_OUTPUT_ERROR_MAP_REQUESTS_SENT, 1);
+
   if (duplicate_pmr)
     /* if there is a pending request already update it */
     {
@@ -3069,6 +3177,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 +3225,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);
@@ -3142,6 +3278,7 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b,
          gid_address_nsh_si (dst) = si;
 
          gid_address_type (dst) = GID_ADDR_NSH;
+         gid_address_type (src) = GID_ADDR_NSH;
        }
     }
 }
@@ -3151,9 +3288,10 @@ 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;
+  u32 next_index;
   uword n_left_from, n_left_to_next;
   vnet_main_t *vnm = vnet_get_main ();
 
@@ -3174,6 +3312,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 +3331,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
@@ -3241,7 +3411,6 @@ lisp_cp_lookup_inline (vlib_main_t * vm,
                  /* send map-request */
                  queue_map_request (&src, &dst, 0 /* smr_invoked */ ,
                                     0 /* is_resend */ );
-                 pkts_mapped++;
                }
              else
                {
@@ -3264,11 +3433,12 @@ lisp_cp_lookup_inline (vlib_main_t * vm,
              /* send map-request */
              queue_map_request (&src, &dst, 0 /* smr_invoked */ ,
                                 0 /* is_resend */ );
-             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 +3451,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);
@@ -3289,9 +3458,6 @@ lisp_cp_lookup_inline (vlib_main_t * vm,
 
       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     }
-  vlib_node_increment_counter (vm, node->node_index,
-                              LISP_CP_LOOKUP_ERROR_MAP_REQUESTS_SENT,
-                              pkts_mapped);
   return from_frame->n_vectors;
 }
 
@@ -3339,7 +3505,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 +3525,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 +3545,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 +3565,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* */
@@ -4219,6 +4385,7 @@ lisp_cp_init (vlib_main_t * vm)
   lcm->map_register_ttl = MAP_REGISTER_DEFAULT_TTL;
   lcm->max_expired_map_registers = MAX_EXPIRED_MAP_REGISTERS_DEFAULT;
   lcm->expired_map_registers = 0;
+  lcm->transport_protocol = LISP_TRANSPORT_PROTOCOL_UDP;
   return 0;
 }
 
@@ -4588,6 +4755,26 @@ VLIB_REGISTER_NODE (lisp_retry_service_node,static) = {
 };
 /* *INDENT-ON* */
 
+u32
+vnet_lisp_set_transport_protocol (u8 protocol)
+{
+  lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
+
+  if (protocol < LISP_TRANSPORT_PROTOCOL_UDP ||
+      protocol > LISP_TRANSPORT_PROTOCOL_API)
+    return VNET_API_ERROR_INVALID_ARGUMENT;
+
+  lcm->transport_protocol = protocol;
+  return 0;
+}
+
+lisp_transport_protocol_t
+vnet_lisp_get_transport_protocol (void)
+{
+  lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
+  return lcm->transport_protocol;
+}
+
 VLIB_INIT_FUNCTION (lisp_cp_init);
 
 /*