Periodic scan and probe of IP neighbors to maintain neighbor pools
[vpp.git] / src / vnet / ip / ip_api.c
index 5165927..3711c40 100644 (file)
@@ -25,6 +25,7 @@
 #include <vnet/api_errno.h>
 #include <vnet/ethernet/ethernet.h>
 #include <vnet/ip/ip.h>
+#include <vnet/ip/ip_neighbor.h>
 #include <vnet/ip/ip6_neighbor.h>
 #include <vnet/fib/fib_table.h>
 #include <vnet/fib/fib_api.h>
@@ -42,6 +43,8 @@
 #include <vnet/fib/ip4_fib.h>
 #include <vnet/fib/ip6_fib.h>
 #include <vnet/ip/ip6_hop_by_hop.h>
+#include <vnet/ip/ip4_reassembly.h>
+#include <vnet/ip/ip6_reassembly.h>
 
 #include <vnet/vnet_msg_enum.h>
 
@@ -74,8 +77,11 @@ _(IP_ADDRESS_DUMP, ip_address_dump)                                     \
 _(IP_DUMP, ip_dump)                                                     \
 _(IP_NEIGHBOR_ADD_DEL, ip_neighbor_add_del)                             \
 _(SET_ARP_NEIGHBOR_LIMIT, set_arp_neighbor_limit)                      \
+_(IP_PROBE_NEIGHBOR, ip_probe_neighbor)                                \
+_(IP_SCAN_NEIGHBOR_ENABLE_DISABLE, ip_scan_neighbor_enable_disable)     \
 _(WANT_IP4_ARP_EVENTS, want_ip4_arp_events)                             \
 _(WANT_IP6_ND_EVENTS, want_ip6_nd_events)                               \
+_(WANT_IP6_RA_EVENTS, want_ip6_ra_events)                               \
 _(PROXY_ARP_ADD_DEL, proxy_arp_add_del)                                 \
 _(PROXY_ARP_INTFC_ENABLE_DISABLE, proxy_arp_intfc_enable_disable)       \
 _(RESET_FIB, reset_fib)                                                        \
@@ -88,6 +94,7 @@ _(SW_INTERFACE_IP6ND_RA_CONFIG, sw_interface_ip6nd_ra_config)           \
 _(SW_INTERFACE_IP6ND_RA_PREFIX, sw_interface_ip6nd_ra_prefix)           \
 _(IP6ND_PROXY_ADD_DEL, ip6nd_proxy_add_del)                             \
 _(IP6ND_PROXY_DUMP, ip6nd_proxy_dump)                                   \
+_(IP6ND_SEND_ROUTER_SOLICITATION, ip6nd_send_router_solicitation)       \
 _(SW_INTERFACE_IP6_ENABLE_DISABLE, sw_interface_ip6_enable_disable )    \
 _(SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS,                             \
   sw_interface_ip6_set_link_local_address)                             \
@@ -97,7 +104,10 @@ _(IOAM_DISABLE, ioam_disable)                                           \
 _(IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL,                               \
   ip_source_and_port_range_check_add_del)                               \
 _(IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL,                     \
-  ip_source_and_port_range_check_interface_add_del)
+  ip_source_and_port_range_check_interface_add_del)                     \
+_(IP_REASSEMBLY_SET, ip_reassembly_set)                                 \
+_(IP_REASSEMBLY_GET, ip_reassembly_get)                                 \
+_(IP_REASSEMBLY_ENABLE_DISABLE, ip_reassembly_enable_disable)
 
 extern void stats_dslock_with_hint (int hint, int tag);
 extern void stats_dsunlock (void);
@@ -107,8 +117,8 @@ send_ip_neighbor_details (u32 sw_if_index,
                          u8 is_ipv6,
                          u8 is_static,
                          u8 * mac_address,
-                         u8 * ip_address,
-                         unix_shared_memory_queue_t * q, u32 context)
+                         u8 * ip_address, vl_api_registration_t * reg,
+                         u32 context)
 {
   vl_api_ip_neighbor_details_t *mp;
 
@@ -122,16 +132,16 @@ send_ip_neighbor_details (u32 sw_if_index,
   memcpy (mp->mac_address, mac_address, 6);
   memcpy (mp->ip_address, ip_address, (is_ipv6) ? 16 : 4);
 
-  vl_msg_api_send_shmem (q, (u8 *) & mp);
+  vl_api_send_msg (reg, (u8 *) mp);
 }
 
 static void
 vl_api_ip_neighbor_dump_t_handler (vl_api_ip_neighbor_dump_t * mp)
 {
-  unix_shared_memory_queue_t *q;
+  vl_api_registration_t *reg;
 
-  q = vl_api_client_index_to_input_queue (mp->client_index);
-  if (q == 0)
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
     return;
 
   u32 sw_if_index = ntohl (mp->sw_if_index);
@@ -149,7 +159,7 @@ vl_api_ip_neighbor_dump_t_handler (vl_api_ip_neighbor_dump_t * mp)
           ((n->flags & IP6_NEIGHBOR_FLAG_STATIC) ? 1 : 0),
            (u8 *) n->link_layer_address,
            (u8 *) & (n->key.ip6_address.as_u8),
-           q, mp->context);
+           reg, mp->context);
       }
       /* *INDENT-ON* */
       vec_free (ns);
@@ -166,43 +176,16 @@ vl_api_ip_neighbor_dump_t_handler (vl_api_ip_neighbor_dump_t * mp)
           ((n->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC) ? 1 : 0),
           (u8*) n->ethernet_address,
           (u8*) & (n->ip4_address.as_u8),
-          q, mp->context);
+          reg, mp->context);
       }
       /* *INDENT-ON* */
       vec_free (ns);
     }
 }
 
-
-void
-copy_fib_next_hop (fib_route_path_encode_t * api_rpath, void *fp_arg)
-{
-  int is_ip4;
-  vl_api_fib_path_t *fp = (vl_api_fib_path_t *) fp_arg;
-
-  if (api_rpath->rpath.frp_proto == DPO_PROTO_IP4)
-    fp->afi = IP46_TYPE_IP4;
-  else if (api_rpath->rpath.frp_proto == DPO_PROTO_IP6)
-    fp->afi = IP46_TYPE_IP6;
-  else
-    {
-      is_ip4 = ip46_address_is_ip4 (&api_rpath->rpath.frp_addr);
-      if (is_ip4)
-       fp->afi = IP46_TYPE_IP4;
-      else
-       fp->afi = IP46_TYPE_IP6;
-    }
-  if (fp->afi == IP46_TYPE_IP4)
-    memcpy (fp->next_hop, &api_rpath->rpath.frp_addr.ip4,
-           sizeof (api_rpath->rpath.frp_addr.ip4));
-  else
-    memcpy (fp->next_hop, &api_rpath->rpath.frp_addr.ip6,
-           sizeof (api_rpath->rpath.frp_addr.ip6));
-}
-
 static void
 send_ip_fib_details (vpe_api_main_t * am,
-                    unix_shared_memory_queue_t * q,
+                    vl_api_registration_t * reg,
                     const fib_table_t * table,
                     const fib_prefix_t * pfx,
                     fib_route_path_encode_t * api_rpaths, u32 context)
@@ -230,42 +213,11 @@ send_ip_fib_details (vpe_api_main_t * am,
   fp = mp->path;
   vec_foreach (api_rpath, api_rpaths)
   {
-    memset (fp, 0, sizeof (*fp));
-    switch (api_rpath->dpo.dpoi_type)
-      {
-      case DPO_RECEIVE:
-       fp->is_local = true;
-       break;
-      case DPO_DROP:
-       fp->is_drop = true;
-       break;
-      case DPO_IP_NULL:
-       switch (api_rpath->dpo.dpoi_index)
-         {
-         case IP_NULL_ACTION_NONE:
-           fp->is_drop = true;
-           break;
-         case IP_NULL_ACTION_SEND_ICMP_UNREACH:
-           fp->is_unreach = true;
-           break;
-         case IP_NULL_ACTION_SEND_ICMP_PROHIBIT:
-           fp->is_prohibit = true;
-           break;
-         default:
-           break;
-         }
-       break;
-      default:
-       break;
-      }
-    fp->weight = api_rpath->rpath.frp_weight;
-    fp->preference = api_rpath->rpath.frp_preference;
-    fp->sw_if_index = htonl (api_rpath->rpath.frp_sw_if_index);
-    copy_fib_next_hop (api_rpath, fp);
+    fib_api_path_encode (api_rpath, fp);
     fp++;
   }
 
-  vl_msg_api_send_shmem (q, (u8 *) & mp);
+  vl_api_send_msg (reg, (u8 *) mp);
 }
 
 typedef struct vl_api_ip_fib_dump_walk_ctx_t_
@@ -273,21 +225,21 @@ typedef struct vl_api_ip_fib_dump_walk_ctx_t_
   fib_node_index_t *feis;
 } vl_api_ip_fib_dump_walk_ctx_t;
 
-static int
+static fib_table_walk_rc_t
 vl_api_ip_fib_dump_walk (fib_node_index_t fei, void *arg)
 {
   vl_api_ip_fib_dump_walk_ctx_t *ctx = arg;
 
   vec_add1 (ctx->feis, fei);
 
-  return (1);
+  return (FIB_TABLE_WALK_CONTINUE);
 }
 
 static void
 vl_api_ip_fib_dump_t_handler (vl_api_ip_fib_dump_t * mp)
 {
   vpe_api_main_t *am = &vpe_api_main;
-  unix_shared_memory_queue_t *q;
+  vl_api_registration_t *reg;
   ip4_main_t *im = &ip4_main;
   fib_table_t *fib_table;
   fib_node_index_t *lfeip;
@@ -298,8 +250,8 @@ vl_api_ip_fib_dump_t_handler (vl_api_ip_fib_dump_t * mp)
     .feis = NULL,
   };
 
-  q = vl_api_client_index_to_input_queue (mp->client_index);
-  if (q == 0)
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
     return;
 
   /* *INDENT-OFF* */
@@ -321,7 +273,7 @@ vl_api_ip_fib_dump_t_handler (vl_api_ip_fib_dump_t * mp)
     fib_table = fib_table_get (fib_index, pfx.fp_proto);
     api_rpaths = NULL;
     fib_entry_encode (*lfeip, &api_rpaths);
-    send_ip_fib_details (am, q, fib_table, &pfx, api_rpaths, mp->context);
+    send_ip_fib_details (am, reg, fib_table, &pfx, api_rpaths, mp->context);
     vec_free (api_rpaths);
   }
 
@@ -330,8 +282,9 @@ vl_api_ip_fib_dump_t_handler (vl_api_ip_fib_dump_t * mp)
 
 static void
 send_ip6_fib_details (vpe_api_main_t * am,
-                     unix_shared_memory_queue_t * q,
-                     u32 table_id, fib_prefix_t * pfx,
+                     vl_api_registration_t * reg,
+                     const fib_table_t * table,
+                     const fib_prefix_t * pfx,
                      fib_route_path_encode_t * api_rpaths, u32 context)
 {
   vl_api_ip6_fib_details_t *mp;
@@ -347,50 +300,21 @@ send_ip6_fib_details (vpe_api_main_t * am,
   mp->_vl_msg_id = ntohs (VL_API_IP6_FIB_DETAILS);
   mp->context = context;
 
-  mp->table_id = htonl (table_id);
+  mp->table_id = htonl (table->ft_table_id);
   mp->address_length = pfx->fp_len;
   memcpy (mp->address, &pfx->fp_addr.ip6, sizeof (pfx->fp_addr.ip6));
+  memcpy (mp->table_name, table->ft_desc,
+         clib_min (vec_len (table->ft_desc), sizeof (mp->table_name)));
 
   mp->count = htonl (path_count);
   fp = mp->path;
   vec_foreach (api_rpath, api_rpaths)
   {
-    memset (fp, 0, sizeof (*fp));
-    switch (api_rpath->dpo.dpoi_type)
-      {
-      case DPO_RECEIVE:
-       fp->is_local = true;
-       break;
-      case DPO_DROP:
-       fp->is_drop = true;
-       break;
-      case DPO_IP_NULL:
-       switch (api_rpath->dpo.dpoi_index)
-         {
-         case IP_NULL_DPO_ACTION_NUM + IP_NULL_ACTION_NONE:
-           fp->is_drop = true;
-           break;
-         case IP_NULL_DPO_ACTION_NUM + IP_NULL_ACTION_SEND_ICMP_UNREACH:
-           fp->is_unreach = true;
-           break;
-         case IP_NULL_DPO_ACTION_NUM + IP_NULL_ACTION_SEND_ICMP_PROHIBIT:
-           fp->is_prohibit = true;
-           break;
-         default:
-           break;
-         }
-       break;
-      default:
-       break;
-      }
-    fp->weight = api_rpath->rpath.frp_weight;
-    fp->preference = api_rpath->rpath.frp_preference;
-    fp->sw_if_index = htonl (api_rpath->rpath.frp_sw_if_index);
-    copy_fib_next_hop (api_rpath, fp);
+    fib_api_path_encode (api_rpath, fp);
     fp++;
   }
 
-  vl_msg_api_send_shmem (q, (u8 *) & mp);
+  vl_api_send_msg (reg, (u8 *) mp);
 }
 
 typedef struct apt_ip6_fib_show_ctx_t_
@@ -411,7 +335,7 @@ api_ip6_fib_table_put_entries (clib_bihash_kv_24_8_t * kvp, void *arg)
 }
 
 static void
-api_ip6_fib_table_get_all (unix_shared_memory_queue_t * q,
+api_ip6_fib_table_get_all (vl_api_registration_t * reg,
                           vl_api_ip6_fib_dump_t * mp,
                           fib_table_t * fib_table)
 {
@@ -436,9 +360,7 @@ api_ip6_fib_table_get_all (unix_shared_memory_queue_t * q,
     fib_entry_get_prefix (*fib_entry_index, &pfx);
     api_rpaths = NULL;
     fib_entry_encode (*fib_entry_index, &api_rpaths);
-    send_ip6_fib_details (am, q,
-                         fib_table->ft_table_id,
-                         &pfx, api_rpaths, mp->context);
+    send_ip6_fib_details (am, reg, fib_table, &pfx, api_rpaths, mp->context);
     vec_free (api_rpaths);
   }
 
@@ -448,24 +370,28 @@ api_ip6_fib_table_get_all (unix_shared_memory_queue_t * q,
 static void
 vl_api_ip6_fib_dump_t_handler (vl_api_ip6_fib_dump_t * mp)
 {
-  unix_shared_memory_queue_t *q;
+  vl_api_registration_t *reg;
   ip6_main_t *im6 = &ip6_main;
   fib_table_t *fib_table;
 
-  q = vl_api_client_index_to_input_queue (mp->client_index);
-  if (q == 0)
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
     return;
 
   /* *INDENT-OFF* */
   pool_foreach (fib_table, im6->fibs,
   ({
-    api_ip6_fib_table_get_all(q, mp, fib_table);
+    /* don't send link locals */
+    if (fib_table->ft_flags & FIB_TABLE_FLAG_IP6_LL)
+      continue;
+
+    api_ip6_fib_table_get_all(reg, mp, fib_table);
   }));
   /* *INDENT-ON* */
 }
 
 static void
-send_ip_mfib_details (unix_shared_memory_queue_t * q,
+send_ip_mfib_details (vl_api_registration_t * reg,
                      u32 context, u32 table_id, fib_node_index_t mfei)
 {
   fib_route_path_encode_t *api_rpath, *api_rpaths = NULL;
@@ -500,16 +426,12 @@ send_ip_mfib_details (unix_shared_memory_queue_t * q,
   fp = mp->path;
   vec_foreach (api_rpath, api_rpaths)
   {
-    memset (fp, 0, sizeof (*fp));
-
-    fp->weight = 0;
-    fp->sw_if_index = htonl (api_rpath->rpath.frp_sw_if_index);
-    copy_fib_next_hop (api_rpath, fp);
+    fib_api_path_encode (api_rpath, fp);
     fp++;
   }
   vec_free (api_rpaths);
 
-  vl_msg_api_send_shmem (q, (u8 *) & mp);
+  vl_api_send_msg (reg, (u8 *) mp);
 }
 
 typedef struct vl_api_ip_mfib_dump_ctc_t_
@@ -530,7 +452,7 @@ vl_api_ip_mfib_table_dump_walk (fib_node_index_t fei, void *arg)
 static void
 vl_api_ip_mfib_dump_t_handler (vl_api_ip_mfib_dump_t * mp)
 {
-  unix_shared_memory_queue_t *q;
+  vl_api_registration_t *reg;
   ip4_main_t *im = &ip4_main;
   mfib_table_t *mfib_table;
   fib_node_index_t *mfeip;
@@ -538,11 +460,10 @@ vl_api_ip_mfib_dump_t_handler (vl_api_ip_mfib_dump_t * mp)
     .entries = NULL,
   };
 
-  q = vl_api_client_index_to_input_queue (mp->client_index);
-  if (q == 0)
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
     return;
 
-
   /* *INDENT-OFF* */
   pool_foreach (mfib_table, im->mfibs,
   ({
@@ -554,7 +475,7 @@ vl_api_ip_mfib_dump_t_handler (vl_api_ip_mfib_dump_t * mp)
 
     vec_foreach (mfeip, ctx.entries)
     {
-      send_ip_mfib_details (q, mp->context,
+      send_ip_mfib_details (reg, mp->context,
                             mfib_table->mft_table_id,
                             *mfeip);
     }
@@ -568,7 +489,7 @@ vl_api_ip_mfib_dump_t_handler (vl_api_ip_mfib_dump_t * mp)
 
 static void
 send_ip6_mfib_details (vpe_api_main_t * am,
-                      unix_shared_memory_queue_t * q,
+                      vl_api_registration_t * reg,
                       u32 table_id,
                       mfib_prefix_t * pfx,
                       fib_route_path_encode_t * api_rpaths, u32 context)
@@ -597,15 +518,11 @@ send_ip6_mfib_details (vpe_api_main_t * am,
   fp = mp->path;
   vec_foreach (api_rpath, api_rpaths)
   {
-    memset (fp, 0, sizeof (*fp));
-
-    fp->weight = 0;
-    fp->sw_if_index = htonl (api_rpath->rpath.frp_sw_if_index);
-    copy_fib_next_hop (api_rpath, fp);
+    fib_api_path_encode (api_rpath, fp);
     fp++;
   }
 
-  vl_msg_api_send_shmem (q, (u8 *) & mp);
+  vl_api_send_msg (reg, (u8 *) mp);
 }
 
 typedef struct vl_api_ip6_mfib_dump_ctc_t_
@@ -627,7 +544,7 @@ static void
 vl_api_ip6_mfib_dump_t_handler (vl_api_ip6_mfib_dump_t * mp)
 {
   vpe_api_main_t *am = &vpe_api_main;
-  unix_shared_memory_queue_t *q;
+  vl_api_registration_t *reg;
   ip6_main_t *im = &ip6_main;
   mfib_table_t *mfib_table;
   fib_node_index_t *mfeip;
@@ -637,8 +554,8 @@ vl_api_ip6_mfib_dump_t_handler (vl_api_ip6_mfib_dump_t * mp)
     .entries = NULL,
   };
 
-  q = vl_api_client_index_to_input_queue (mp->client_index);
-  if (q == 0)
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
     return;
 
 
@@ -655,7 +572,7 @@ vl_api_ip6_mfib_dump_t_handler (vl_api_ip6_mfib_dump_t * mp)
     {
       mfib_entry_get_prefix (*mfeip, &pfx);
       mfib_entry_encode (*mfeip, &api_rpaths);
-      send_ip6_mfib_details (am, q,
+      send_ip6_mfib_details (am, reg,
                              mfib_table->mft_table_id,
                              &pfx, api_rpaths,
                              mp->context);
@@ -850,7 +767,7 @@ add_del_route_t_handler (u8 is_multipath,
                         u8 is_resolve_attached,
                         u8 is_interface_rx,
                         u8 is_rpf_id,
-                        u8 is_l2_bridged,
+                        u8 is_dvr,
                         u8 is_source_lookup,
                         u8 is_udp_encap,
                         u32 fib_index,
@@ -863,7 +780,7 @@ add_del_route_t_handler (u8 is_multipath,
                         u16 next_hop_weight,
                         u16 next_hop_preference,
                         mpls_label_t next_hop_via_label,
-                        mpls_label_t * next_hop_out_label_stack)
+                        fib_mpls_label_t * next_hop_out_label_stack)
 {
   vnet_classify_main_t *cm = &vnet_classify_main;
   fib_route_path_flags_t path_flags = FIB_ROUTE_PATH_FLAG_NONE;
@@ -891,8 +808,8 @@ add_del_route_t_handler (u8 is_multipath,
       path.frp_local_label = next_hop_via_label;
       path.frp_eos = MPLS_NON_EOS;
     }
-  if (is_l2_bridged)
-    path.frp_proto = DPO_PROTO_ETHERNET;
+  if (is_dvr)
+    path_flags |= FIB_ROUTE_PATH_DVR;
   if (is_resolve_host)
     path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
   if (is_resolve_attached)
@@ -910,6 +827,11 @@ add_del_route_t_handler (u8 is_multipath,
       path_flags |= FIB_ROUTE_PATH_UDP_ENCAP;
       path.frp_udp_encap_id = next_hop_id;
     }
+  if (path.frp_sw_if_index == ~0 && ip46_address_is_zero (&path.frp_addr)
+      && path.frp_fib_index != ~0)
+    {
+      path_flags |= FIB_ROUTE_PATH_DEAG;
+    }
 
   path.frp_flags = path_flags;
 
@@ -1017,23 +939,11 @@ add_del_route_check (fib_protocol_t table_proto,
 {
   vnet_main_t *vnm = vnet_get_main ();
 
-  /* Temporaray whilst I do the CSIT dance */
-  u8 create_missing_tables = 1;
-
   *fib_index = fib_table_find (table_proto, ntohl (table_id));
   if (~0 == *fib_index)
     {
-      if (create_missing_tables)
-       {
-         *fib_index = fib_table_find_or_create_and_lock (table_proto,
-                                                         ntohl (table_id),
-                                                         FIB_SOURCE_API);
-       }
-      else
-       {
-         /* No such VRF, and we weren't asked to create one */
-         return VNET_API_ERROR_NO_SUCH_FIB;
-       }
+      /* No such VRF, and we weren't asked to create one */
+      return VNET_API_ERROR_NO_SUCH_FIB;
     }
 
   if (!is_rpf_id && ~0 != ntohl (next_hop_sw_if_index))
@@ -1062,26 +972,8 @@ add_del_route_check (fib_protocol_t table_proto,
 
       if (~0 == *next_hop_fib_index)
        {
-         if (create_missing_tables)
-           {
-             if (is_rpf_id)
-               *next_hop_fib_index =
-                 mfib_table_find_or_create_and_lock (fib_nh_proto,
-                                                     ntohl
-                                                     (next_hop_table_id),
-                                                     MFIB_SOURCE_API);
-             else
-               *next_hop_fib_index =
-                 fib_table_find_or_create_and_lock (fib_nh_proto,
-                                                    ntohl
-                                                    (next_hop_table_id),
-                                                    FIB_SOURCE_API);
-           }
-         else
-           {
-             /* No such VRF, and we weren't asked to create one */
-             return VNET_API_ERROR_NO_SUCH_FIB;
-           }
+         /* No such VRF, and we weren't asked to create one */
+         return VNET_API_ERROR_NO_SUCH_FIB;
        }
     }
 
@@ -1092,7 +984,7 @@ static int
 ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
 {
   u32 fib_index, next_hop_fib_index;
-  mpls_label_t *label_stack = NULL;
+  fib_mpls_label_t *label_stack = NULL;
   int rv, ii, n_labels;;
 
   rv = add_del_route_check (FIB_PROTOCOL_IP4,
@@ -1118,13 +1010,19 @@ ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
   n_labels = mp->next_hop_n_out_labels;
   if (n_labels == 0)
     ;
-  else if (1 == n_labels)
-    vec_add1 (label_stack, ntohl (mp->next_hop_out_label_stack[0]));
   else
     {
       vec_validate (label_stack, n_labels - 1);
       for (ii = 0; ii < n_labels; ii++)
-       label_stack[ii] = ntohl (mp->next_hop_out_label_stack[ii]);
+       {
+         label_stack[ii].fml_value =
+           ntohl (mp->next_hop_out_label_stack[ii].label);
+         label_stack[ii].fml_ttl = mp->next_hop_out_label_stack[ii].ttl;
+         label_stack[ii].fml_exp = mp->next_hop_out_label_stack[ii].exp;
+         label_stack[ii].fml_mode =
+           (mp->next_hop_out_label_stack[ii].is_uniform ?
+            FIB_MPLS_LSP_MODE_UNIFORM : FIB_MPLS_LSP_MODE_PIPE);
+       }
     }
 
   return (add_del_route_t_handler (mp->is_multipath,
@@ -1137,7 +1035,7 @@ ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
                                   mp->classify_table_index,
                                   mp->is_resolve_host,
                                   mp->is_resolve_attached, 0, 0,
-                                  mp->is_l2_bridged,
+                                  mp->is_dvr,
                                   mp->is_source_lookup,
                                   mp->is_udp_encap,
                                   fib_index, &pfx, DPO_PROTO_IP4,
@@ -1154,8 +1052,8 @@ ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
 static int
 ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
 {
+  fib_mpls_label_t *label_stack = NULL;
   u32 fib_index, next_hop_fib_index;
-  mpls_label_t *label_stack = NULL;
   int rv, ii, n_labels;;
 
   rv = add_del_route_check (FIB_PROTOCOL_IP6,
@@ -1181,13 +1079,19 @@ ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
   n_labels = mp->next_hop_n_out_labels;
   if (n_labels == 0)
     ;
-  else if (1 == n_labels)
-    vec_add1 (label_stack, ntohl (mp->next_hop_out_label_stack[0]));
   else
     {
       vec_validate (label_stack, n_labels - 1);
       for (ii = 0; ii < n_labels; ii++)
-       label_stack[ii] = ntohl (mp->next_hop_out_label_stack[ii]);
+       {
+         label_stack[ii].fml_value =
+           ntohl (mp->next_hop_out_label_stack[ii].label);
+         label_stack[ii].fml_ttl = mp->next_hop_out_label_stack[ii].ttl;
+         label_stack[ii].fml_exp = mp->next_hop_out_label_stack[ii].exp;
+         label_stack[ii].fml_mode =
+           (mp->next_hop_out_label_stack[ii].is_uniform ?
+            FIB_MPLS_LSP_MODE_UNIFORM : FIB_MPLS_LSP_MODE_PIPE);
+       }
     }
 
   return (add_del_route_t_handler (mp->is_multipath,
@@ -1200,7 +1104,7 @@ ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
                                   mp->classify_table_index,
                                   mp->is_resolve_host,
                                   mp->is_resolve_attached, 0, 0,
-                                  mp->is_l2_bridged,
+                                  mp->is_dvr,
                                   mp->is_source_lookup,
                                   mp->is_udp_encap,
                                   fib_index, &pfx, DPO_PROTO_IP6,
@@ -1306,13 +1210,15 @@ mroute_add_del_handler (u8 is_add,
                        dpo_proto_t nh_proto,
                        u32 entry_flags,
                        fib_rpf_id_t rpf_id,
-                       u32 next_hop_sw_if_index, u32 itf_flags, u32 bier_imp)
+                       u32 next_hop_sw_if_index,
+                       ip46_address_t * nh, u32 itf_flags, u32 bier_imp)
 {
   stats_dslock_with_hint (1 /* release hint */ , 2 /* tag */ );
 
   fib_route_path_t path = {
     .frp_sw_if_index = next_hop_sw_if_index,
     .frp_proto = nh_proto,
+    .frp_addr = *nh,
   };
 
   if (is_local)
@@ -1351,6 +1257,7 @@ api_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp)
 {
   fib_protocol_t fproto;
   dpo_proto_t nh_proto;
+  ip46_address_t nh;
   u32 fib_index;
   int rv;
 
@@ -1375,6 +1282,8 @@ api_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp)
                   sizeof (pfx.fp_grp_addr.ip4));
       clib_memcpy (&pfx.fp_src_addr.ip4, mp->src_address,
                   sizeof (pfx.fp_src_addr.ip4));
+      memset (&nh.ip6, 0, sizeof (nh.ip6));
+      clib_memcpy (&nh.ip4, mp->nh_address, sizeof (nh.ip4));
     }
   else
     {
@@ -1382,6 +1291,7 @@ api_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp)
                   sizeof (pfx.fp_grp_addr.ip6));
       clib_memcpy (&pfx.fp_src_addr.ip6, mp->src_address,
                   sizeof (pfx.fp_src_addr.ip6));
+      clib_memcpy (&nh.ip6, mp->nh_address, sizeof (nh.ip6));
     }
 
   return (mroute_add_del_handler (mp->is_add,
@@ -1391,6 +1301,7 @@ api_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp)
                                  ntohl (mp->entry_flags),
                                  ntohl (mp->rpf_id),
                                  ntohl (mp->next_hop_sw_if_index),
+                                 &nh,
                                  ntohl (mp->itf_flags),
                                  ntohl (mp->bier_imp)));
 }
@@ -1413,8 +1324,8 @@ vl_api_ip_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp)
 
 static void
 send_ip_details (vpe_api_main_t * am,
-                unix_shared_memory_queue_t * q, u32 sw_if_index,
-                u8 is_ipv6, u32 context)
+                vl_api_registration_t * reg, u32 sw_if_index, u8 is_ipv6,
+                u32 context)
 {
   vl_api_ip_details_t *mp;
 
@@ -1426,12 +1337,12 @@ send_ip_details (vpe_api_main_t * am,
   mp->is_ipv6 = is_ipv6;
   mp->context = context;
 
-  vl_msg_api_send_shmem (q, (u8 *) & mp);
+  vl_api_send_msg (reg, (u8 *) mp);
 }
 
 static void
 send_ip_address_details (vpe_api_main_t * am,
-                        unix_shared_memory_queue_t * q,
+                        vl_api_registration_t * reg,
                         u8 * ip, u16 prefix_length,
                         u32 sw_if_index, u8 is_ipv6, u32 context)
 {
@@ -1455,14 +1366,14 @@ send_ip_address_details (vpe_api_main_t * am,
   mp->sw_if_index = htonl (sw_if_index);
   mp->is_ipv6 = is_ipv6;
 
-  vl_msg_api_send_shmem (q, (u8 *) & mp);
+  vl_api_send_msg (reg, (u8 *) mp);
 }
 
 static void
 vl_api_ip_address_dump_t_handler (vl_api_ip_address_dump_t * mp)
 {
   vpe_api_main_t *am = &vpe_api_main;
-  unix_shared_memory_queue_t *q;
+  vl_api_registration_t *reg;
   ip6_address_t *r6;
   ip4_address_t *r4;
   ip6_main_t *im6 = &ip6_main;
@@ -1477,8 +1388,8 @@ vl_api_ip_address_dump_t_handler (vl_api_ip_address_dump_t * mp)
 
   sw_if_index = ntohl (mp->sw_if_index);
 
-  q = vl_api_client_index_to_input_queue (mp->client_index);
-  if (q == 0)
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
     return;
 
   if (mp->is_ipv6)
@@ -1489,7 +1400,7 @@ vl_api_ip_address_dump_t_handler (vl_api_ip_address_dump_t * mp)
       ({
         r6 = ip_interface_address_get_address (lm6, ia);
         u16 prefix_length = ia->address_length;
-        send_ip_address_details(am, q, (u8*)r6, prefix_length,
+        send_ip_address_details(am, reg, (u8*)r6, prefix_length,
                                sw_if_index, 1, mp->context);
       }));
       /* *INDENT-ON* */
@@ -1502,7 +1413,7 @@ vl_api_ip_address_dump_t_handler (vl_api_ip_address_dump_t * mp)
       ({
         r4 = ip_interface_address_get_address (lm4, ia);
         u16 prefix_length = ia->address_length;
-        send_ip_address_details(am, q, (u8*)r4, prefix_length,
+        send_ip_address_details(am, reg, (u8*)r4, prefix_length,
                                sw_if_index, 0, mp->context);
       }));
       /* *INDENT-ON* */
@@ -1517,15 +1428,13 @@ vl_api_ip_dump_t_handler (vl_api_ip_dump_t * mp)
   vnet_main_t *vnm = vnet_get_main ();
   vlib_main_t *vm = vlib_get_main ();
   vnet_interface_main_t *im = &vnm->interface_main;
-  unix_shared_memory_queue_t *q;
+  vl_api_registration_t *reg;
   vnet_sw_interface_t *si, *sorted_sis;
   u32 sw_if_index = ~0;
 
-  q = vl_api_client_index_to_input_queue (mp->client_index);
-  if (q == 0)
-    {
-      return;
-    }
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
+    return;
 
   /* Gather interfaces. */
   sorted_sis = vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces));
@@ -1546,7 +1455,7 @@ vl_api_ip_dump_t_handler (vl_api_ip_dump_t * mp)
            continue;
          }
        sw_if_index = si->sw_if_index;
-       send_ip_details (am, q, sw_if_index, mp->is_ipv6, mp->context);
+       send_ip_details (am, reg, sw_if_index, mp->is_ipv6, mp->context);
       }
   }
 }
@@ -1664,7 +1573,7 @@ static void
 }
 
 static void
-send_ip6nd_proxy_details (unix_shared_memory_queue_t * q,
+send_ip6nd_proxy_details (vl_api_registration_t * reg,
                          u32 context,
                          const ip46_address_t * addr, u32 sw_if_index)
 {
@@ -1677,7 +1586,7 @@ send_ip6nd_proxy_details (unix_shared_memory_queue_t * q,
   mp->sw_if_index = htonl (sw_if_index);
   memcpy (mp->address, addr, 16);
 
-  vl_msg_api_send_shmem (q, (u8 *) & mp);
+  vl_api_send_msg (reg, (u8 *) mp);
 }
 
 typedef struct api_ip6nd_proxy_fib_table_walk_ctx_t_
@@ -1685,7 +1594,7 @@ typedef struct api_ip6nd_proxy_fib_table_walk_ctx_t_
   u32 *indices;
 } api_ip6nd_proxy_fib_table_walk_ctx_t;
 
-static int
+static fib_table_walk_rc_t
 api_ip6nd_proxy_fib_table_walk (fib_node_index_t fei, void *arg)
 {
   api_ip6nd_proxy_fib_table_walk_ctx_t *ctx = arg;
@@ -1695,7 +1604,7 @@ api_ip6nd_proxy_fib_table_walk (fib_node_index_t fei, void *arg)
       vec_add1 (ctx->indices, fei);
     }
 
-  return (1);
+  return (FIB_TABLE_WALK_CONTINUE);
 }
 
 static void
@@ -1708,13 +1617,11 @@ vl_api_ip6nd_proxy_dump_t_handler (vl_api_ip6nd_proxy_dump_t * mp)
   };
   fib_node_index_t *feip;
   fib_prefix_t pfx;
-  unix_shared_memory_queue_t *q;
+  vl_api_registration_t *reg;
 
-  q = vl_api_client_index_to_input_queue (mp->client_index);
-  if (q == 0)
-    {
-      return;
-    }
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
+    return;
 
   /* *INDENT-OFF* */
   pool_foreach (fib_table, im6->fibs,
@@ -1732,7 +1639,7 @@ vl_api_ip6nd_proxy_dump_t_handler (vl_api_ip6nd_proxy_dump_t * mp)
   {
     fib_entry_get_prefix (*feip, &pfx);
 
-    send_ip6nd_proxy_details (q,
+    send_ip6nd_proxy_details (reg,
                              mp->context,
                              &pfx.fp_addr,
                              fib_entry_get_resolving_interface (*feip));
@@ -1756,6 +1663,32 @@ vl_api_ip6nd_proxy_add_del_t_handler (vl_api_ip6nd_proxy_add_del_t * mp)
   REPLY_MACRO (VL_API_IP6ND_PROXY_ADD_DEL_REPLY);
 }
 
+static void
+  vl_api_ip6nd_send_router_solicitation_t_handler
+  (vl_api_ip6nd_send_router_solicitation_t * mp)
+{
+  vl_api_ip6nd_send_router_solicitation_reply_t *rmp;
+  icmp6_send_router_solicitation_params_t params;
+  vlib_main_t *vm = vlib_get_main ();
+  int rv = 0;
+
+  VALIDATE_SW_IF_INDEX (mp);
+
+  BAD_SW_IF_INDEX_LABEL;
+  REPLY_MACRO (VL_API_IP6ND_SEND_ROUTER_SOLICITATION_REPLY);
+
+  if (rv != 0)
+    return;
+
+  params.irt = ntohl (mp->irt);
+  params.mrt = ntohl (mp->mrt);
+  params.mrc = ntohl (mp->mrc);
+  params.mrd = ntohl (mp->mrd);
+
+  icmp6_send_router_solicitation (vm, ntohl (mp->sw_if_index), mp->stop,
+                                 &params);
+}
+
 static void
   vl_api_sw_interface_ip6_enable_disable_t_handler
   (vl_api_sw_interface_ip6_enable_disable_t * mp)
@@ -1823,7 +1756,7 @@ static void
 }
 
 void
-vl_mfib_signal_send_one (unix_shared_memory_queue_t * q,
+vl_mfib_signal_send_one (vl_api_registration_t * reg,
                         u32 context, const mfib_signal_t * mfs)
 {
   vl_api_mfib_signal_details_t *mp;
@@ -1872,21 +1805,19 @@ vl_mfib_signal_send_one (unix_shared_memory_queue_t * q,
       mp->ip_packet_len = 0;
     }
 
-  vl_msg_api_send_shmem (q, (u8 *) & mp);
+  vl_api_send_msg (reg, (u8 *) mp);
 }
 
 static void
 vl_api_mfib_signal_dump_t_handler (vl_api_mfib_signal_dump_t * mp)
 {
-  unix_shared_memory_queue_t *q;
+  vl_api_registration_t *reg;
 
-  q = vl_api_client_index_to_input_queue (mp->client_index);
-  if (q == 0)
-    {
-      return;
-    }
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
+    return;
 
-  while (q->cursize < q->maxsize && mfib_signal_send_one (q, mp->context))
+  while (vl_api_can_send_msg (reg) && mfib_signal_send_one (reg, mp->context))
     ;
 }
 
@@ -2106,7 +2037,7 @@ handle_ip4_arp_event (u32 pool_index)
   vlib_main_t *vm = vam->vlib_main;
   vl_api_ip4_arp_event_t *event;
   vl_api_ip4_arp_event_t *mp;
-  unix_shared_memory_queue_t *q;
+  vl_api_registration_t *reg;
 
   /* Client can cancel, die, etc. */
   if (pool_is_free_index (vam->arp_events, pool_index))
@@ -2114,8 +2045,8 @@ handle_ip4_arp_event (u32 pool_index)
 
   event = pool_elt_at_index (vam->arp_events, pool_index);
 
-  q = vl_api_client_index_to_input_queue (event->client_index);
-  if (!q)
+  reg = vl_api_client_index_to_registration (event->client_index);
+  if (!reg)
     {
       (void) vnet_add_del_ip4_arp_change_event
        (vnm, arp_change_delete_callback,
@@ -2125,11 +2056,11 @@ handle_ip4_arp_event (u32 pool_index)
       return;
     }
 
-  if (q->cursize < q->maxsize)
+  if (vl_api_can_send_msg (reg))
     {
       mp = vl_msg_api_alloc (sizeof (*mp));
       clib_memcpy (mp, event, sizeof (*mp));
-      vl_msg_api_send_shmem (q, (u8 *) & mp);
+      vl_api_send_msg (reg, (u8 *) mp);
     }
   else
     {
@@ -2155,7 +2086,7 @@ handle_ip6_nd_event (u32 pool_index)
   vlib_main_t *vm = vam->vlib_main;
   vl_api_ip6_nd_event_t *event;
   vl_api_ip6_nd_event_t *mp;
-  unix_shared_memory_queue_t *q;
+  vl_api_registration_t *reg;
 
   /* Client can cancel, die, etc. */
   if (pool_is_free_index (vam->nd_events, pool_index))
@@ -2163,8 +2094,8 @@ handle_ip6_nd_event (u32 pool_index)
 
   event = pool_elt_at_index (vam->nd_events, pool_index);
 
-  q = vl_api_client_index_to_input_queue (event->client_index);
-  if (!q)
+  reg = vl_api_client_index_to_registration (event->client_index);
+  if (!reg)
     {
       (void) vnet_add_del_ip6_nd_change_event
        (vnm, nd_change_delete_callback,
@@ -2174,11 +2105,11 @@ handle_ip6_nd_event (u32 pool_index)
       return;
     }
 
-  if (q->cursize < q->maxsize)
+  if (vl_api_can_send_msg (reg))
     {
       mp = vl_msg_api_alloc (sizeof (*mp));
       clib_memcpy (mp, event, sizeof (*mp));
-      vl_msg_api_send_shmem (q, (u8 *) & mp);
+      vl_api_send_msg (reg, (u8 *) mp);
     }
   else
     {
@@ -2289,7 +2220,7 @@ nd_change_delete_callback (u32 pool_index, u8 * notused)
 static vlib_node_registration_t wc_arp_process_node;
 
 enum
-{ WC_ARP_REPORT, WC_ND_REPORT };
+{ WC_ARP_REPORT, WC_ND_REPORT, RA_REPORT, REPORT_MAX };
 
 static uword
 wc_arp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
@@ -2330,9 +2261,10 @@ wc_arp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
             /* *INDENT-OFF* */
             pool_foreach(reg, vpe_api_main.wc_ip4_arp_events_registrations,
             ({
-             unix_shared_memory_queue_t *q;
-              q = vl_api_client_index_to_input_queue (reg->client_index);
-             if (q && q->cursize < q->maxsize)
+             vl_api_registration_t *vl_reg;
+              vl_reg = vl_api_client_index_to_registration (reg->client_index);
+              ASSERT (vl_reg != NULL);
+             if (reg && vl_api_can_send_msg (vl_reg))
                {
                  vl_api_ip4_arp_event_t * event = vl_msg_api_alloc (sizeof *event);
                  memset (event, 0, sizeof *event);
@@ -2343,7 +2275,7 @@ wc_arp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
                  event->address = arp_events[i].ip4;
                  event->sw_if_index = htonl(arp_events[i].sw_if_index);
                  memcpy(event->new_mac, arp_events[i].mac, sizeof event->new_mac);
-                 vl_msg_api_send_shmem (q, (u8 *) &event);
+                 vl_api_send_msg (vl_reg, (u8 *) event);
                }
             }));
             /* *INDENT-ON* */
@@ -2369,9 +2301,9 @@ wc_arp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
               /* *INDENT-OFF* */
               pool_foreach(reg, vpe_api_main.wc_ip6_nd_events_registrations,
               ({
-               unix_shared_memory_queue_t *q;
-                q = vl_api_client_index_to_input_queue (reg->client_index);
-               if (q && q->cursize < q->maxsize)
+               vl_api_registration_t *vl_reg;
+                vl_reg = vl_api_client_index_to_registration (reg->client_index);
+               if (vl_reg && vl_api_can_send_msg (vl_reg))
                  {
                    vl_api_ip6_nd_event_t * event = vl_msg_api_alloc (sizeof *event);
                    memset (event, 0, sizeof *event);
@@ -2382,12 +2314,80 @@ wc_arp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
                    memcpy(event->address, nd_events[i].ip6.as_u8, sizeof event->address);
                    event->sw_if_index = htonl(nd_events[i].sw_if_index);
                    memcpy(event->new_mac, nd_events[i].mac, sizeof event->new_mac);
-                   vl_msg_api_send_shmem (q, (u8 *) &event);
+                   vl_api_send_msg (vl_reg, (u8 *) event);
                  }
               }));
             /* *INDENT-ON* */
            }
        }
+      else if (event_type == RA_REPORT)
+       {
+         ra_report_t *ra_events = event_data;
+         for (i = 0; i < vec_len (ra_events); i++)
+           {
+             vpe_client_registration_t *reg;
+              /* *INDENT-OFF* */
+              pool_foreach(reg, vpe_api_main.ip6_ra_events_registrations,
+              ({
+               vl_api_registration_t *vl_reg;
+               vl_reg =
+                 vl_api_client_index_to_registration (reg->client_index);
+               if (vl_reg && vl_api_can_send_msg (vl_reg))
+                 {
+                   u32 event_size =
+                     sizeof (vl_api_ip6_ra_event_t) +
+                     vec_len (ra_events[i].prefixes) *
+                     sizeof (vl_api_ip6_ra_prefix_info_t);
+                   vl_api_ip6_ra_event_t *event =
+                     vl_msg_api_alloc (event_size);
+                   memset (event, 0, event_size);
+                   event->_vl_msg_id = htons (VL_API_IP6_RA_EVENT);
+                   event->client_index = reg->client_index;
+                   event->pid = reg->client_pid;
+
+                   event->sw_if_index = clib_host_to_net_u32 (ra_events[i].sw_if_index);
+
+                   memcpy (event->router_address, ra_events[i].router_address, 16);
+
+                   event->current_hop_limit = ra_events[i].current_hop_limit;
+                   event->flags = ra_events[i].flags;
+                   event->router_lifetime_in_sec =
+                     clib_host_to_net_u16 (ra_events
+                                           [i].router_lifetime_in_sec);
+                   event->neighbor_reachable_time_in_msec =
+                     clib_host_to_net_u32 (ra_events
+                                           [i].neighbor_reachable_time_in_msec);
+                   event->time_in_msec_between_retransmitted_neighbor_solicitations
+                     =
+                     clib_host_to_net_u32 (ra_events
+                                           [i].time_in_msec_between_retransmitted_neighbor_solicitations);
+
+                   event->n_prefixes =
+                     clib_host_to_net_u32 (vec_len (ra_events[i].prefixes));
+                   vl_api_ip6_ra_prefix_info_t *prefix =
+                     (typeof (prefix)) event->prefixes;
+                   u32 j;
+                   for (j = 0; j < vec_len (ra_events[i].prefixes); j++)
+                     {
+                       ra_report_prefix_info_t *info =
+                         &ra_events[i].prefixes[j];
+                       memcpy (prefix->dst_address, info->dst_address.as_u8,
+                               16);
+                       prefix->dst_address_length = info->dst_address_length;
+                       prefix->flags = info->flags;
+                       prefix->valid_time =
+                         clib_host_to_net_u32 (info->valid_time);
+                       prefix->preferred_time =
+                         clib_host_to_net_u32 (info->preferred_time);
+                       prefix++;
+                     }
+
+                   vl_api_send_msg (vl_reg, (u8 *) event);
+                 }
+              }));
+            /* *INDENT-ON* */
+           }
+       }
       vlib_process_put_event_data (vm, event_data);
     }
 
@@ -2453,7 +2453,7 @@ vl_api_want_ip4_arp_events_t_handler (vl_api_want_ip4_arp_events_t * mp)
              hash_unset (am->wc_ip4_arp_events_registration_hash,
                          mp->client_index);
              if (pool_elts (am->wc_ip4_arp_events_registrations) == 0)
-               wc_arp_set_publisher_node (~0, WC_ARP_REPORT);
+               wc_arp_set_publisher_node (~0, REPORT_MAX);
              goto reply;
            }
        }
@@ -2538,7 +2538,7 @@ vl_api_want_ip6_nd_events_t_handler (vl_api_want_ip6_nd_events_t * mp)
              hash_unset (am->wc_ip6_nd_events_registration_hash,
                          mp->client_index);
              if (pool_elts (am->wc_ip6_nd_events_registrations) == 0)
-               wc_nd_set_publisher_node (~0, 2);
+               wc_nd_set_publisher_node (~0, REPORT_MAX);
              goto reply;
            }
        }
@@ -2592,6 +2592,50 @@ reply:
   REPLY_MACRO (VL_API_WANT_IP6_ND_EVENTS_REPLY);
 }
 
+static void
+vl_api_want_ip6_ra_events_t_handler (vl_api_want_ip6_ra_events_t * mp)
+{
+  vpe_api_main_t *am = &vpe_api_main;
+  vl_api_want_ip6_ra_events_reply_t *rmp;
+  int rv = 0;
+
+  uword *p = hash_get (am->ip6_ra_events_registration_hash, mp->client_index);
+  vpe_client_registration_t *rp;
+  if (p)
+    {
+      if (mp->enable_disable)
+       {
+         clib_warning ("pid %d: already enabled...", ntohl (mp->pid));
+         rv = VNET_API_ERROR_INVALID_REGISTRATION;
+         goto reply;
+       }
+      else
+       {
+         rp = pool_elt_at_index (am->ip6_ra_events_registrations, p[0]);
+         pool_put (am->ip6_ra_events_registrations, rp);
+         hash_unset (am->ip6_ra_events_registration_hash, mp->client_index);
+         if (pool_elts (am->ip6_ra_events_registrations) == 0)
+           ra_set_publisher_node (~0, REPORT_MAX);
+         goto reply;
+       }
+    }
+  if (mp->enable_disable == 0)
+    {
+      clib_warning ("pid %d: already disabled...", ntohl (mp->pid));
+      rv = VNET_API_ERROR_INVALID_REGISTRATION;
+      goto reply;
+    }
+  pool_get (am->ip6_ra_events_registrations, rp);
+  rp->client_index = mp->client_index;
+  rp->client_pid = ntohl (mp->pid);
+  hash_set (am->ip6_ra_events_registration_hash, rp->client_index,
+           rp - am->ip6_ra_events_registrations);
+  ra_set_publisher_node (wc_arp_process_node.index, RA_REPORT);
+
+reply:
+  REPLY_MACRO (VL_API_WANT_IP6_RA_EVENTS_REPLY);
+}
+
 static void
 vl_api_proxy_arp_add_del_t_handler (vl_api_proxy_arp_add_del_t * mp)
 {
@@ -2599,13 +2643,12 @@ vl_api_proxy_arp_add_del_t_handler (vl_api_proxy_arp_add_del_t * mp)
   u32 fib_index;
   int rv;
   ip4_main_t *im = &ip4_main;
-  stats_main_t *sm = &stats_main;
   int vnet_proxy_arp_add_del (ip4_address_t * lo_addr,
                              ip4_address_t * hi_addr,
                              u32 fib_index, int is_del);
   uword *p;
 
-  dslock (sm, 1 /* release hint */ , 6 /* tag */ );
+  stats_dslock_with_hint (1 /* release hint */ , 6 /* tag */ );
 
   p = hash_get (im->fib_index_by_table_id, ntohl (mp->vrf_id));
 
@@ -2622,7 +2665,7 @@ vl_api_proxy_arp_add_del_t_handler (vl_api_proxy_arp_add_del_t * mp)
                               fib_index, mp->is_add == 0);
 
 out:
-  dsunlock (sm);
+  stats_dsunlock ();
   REPLY_MACRO (VL_API_PROXY_ARP_ADD_DEL_REPLY);
 }
 
@@ -2651,6 +2694,55 @@ static void
   REPLY_MACRO (VL_API_PROXY_ARP_INTFC_ENABLE_DISABLE_REPLY);
 }
 
+static void
+vl_api_ip_probe_neighbor_t_handler (vl_api_ip_probe_neighbor_t * mp)
+{
+  int rv = 0;
+  vlib_main_t *vm = vlib_get_main ();
+  vl_api_ip_probe_neighbor_reply_t *rmp;
+  clib_error_t *error;
+
+  VALIDATE_SW_IF_INDEX (mp);
+
+  u32 sw_if_index = ntohl (mp->sw_if_index);
+
+  if (mp->is_ipv6)
+    error = ip6_probe_neighbor (vm, (ip6_address_t *) mp->dst_address,
+                               sw_if_index);
+  else
+    error = ip4_probe_neighbor (vm, (ip4_address_t *) mp->dst_address,
+                               sw_if_index);
+
+  if (error)
+    {
+      clib_error_report (error);
+      rv = clib_error_get_code (error);
+    }
+
+  BAD_SW_IF_INDEX_LABEL;
+
+  REPLY_MACRO (VL_API_PROXY_ARP_INTFC_ENABLE_DISABLE_REPLY);
+}
+
+static void
+  vl_api_ip_scan_neighbor_enable_disable_t_handler
+  (vl_api_ip_scan_neighbor_enable_disable_t * mp)
+{
+  int rv = 0;
+  vl_api_ip_scan_neighbor_enable_disable_reply_t *rmp;
+  ip_neighbor_scan_arg_t arg;
+
+  arg.mode = mp->mode;
+  arg.scan_interval = mp->scan_interval;
+  arg.max_proc_time = mp->max_proc_time;
+  arg.max_update = mp->max_update;
+  arg.scan_int_delay = mp->scan_int_delay;
+  arg.stale_threshold = mp->stale_threshold;
+  ip_neighbor_scan_enable_disable (&arg);
+
+  REPLY_MACRO (VL_API_IP_SCAN_NEIGHBOR_ENABLE_DISABLE_REPLY);
+}
+
 static int
 ip4_reset_fib_t_handler (vl_api_reset_fib_t * mp)
 {
@@ -2658,7 +2750,6 @@ ip4_reset_fib_t_handler (vl_api_reset_fib_t * mp)
   vnet_interface_main_t *im = &vnm->interface_main;
   ip4_main_t *im4 = &ip4_main;
   static u32 *sw_if_indices_to_shut;
-  stats_main_t *sm = &stats_main;
   fib_table_t *fib_table;
   ip4_fib_t *fib;
   u32 sw_if_index;
@@ -2666,7 +2757,7 @@ ip4_reset_fib_t_handler (vl_api_reset_fib_t * mp)
   int rv = VNET_API_ERROR_NO_SUCH_FIB;
   u32 target_fib_id = ntohl (mp->vrf_id);
 
-  dslock (sm, 1 /* release hint */ , 8 /* tag */ );
+  stats_dslock_with_hint (1 /* release hint */ , 8 /* tag */ );
 
   /* *INDENT-OFF* */
   pool_foreach (fib_table, im4->fibs,
@@ -2715,7 +2806,7 @@ ip4_reset_fib_t_handler (vl_api_reset_fib_t * mp)
     })); /* pool_foreach (fib) */
     /* *INDENT-ON* */
 
-  dsunlock (sm);
+  stats_dsunlock ();
   return rv;
 }
 
@@ -2725,7 +2816,6 @@ ip6_reset_fib_t_handler (vl_api_reset_fib_t * mp)
   vnet_main_t *vnm = vnet_get_main ();
   vnet_interface_main_t *im = &vnm->interface_main;
   ip6_main_t *im6 = &ip6_main;
-  stats_main_t *sm = &stats_main;
   static u32 *sw_if_indices_to_shut;
   fib_table_t *fib_table;
   ip6_fib_t *fib;
@@ -2734,7 +2824,7 @@ ip6_reset_fib_t_handler (vl_api_reset_fib_t * mp)
   int rv = VNET_API_ERROR_NO_SUCH_FIB;
   u32 target_fib_id = ntohl (mp->vrf_id);
 
-  dslock (sm, 1 /* release hint */ , 9 /* tag */ );
+  stats_dslock_with_hint (1 /* release hint */ , 9 /* tag */ );
 
   /* *INDENT-OFF* */
   pool_foreach (fib_table, im6->fibs,
@@ -2774,7 +2864,7 @@ ip6_reset_fib_t_handler (vl_api_reset_fib_t * mp)
   })); /* pool_foreach (fib) */
   /* *INDENT-ON* */
 
-  dsunlock (sm);
+  stats_dsunlock ();
   return rv;
 }
 
@@ -2820,6 +2910,78 @@ vl_api_set_arp_neighbor_limit_t_handler (vl_api_set_arp_neighbor_limit_t * mp)
   REPLY_MACRO (VL_API_SET_ARP_NEIGHBOR_LIMIT_REPLY);
 }
 
+void
+vl_api_ip_reassembly_set_t_handler (vl_api_ip_reassembly_set_t * mp)
+{
+  vl_api_ip_reassembly_set_reply_t *rmp;
+  int rv = 0;
+  if (mp->is_ip6)
+    {
+      rv = ip6_reass_set (clib_net_to_host_u32 (mp->timeout_ms),
+                         clib_net_to_host_u32 (mp->max_reassemblies),
+                         clib_net_to_host_u32 (mp->expire_walk_interval_ms));
+    }
+  else
+    {
+      rv = ip4_reass_set (clib_net_to_host_u32 (mp->timeout_ms),
+                         clib_net_to_host_u32 (mp->max_reassemblies),
+                         clib_net_to_host_u32 (mp->expire_walk_interval_ms));
+    }
+
+  REPLY_MACRO (VL_API_IP_REASSEMBLY_SET_REPLY);
+}
+
+void
+vl_api_ip_reassembly_get_t_handler (vl_api_ip_reassembly_get_t * mp)
+{
+  unix_shared_memory_queue_t *q;
+
+  q = vl_api_client_index_to_input_queue (mp->client_index);
+
+  if (q == 0)
+    return;
+
+  vl_api_ip_reassembly_get_reply_t *rmp = vl_msg_api_alloc (sizeof (*rmp));
+  memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id = ntohs (VL_API_IP_REASSEMBLY_GET_REPLY);
+  rmp->context = mp->context;
+  rmp->retval = 0;
+  if (mp->is_ip6)
+    {
+      rmp->is_ip6 = 1;
+      ip6_reass_get (&rmp->timeout_ms, &rmp->max_reassemblies,
+                    &rmp->expire_walk_interval_ms);
+    }
+  else
+    {
+      rmp->is_ip6 = 0;
+      ip4_reass_get (&rmp->timeout_ms, &rmp->max_reassemblies,
+                    &rmp->expire_walk_interval_ms);
+    }
+  rmp->timeout_ms = clib_host_to_net_u32 (rmp->timeout_ms);
+  rmp->max_reassemblies = clib_host_to_net_u32 (rmp->max_reassemblies);
+  rmp->expire_walk_interval_ms =
+    clib_host_to_net_u32 (rmp->expire_walk_interval_ms);
+  vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+void
+  vl_api_ip_reassembly_enable_disable_t_handler
+  (vl_api_ip_reassembly_enable_disable_t * mp)
+{
+  vl_api_ip_reassembly_enable_disable_reply_t *rmp;
+  int rv = 0;
+  rv = ip4_reass_enable_disable (clib_net_to_host_u32 (mp->sw_if_index),
+                                mp->enable_ip4);
+  if (0 == rv)
+    {
+      rv = ip6_reass_enable_disable (clib_net_to_host_u32 (mp->sw_if_index),
+                                    mp->enable_ip6);
+    }
+
+  REPLY_MACRO (VL_API_IP_REASSEMBLY_SET_REPLY);
+}
+
 #define vl_msg_name_crc_list
 #include <vnet/ip/ip.api.h>
 #undef vl_msg_name_crc_list