VPP-355: add PBB (802.1ah) tag rewrite
[vpp.git] / vpp / vpp-api / api.c
index 93401ed..2fdf526 100644 (file)
 #include <vnet/l2/l2_bd.h>
 #include <vnet/l2tp/l2tp.h>
 #include <vnet/ip/ip.h>
+#include <vnet/ip/ip6.h>
 #include <vnet/unix/tuntap.h>
 #include <vnet/unix/tapcli.h>
-#include <vnet/mpls-gre/mpls.h>
+#include <vnet/mpls/mpls.h>
 #include <vnet/dhcp/proxy.h>
 #include <vnet/dhcp/client.h>
 #if IPV6SR > 0
@@ -73,6 +74,8 @@
 #include <vnet/l2/l2_vtr.h>
 #include <vnet/vxlan-gpe/vxlan_gpe.h>
 #include <vnet/lisp-gpe/lisp_gpe.h>
+#include <vnet/lisp-gpe/lisp_gpe_fwd_entry.h>
+#include <vnet/lisp-gpe/lisp_gpe_tenant.h>
 #include <vnet/lisp-cp/control.h>
 #include <vnet/map/map.h>
 #include <vnet/cop/cop.h>
@@ -83,6 +86,7 @@
 #include <vnet/devices/netmap/netmap.h>
 #include <vnet/flow/flow_report.h>
 #include <vnet/ipsec-gre/ipsec_gre.h>
+#include <vnet/flow/flow_report_classify.h>
 
 #undef BIHASH_TYPE
 #undef __included_bihash_template_h__
@@ -92,9 +96,7 @@
 #include <vnet/ipsec/ipsec.h>
 #include <vnet/ipsec/ikev2.h>
 #endif /* IPSEC */
-#if DPDK > 0
 #include <vnet/devices/virtio/vhost-user.h>
-#endif
 
 #include <stats/stats.h>
 #include <oam/oam.h>
 #include <vnet/l2/l2_bd.h>
 #include <vpp-api/vpe_msg_enum.h>
 
+#include <vnet/fib/ip6_fib.h>
+#include <vnet/fib/ip4_fib.h>
+#include <vnet/dpo/drop_dpo.h>
+#include <vnet/dpo/receive_dpo.h>
+#include <vnet/dpo/lookup_dpo.h>
+#include <vnet/dpo/classify_dpo.h>
+
 #define f64_endian(a)
 #define f64_print(a,b)
 
@@ -156,6 +165,22 @@ do {                                                            \
     vl_msg_api_send_shmem (q, (u8 *)&rmp);                      \
 } while(0);
 
+#define REPLY_MACRO3(t, n, body)                               \
+do {                                                            \
+    unix_shared_memory_queue_t * q;                             \
+    rv = vl_msg_api_pd_handler (mp, rv);                        \
+    q = vl_api_client_index_to_input_queue (mp->client_index);  \
+    if (!q)                                                     \
+        return;                                                 \
+                                                                \
+    rmp = vl_msg_api_alloc (sizeof (*rmp) + n);                 \
+    rmp->_vl_msg_id = ntohs((t));                               \
+    rmp->context = mp->context;                                 \
+    rmp->retval = ntohl(rv);                                    \
+    do {body;} while (0);                                       \
+    vl_msg_api_send_shmem (q, (u8 *)&rmp);                      \
+} while(0);
+
 #if (1 || CLIB_DEBUG > 0)      /* "trust, but verify" */
 
 #define VALIDATE_SW_IF_INDEX(mp)                               \
@@ -228,9 +253,13 @@ _(IP_ADD_DEL_ROUTE, ip_add_del_route)                                   \
 _(IS_ADDRESS_REACHABLE, is_address_reachable)                           \
 _(SW_INTERFACE_ADD_DEL_ADDRESS, sw_interface_add_del_address)           \
 _(SW_INTERFACE_SET_TABLE, sw_interface_set_table)                       \
+_(SW_INTERFACE_SET_MPLS_ENABLE, sw_interface_set_mpls_enable)           \
 _(SW_INTERFACE_SET_VPATH, sw_interface_set_vpath)                       \
 _(SW_INTERFACE_SET_L2_XCONNECT, sw_interface_set_l2_xconnect)           \
 _(SW_INTERFACE_SET_L2_BRIDGE, sw_interface_set_l2_bridge)               \
+_(SW_INTERFACE_SET_DPDK_HQOS_PIPE, sw_interface_set_dpdk_hqos_pipe)     \
+_(SW_INTERFACE_SET_DPDK_HQOS_SUBPORT, sw_interface_set_dpdk_hqos_subport) \
+_(SW_INTERFACE_SET_DPDK_HQOS_TCTBL, sw_interface_set_dpdk_hqos_tctbl)   \
 _(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del)                         \
 _(BRIDGE_DOMAIN_DUMP, bridge_domain_dump)                               \
 _(BRIDGE_DOMAIN_DETAILS, bridge_domain_details)                         \
@@ -267,8 +296,8 @@ _(SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS,                          \
 _(SW_INTERFACE_SET_UNNUMBERED, sw_interface_set_unnumbered)            \
 _(CREATE_LOOPBACK, create_loopback)                                    \
 _(CONTROL_PING, control_ping)                                           \
-_(NOPRINT_CONTROL_PING, noprint_control_ping)                           \
 _(CLI_REQUEST, cli_request)                                             \
+_(CLI_INBAND, cli_inband)                                              \
 _(SET_ARP_NEIGHBOR_LIMIT, set_arp_neighbor_limit)                      \
 _(L2_PATCH_ADD_DEL, l2_patch_add_del)                                  \
 _(CLASSIFY_ADD_DEL_TABLE, classify_add_del_table)                      \
@@ -303,6 +332,7 @@ _(VXLAN_GPE_ADD_DEL_TUNNEL, vxlan_gpe_add_del_tunnel)                   \
 _(VXLAN_GPE_TUNNEL_DUMP, vxlan_gpe_tunnel_dump)                         \
 _(INTERFACE_NAME_RENUMBER, interface_name_renumber)                    \
 _(WANT_IP4_ARP_EVENTS, want_ip4_arp_events)                             \
+_(WANT_IP6_ND_EVENTS, want_ip6_nd_events)                               \
 _(INPUT_ACL_SET_INTERFACE, input_acl_set_interface)                     \
 _(IPSEC_SPD_ADD_DEL, ipsec_spd_add_del)                                 \
 _(IPSEC_INTERFACE_ADD_DEL_SPD, ipsec_interface_add_del_spd)             \
@@ -326,9 +356,8 @@ _(COP_INTERFACE_ENABLE_DISABLE, cop_interface_enable_disable)               \
 _(COP_WHITELIST_ENABLE_DISABLE, cop_whitelist_enable_disable)          \
 _(GET_NODE_GRAPH, get_node_graph)                                       \
 _(SW_INTERFACE_CLEAR_STATS, sw_interface_clear_stats)                   \
-_(TRACE_PROFILE_ADD, trace_profile_add)                                 \
-_(TRACE_PROFILE_APPLY, trace_profile_apply)                             \
-_(TRACE_PROFILE_DEL, trace_profile_del)                                 \
+_(IOAM_ENABLE, ioam_enable)                                 \
+_(IOAM_DISABLE, ioam_disable)                                 \
 _(LISP_ADD_DEL_LOCATOR_SET, lisp_add_del_locator_set)                   \
 _(LISP_ADD_DEL_LOCATOR, lisp_add_del_locator)                           \
 _(LISP_ADD_DEL_LOCAL_EID, lisp_add_del_local_eid)                       \
@@ -340,6 +369,7 @@ _(LISP_GPE_ADD_DEL_IFACE, lisp_gpe_add_del_iface)                       \
 _(LISP_ADD_DEL_REMOTE_MAPPING, lisp_add_del_remote_mapping)             \
 _(LISP_ADD_DEL_ADJACENCY, lisp_add_del_adjacency)                       \
 _(LISP_PITR_SET_LOCATOR_SET, lisp_pitr_set_locator_set)                 \
+_(LISP_MAP_REQUEST_MODE, lisp_map_request_mode)                         \
 _(LISP_EID_TABLE_ADD_DEL_MAP, lisp_eid_table_add_del_map)               \
 _(LISP_LOCATOR_SET_DUMP, lisp_locator_set_dump)                         \
 _(LISP_LOCATOR_DUMP, lisp_locator_dump)                                 \
@@ -347,11 +377,13 @@ _(LISP_EID_TABLE_DUMP, lisp_eid_table_dump)                             \
 _(LISP_GPE_TUNNEL_DUMP, lisp_gpe_tunnel_dump)                           \
 _(LISP_MAP_RESOLVER_DUMP, lisp_map_resolver_dump)                       \
 _(LISP_EID_TABLE_MAP_DUMP, lisp_eid_table_map_dump)                     \
+_(LISP_EID_TABLE_VNI_DUMP, lisp_eid_table_vni_dump)                     \
 _(SHOW_LISP_STATUS, show_lisp_status)                                   \
 _(LISP_ADD_DEL_MAP_REQUEST_ITR_RLOCS,                                   \
   lisp_add_del_map_request_itr_rlocs)                                   \
 _(LISP_GET_MAP_REQUEST_ITR_RLOCS, lisp_get_map_request_itr_rlocs)       \
 _(SHOW_LISP_PITR, show_lisp_pitr)                                       \
+_(SHOW_LISP_MAP_REQUEST_MODE, show_lisp_map_request_mode)               \
 _(SR_MULTICAST_MAP_ADD_DEL, sr_multicast_map_add_del)                   \
 _(AF_PACKET_CREATE, af_packet_create)                                   \
 _(AF_PACKET_DELETE, af_packet_delete)                                   \
@@ -374,8 +406,12 @@ _(CLASSIFY_TABLE_BY_INTERFACE, classify_table_by_interface)             \
 _(CLASSIFY_TABLE_INFO,classify_table_info)                              \
 _(CLASSIFY_SESSION_DUMP,classify_session_dump)                          \
 _(CLASSIFY_SESSION_DETAILS,classify_session_details)                    \
-_(IPFIX_ENABLE,ipfix_enable)                                            \
-_(IPFIX_DUMP,ipfix_dump)                                                \
+_(SET_IPFIX_EXPORTER, set_ipfix_exporter)                               \
+_(IPFIX_EXPORTER_DUMP, ipfix_exporter_dump)                             \
+_(SET_IPFIX_CLASSIFY_STREAM, set_ipfix_classify_stream)                 \
+_(IPFIX_CLASSIFY_STREAM_DUMP, ipfix_classify_stream_dump)               \
+_(IPFIX_CLASSIFY_TABLE_ADD_DEL, ipfix_classify_table_add_del)           \
+_(IPFIX_CLASSIFY_TABLE_DUMP, ipfix_classify_table_dump)                 \
 _(GET_NEXT_INDEX, get_next_index)                                       \
 _(PG_CREATE_INTERFACE, pg_create_interface)                             \
 _(PG_CAPTURE, pg_capture)                                               \
@@ -385,7 +421,9 @@ _(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)                     \
 _(IPSEC_GRE_ADD_DEL_TUNNEL, ipsec_gre_add_del_tunnel)                   \
-_(IPSEC_GRE_TUNNEL_DUMP, ipsec_gre_tunnel_dump)
+_(IPSEC_GRE_TUNNEL_DUMP, ipsec_gre_tunnel_dump)                         \
+_(DELETE_SUBIF, delete_subif)                                           \
+_(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite)
 
 #define QUOTE_(x) #x
 #define QUOTE(x) QUOTE_(x)
@@ -425,12 +463,15 @@ typedef struct
     /* notifications happen really early in the game */
   u8 link_state_process_up;
 
-  /* ip4 pending route adds */
+  /* ip4 and ip6 pending route adds */
   pending_route_t *pending_routes;
 
   /* ip4 arp event registration pool */
   vl_api_ip4_arp_event_t *arp_events;
 
+  /* ip6 nd event registration pool */
+  vl_api_ip6_nd_event_t *nd_events;
+
   /* convenience */
   vlib_main_t *vlib_main;
   vnet_main_t *vnet_main;
@@ -447,6 +488,7 @@ static void send_sw_interface_flags_deleted (vpe_api_main_t * am,
                                             u32 sw_if_index);
 
 static int arp_change_delete_callback (u32 pool_index, u8 * notused);
+static int nd_change_delete_callback (u32 pool_index, u8 * notused);
 
 
 /* Clean up all registrations belonging to the indicated client */
@@ -629,17 +671,25 @@ reply:                                                                  \
     REPLY_MACRO (VL_API_WANT_##UCA##_REPLY);                            \
 }
 
+/* *INDENT-OFF* */
 pub_sub_handler (interface_events, INTERFACE_EVENTS)
 pub_sub_handler (oam_events, OAM_EVENTS)
+/* *INDENT-ON* */
+
 #define RESOLUTION_EVENT 1
 #define RESOLUTION_PENDING_EVENT 2
 #define IP4_ARP_EVENT 3
-     static int 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);
-     static int mpls_ethernet_add_del_tunnel_2_t_handler
-       (vl_api_mpls_ethernet_add_del_tunnel_2_t * mp);
+#define IP6_ND_EVENT 4
+
+static int 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);
+
+static int mpls_ethernet_add_del_tunnel_2_t_handler
+  (vl_api_mpls_ethernet_add_del_tunnel_2_t * mp);
 
-     void handle_ip4_arp_event (u32 pool_index)
+void
+handle_ip4_arp_event (u32 pool_index)
 {
   vpe_api_main_t *vam = &vpe_api_main;
   vnet_main_t *vnm = vam->vnet_main;
@@ -687,6 +737,55 @@ pub_sub_handler (oam_events, OAM_EVENTS)
     }
 }
 
+void
+handle_ip6_nd_event (u32 pool_index)
+{
+  vpe_api_main_t *vam = &vpe_api_main;
+  vnet_main_t *vnm = vam->vnet_main;
+  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;
+
+  /* Client can cancel, die, etc. */
+  if (pool_is_free_index (vam->nd_events, pool_index))
+    return;
+
+  event = pool_elt_at_index (vam->nd_events, pool_index);
+
+  q = vl_api_client_index_to_input_queue (event->client_index);
+  if (!q)
+    {
+      (void) vnet_add_del_ip6_nd_change_event
+       (vnm, nd_change_delete_callback,
+        event->pid, &event->address,
+        vpe_resolver_process_node.index, IP6_ND_EVENT,
+        ~0 /* pool index, notused */ , 0 /* is_add */ );
+      return;
+    }
+
+  if (q->cursize < q->maxsize)
+    {
+      mp = vl_msg_api_alloc (sizeof (*mp));
+      clib_memcpy (mp, event, sizeof (*mp));
+      vl_msg_api_send_shmem (q, (u8 *) & mp);
+    }
+  else
+    {
+      static f64 last_time;
+      /*
+       * Throttle syslog msgs.
+       * It's pretty tempting to just revoke the registration...
+       */
+      if (vlib_time_now (vm) > last_time + 10.0)
+       {
+         clib_warning ("ip6 nd event for %U to pid %d: queue stuffed!",
+                       format_ip6_address, &event->address, event->pid);
+         last_time = vlib_time_now (vm);
+       }
+    }
+}
+
 static uword
 resolver_process (vlib_main_t * vm,
                  vlib_node_runtime_t * rt, vlib_frame_t * f)
@@ -774,6 +873,11 @@ resolver_process (vlib_main_t * vm,
            handle_ip4_arp_event (event_data[i]);
          break;
 
+       case IP6_ND_EVENT:
+         for (i = 0; i < vec_len (event_data); i++)
+           handle_ip6_nd_event (event_data[i]);
+         break;
+
        case ~0:                /* timeout, retry pending resolutions */
           /* *INDENT-OFF* */
           pool_foreach (pr, vam->pending_routes,
@@ -891,251 +995,165 @@ VLIB_REGISTER_NODE (vpe_resolver_process_node,static) = {
 /* *INDENT-ON* */
 
 static int
-ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
+ip_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp,
+                           u32 fib_index,
+                           const fib_prefix_t * prefix,
+                           const ip46_address_t * next_hop,
+                           u32 next_hop_sw_if_index,
+                           u32 next_hop_fib_index, u32 next_hop_weight)
 {
-  ip4_main_t *im = &ip4_main;
-  ip_lookup_main_t *lm = &im->lookup_main;
   vnet_classify_main_t *cm = &vnet_classify_main;
+  fib_protocol_t proto = prefix->fp_proto;
   stats_main_t *sm = &stats_main;
-  ip4_add_del_route_args_t a;
-  ip4_address_t next_hop_address;
-  u32 fib_index;
-  vpe_api_main_t *vam = &vpe_api_main;
-  vnet_main_t *vnm = vam->vnet_main;
-  vlib_main_t *vm = vlib_get_main ();
-  pending_route_t *pr;
-  vl_api_ip_add_del_route_t *adr;
-  uword *p;
-  clib_error_t *e;
-  u32 ai;
-  ip_adjacency_t *adj;
-
-  p = hash_get (im->fib_index_by_table_id, ntohl (mp->vrf_id));
-  if (!p)
-    {
-      if (mp->create_vrf_if_needed)
-       {
-         ip4_fib_t *f;
-         f = find_ip4_fib_by_table_index_or_id (im, ntohl (mp->vrf_id),
-                                                0 /* flags */ );
-         fib_index = f->index;
-       }
-      else
-       {
-         /* No such VRF, and we weren't asked to create one */
-         return VNET_API_ERROR_NO_SUCH_FIB;
-       }
-    }
-  else
-    {
-      fib_index = p[0];
-    }
-
-  if (~0 != mp->next_hop_sw_if_index &&
-      pool_is_free_index (vnm->interface_main.sw_interfaces,
-                         ntohl (mp->next_hop_sw_if_index)))
-    return VNET_API_ERROR_NO_MATCHING_INTERFACE;
-
-  clib_memcpy (next_hop_address.data, mp->next_hop_address,
-              sizeof (next_hop_address.data));
-
-  /* Arp for the next_hop if necessary */
-  if (mp->is_add && mp->resolve_if_needed && ~0 != mp->next_hop_sw_if_index)
-    {
-      u32 lookup_result;
-      ip_adjacency_t *adj;
-
-      lookup_result = ip4_fib_lookup_with_table
-       (im, fib_index, &next_hop_address, 1 /* disable default route */ );
-
-      adj = ip_get_adjacency (lm, lookup_result);
-
-      if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP)
-       {
-         pool_get (vam->pending_routes, pr);
-         pr->resolve_type = RESOLVE_IP4_ADD_DEL_ROUTE;
-         adr = &pr->r;
-         clib_memcpy (adr, mp, sizeof (*adr));
-         /* recursion block, "just in case" */
-         adr->resolve_if_needed = 0;
-         adr->resolve_attempts = ntohl (mp->resolve_attempts);
-         vnet_register_ip4_arp_resolution_event
-           (vnm, &next_hop_address, vpe_resolver_process_node.index,
-            RESOLUTION_EVENT, pr - vam->pending_routes);
-
-         vlib_process_signal_event
-           (vm, vpe_resolver_process_node.index,
-            RESOLUTION_PENDING_EVENT, 0 /* data */ );
-
-         /* The interface may be down, etc. */
-         e = ip4_probe_neighbor
-           (vm, (ip4_address_t *) & (mp->next_hop_address),
-            ntohl (mp->next_hop_sw_if_index));
-
-         if (e)
-           clib_error_report (e);
-
-         return VNET_API_ERROR_IN_PROGRESS;
-       }
-    }
 
   if (mp->is_multipath)
     {
-      u32 flags;
+      fib_route_path_flags_t path_flags = FIB_ROUTE_PATH_FLAG_NONE;
 
       dslock (sm, 1 /* release hint */ , 10 /* tag */ );
 
+      if (mp->is_resolve_host)
+       path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
+      if (mp->is_resolve_attached)
+       path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
+
       if (mp->is_add)
-       flags = IP4_ROUTE_FLAG_ADD;
+       fib_table_entry_path_add (fib_index,
+                                 prefix,
+                                 FIB_SOURCE_API,
+                                 FIB_ENTRY_FLAG_NONE,
+                                 prefix->fp_proto,
+                                 next_hop,
+                                 next_hop_sw_if_index,
+                                 next_hop_fib_index,
+                                 next_hop_weight,
+                                 MPLS_LABEL_INVALID, path_flags);
       else
-       flags = IP4_ROUTE_FLAG_DEL;
-
-      if (mp->not_last)
-       flags |= IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP;
-
-      ip4_add_del_route_next_hop (im, flags,
-                                 (ip4_address_t *) mp->dst_address,
-                                 (u32) mp->dst_address_length,
-                                 (ip4_address_t *) mp->next_hop_address,
-                                 ntohl (mp->next_hop_sw_if_index),
-                                 (u32) mp->next_hop_weight,
-                                 ~0 /* adj_index */ ,
-                                 fib_index);
+       fib_table_entry_path_remove (fib_index,
+                                    prefix,
+                                    FIB_SOURCE_API,
+                                    prefix->fp_proto,
+                                    next_hop,
+                                    next_hop_sw_if_index,
+                                    next_hop_fib_index,
+                                    next_hop_weight, path_flags);
+
       dsunlock (sm);
       return 0;
     }
 
-  memset (&a, 0, sizeof (a));
-  clib_memcpy (a.dst_address.data, mp->dst_address,
-              sizeof (a.dst_address.data));
-
-  a.dst_address_length = mp->dst_address_length;
-
-  a.flags = (mp->is_add ? IP4_ROUTE_FLAG_ADD : IP4_ROUTE_FLAG_DEL);
-  a.flags |= IP4_ROUTE_FLAG_FIB_INDEX;
-  a.table_index_or_table_id = fib_index;
-  a.add_adj = 0;
-  a.n_add_adj = 0;
-
-  if (mp->not_last)
-    a.flags |= IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP;
-
   dslock (sm, 1 /* release hint */ , 2 /* tag */ );
 
-  if (mp->is_add)
+  if (mp->is_drop || mp->is_local || mp->is_classify || mp->lookup_in_vrf)
     {
-      if (mp->is_drop)
-       ai = lm->drop_adj_index;
-      else if (mp->is_local)
-       ai = lm->local_adj_index;
-      else if (mp->is_classify)
+      /*
+       * special route types that link directly to the adj
+       */
+      if (mp->is_add)
        {
-         if (pool_is_free_index
-             (cm->tables, ntohl (mp->classify_table_index)))
+         dpo_id_t dpo = DPO_NULL;
+         dpo_proto_t dproto;
+
+         dproto = fib_proto_to_dpo (prefix->fp_proto);
+
+         if (mp->is_drop)
+           dpo_copy (&dpo, drop_dpo_get (dproto));
+         else if (mp->is_local)
+           receive_dpo_add_or_lock (dproto, ~0, NULL, &dpo);
+         else if (mp->is_classify)
            {
-             dsunlock (sm);
-             return VNET_API_ERROR_NO_SUCH_TABLE;
-           }
-         adj = ip_add_adjacency (lm,
-                                 /* template */ 0,
-                                 /* block size */ 1,
-                                 &ai);
+             if (pool_is_free_index (cm->tables,
+                                     ntohl (mp->classify_table_index)))
+               {
+                 dsunlock (sm);
+                 return VNET_API_ERROR_NO_SUCH_TABLE;
+               }
 
-         adj->lookup_next_index = IP_LOOKUP_NEXT_CLASSIFY;
-         adj->classify.table_index = ntohl (mp->classify_table_index);
-       }
-      else if (mp->lookup_in_vrf)
-       {
-         p = hash_get (im->fib_index_by_table_id, ntohl (mp->lookup_in_vrf));
-         if (p)
+             dpo_set (&dpo, DPO_CLASSIFY, proto,
+                      classify_dpo_create (prefix->fp_proto,
+                                           ntohl
+                                           (mp->classify_table_index)));
+           }
+         else if (mp->lookup_in_vrf)
            {
-             adj = ip_add_adjacency (lm,
-                                     /* template */ 0,
-                                     /* block size */ 1,
-                                     &ai);
-             adj->explicit_fib_index = p[0];
+             next_hop_fib_index =
+               fib_table_id_find_fib_index (dproto,
+                                            ntohl (mp->lookup_in_vrf));
+             if (~0 == next_hop_fib_index)
+               {
+                 dsunlock (sm);
+                 return VNET_API_ERROR_NO_SUCH_INNER_FIB;
+               }
+
+             lookup_dpo_add_or_lock_w_fib_index (next_hop_fib_index,
+                                                 dproto,
+                                                 LOOKUP_INPUT_DST_ADDR,
+                                                 LOOKUP_TABLE_FROM_CONFIG,
+                                                 &dpo);
            }
          else
            {
              dsunlock (sm);
-             return VNET_API_ERROR_NO_SUCH_INNER_FIB;
+             return VNET_API_ERROR_NO_SUCH_TABLE;
            }
+
+         fib_table_entry_special_dpo_add (fib_index,
+                                          prefix,
+                                          FIB_SOURCE_API,
+                                          FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
+         dpo_reset (&dpo);
        }
       else
-       ai = ip4_route_get_next_hop_adj (im,
-                                        fib_index,
-                                        &next_hop_address,
-                                        ntohl (mp->next_hop_sw_if_index),
-                                        fib_index);
-
-      if (ai == lm->miss_adj_index)
        {
-         dsunlock (sm);
-         return VNET_API_ERROR_NO_SUCH_INNER_FIB;
+         fib_table_entry_special_remove (fib_index, prefix, FIB_SOURCE_API);
        }
     }
   else
     {
-      ip_adjacency_t *adj;
-      int disable_default_route = 1;
-
-      /* Trying to delete the default route? */
-      if (a.dst_address.as_u32 == 0 && a.dst_address_length == 0)
-       disable_default_route = 0;
-
-      ai = ip4_fib_lookup_with_table
-       (im, fib_index, &a.dst_address, disable_default_route);
-      if (ai == lm->miss_adj_index)
+      if (mp->is_add)
        {
-         dsunlock (sm);
-         return VNET_API_ERROR_UNKNOWN_DESTINATION;
+         fib_route_path_flags_t path_flags = FIB_ROUTE_PATH_FLAG_NONE;
+
+         if (mp->is_resolve_host)
+           path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
+         if (mp->is_resolve_attached)
+           path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
+
+         fib_table_entry_update_one_path (fib_index,
+                                          prefix,
+                                          FIB_SOURCE_API,
+                                          FIB_ENTRY_FLAG_NONE,
+                                          prefix->fp_proto,
+                                          next_hop,
+                                          next_hop_sw_if_index,
+                                          next_hop_fib_index,
+                                          next_hop_weight,
+                                          MPLS_LABEL_INVALID, path_flags);
        }
-
-      adj = ip_get_adjacency (lm, ai);
-      if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP)
+      else
        {
-         dsunlock (sm);
-         return VNET_API_ERROR_ADDRESS_MATCHES_INTERFACE_ADDRESS;
+         fib_table_entry_delete (fib_index, prefix, FIB_SOURCE_API);
        }
     }
 
-  a.adj_index = ai;
-  ip4_add_del_route (im, &a);
-
   dsunlock (sm);
-  return 0;
+  return (0);
 }
 
 static int
-ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
+ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
 {
-  ip6_main_t *im = &ip6_main;
-  ip_lookup_main_t *lm = &im->lookup_main;
-  vnet_main_t *vnm = vnet_get_main ();
-  vlib_main_t *vm = vlib_get_main ();
   vpe_api_main_t *vam = &vpe_api_main;
-  stats_main_t *sm = &stats_main;
-  ip6_add_del_route_args_t a;
-  ip6_address_t next_hop_address;
-  pending_route_t *pr;
-  vl_api_ip_add_del_route_t *adr;
-
+  vnet_main_t *vnm = vam->vnet_main;
   u32 fib_index;
-  uword *p;
-  clib_error_t *e;
-  ip_adjacency_t *adj = 0;
-  u32 ai;
 
-  p = hash_get (im->fib_index_by_table_id, ntohl (mp->vrf_id));
-
-  if (!p)
+  fib_index = ip4_fib_index_from_table_id (ntohl (mp->vrf_id));
+  if (~0 == fib_index)
     {
       if (mp->create_vrf_if_needed)
        {
-         ip6_fib_t *f;
-         f = find_ip6_fib_by_table_index_or_id (im, ntohl (mp->vrf_id),
-                                                0 /* flags */ );
-         fib_index = f->index;
+         fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
+                                                        ntohl (mp->vrf_id));
        }
       else
        {
@@ -1143,160 +1161,66 @@ ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
          return VNET_API_ERROR_NO_SUCH_FIB;
        }
     }
-  else
-    {
-      fib_index = p[0];
-    }
 
-  if (~0 != mp->next_hop_sw_if_index &&
+  if (~0 != ntohl (mp->next_hop_sw_if_index) &&
       pool_is_free_index (vnm->interface_main.sw_interfaces,
                          ntohl (mp->next_hop_sw_if_index)))
     return VNET_API_ERROR_NO_MATCHING_INTERFACE;
 
-  clib_memcpy (next_hop_address.as_u8, mp->next_hop_address,
-              sizeof (next_hop_address.as_u8));
-
-  /* Arp for the next_hop if necessary */
-  if (mp->is_add && mp->resolve_if_needed && ~0 != mp->next_hop_sw_if_index)
-    {
-      u32 lookup_result;
-      ip_adjacency_t *adj;
-
-      lookup_result = ip6_fib_lookup_with_table
-       (im, fib_index, &next_hop_address);
-
-      adj = ip_get_adjacency (lm, lookup_result);
-
-      if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP)
-       {
-         pool_get (vam->pending_routes, pr);
-         adr = &pr->r;
-         pr->resolve_type = RESOLVE_IP6_ADD_DEL_ROUTE;
-         clib_memcpy (adr, mp, sizeof (*adr));
-         /* recursion block, "just in case" */
-         adr->resolve_if_needed = 0;
-         adr->resolve_attempts = ntohl (mp->resolve_attempts);
-         vnet_register_ip6_neighbor_resolution_event
-           (vnm, &next_hop_address, vpe_resolver_process_node.index,
-            RESOLUTION_EVENT, pr - vam->pending_routes);
-
-         vlib_process_signal_event
-           (vm, vpe_resolver_process_node.index,
-            RESOLUTION_PENDING_EVENT, 0 /* data */ );
-
-         /* The interface may be down, etc. */
-         e = ip6_probe_neighbor
-           (vm, (ip6_address_t *) & (mp->next_hop_address),
-            ntohl (mp->next_hop_sw_if_index));
-
-         if (e)
-           clib_error_report (e);
-
-         return VNET_API_ERROR_IN_PROGRESS;
-       }
-    }
-
-  if (mp->is_multipath)
-    {
-      u32 flags;
-
-      dslock (sm, 1 /* release hint */ , 11 /* tag */ );
-
-      if (mp->is_add)
-       flags = IP6_ROUTE_FLAG_ADD;
-      else
-       flags = IP6_ROUTE_FLAG_DEL;
-
-      if (mp->not_last)
-       flags |= IP6_ROUTE_FLAG_NOT_LAST_IN_GROUP;
-
-      ip6_add_del_route_next_hop (im, flags,
-                                 (ip6_address_t *) mp->dst_address,
-                                 (u32) mp->dst_address_length,
-                                 (ip6_address_t *) mp->next_hop_address,
-                                 ntohl (mp->next_hop_sw_if_index),
-                                 (u32) mp->next_hop_weight,
-                                 ~0 /* adj_index */ ,
-                                 fib_index);
-      dsunlock (sm);
-      return 0;
-    }
-
-  memset (&a, 0, sizeof (a));
-  clib_memcpy (a.dst_address.as_u8, mp->dst_address,
-              sizeof (a.dst_address.as_u8));
-
-  a.dst_address_length = mp->dst_address_length;
+  fib_prefix_t pfx = {
+    .fp_len = mp->dst_address_length,
+    .fp_proto = FIB_PROTOCOL_IP4,
+  };
+  clib_memcpy (&pfx.fp_addr.ip4, mp->dst_address, sizeof (pfx.fp_addr.ip4));
 
-  a.flags = (mp->is_add ? IP6_ROUTE_FLAG_ADD : IP6_ROUTE_FLAG_DEL);
-  a.flags |= IP6_ROUTE_FLAG_FIB_INDEX;
-  a.table_index_or_table_id = fib_index;
-  a.add_adj = 0;
-  a.n_add_adj = 0;
+  ip46_address_t nh;
+  memset (&nh, 0, sizeof (nh));
+  memcpy (&nh.ip4, mp->next_hop_address, sizeof (nh.ip4));
 
-  if (mp->not_last)
-    a.flags |= IP6_ROUTE_FLAG_NOT_LAST_IN_GROUP;
+  return (ip_add_del_route_t_handler (mp, fib_index, &pfx, &nh,
+                                     ntohl (mp->next_hop_sw_if_index),
+                                     fib_index, (u32) mp->next_hop_weight));
+}
 
-  dslock (sm, 1 /* release hint */ , 3 /* tag */ );
+static int
+ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
+{
+  vnet_main_t *vnm = vnet_get_main ();
+  u32 fib_index;
 
-  if (mp->is_add)
+  fib_index = ip6_fib_index_from_table_id (ntohl (mp->vrf_id));
+  if (~0 == fib_index)
     {
-      if (mp->is_drop)
-       ai = lm->drop_adj_index;
-      else if (mp->is_local)
-       ai = lm->local_adj_index;
-      else if (mp->lookup_in_vrf)
+      if (mp->create_vrf_if_needed)
        {
-         p = hash_get (im->fib_index_by_table_id, ntohl (mp->lookup_in_vrf));
-         if (p)
-           {
-             adj = ip_add_adjacency (lm,
-                                     /* template */ 0,
-                                     /* block size */ 1,
-                                     &ai);
-             adj->explicit_fib_index = p[0];
-           }
-         else
-           {
-             dsunlock (sm);
-             return VNET_API_ERROR_NO_SUCH_INNER_FIB;
-           }
+         fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
+                                                        ntohl (mp->vrf_id));
        }
       else
-       ai = ip6_route_get_next_hop_adj (im,
-                                        fib_index,
-                                        &next_hop_address,
-                                        ntohl (mp->next_hop_sw_if_index),
-                                        fib_index);
-      if (ai == lm->miss_adj_index)
        {
-         dsunlock (sm);
-         return VNET_API_ERROR_NEXT_HOP_NOT_IN_FIB;
+         /* No such VRF, and we weren't asked to create one */
+         return VNET_API_ERROR_NO_SUCH_FIB;
        }
     }
-  else
-    {
-      ip_adjacency_t *adj;
 
-      ai = ip6_fib_lookup_with_table (im, fib_index, &a.dst_address);
-      if (ai == lm->miss_adj_index)
-       {
-         dsunlock (sm);
-         return VNET_API_ERROR_UNKNOWN_DESTINATION;
-       }
-      adj = ip_get_adjacency (lm, ai);
-      if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP)
-       {
-         dsunlock (sm);
-         return VNET_API_ERROR_ADDRESS_MATCHES_INTERFACE_ADDRESS;
-       }
-    }
+  if (~0 != ntohl (mp->next_hop_sw_if_index) &&
+      pool_is_free_index (vnm->interface_main.sw_interfaces,
+                         ntohl (mp->next_hop_sw_if_index)))
+    return VNET_API_ERROR_NO_MATCHING_INTERFACE;
 
-  a.adj_index = ai;
-  ip6_add_del_route (im, &a);
+  fib_prefix_t pfx = {
+    .fp_len = mp->dst_address_length,
+    .fp_proto = FIB_PROTOCOL_IP6,
+  };
+  clib_memcpy (&pfx.fp_addr.ip6, mp->dst_address, sizeof (pfx.fp_addr.ip6));
 
-  dsunlock (sm);
-  return 0;
+  ip46_address_t nh;
+  memset (&nh, 0, sizeof (nh));
+  memcpy (&nh.ip6, mp->next_hop_address, sizeof (nh.ip6));
+
+  return (ip_add_del_route_t_handler (mp, fib_index, &pfx,
+                                     &nh, ntohl (mp->next_hop_sw_if_index),
+                                     fib_index, (u32) mp->next_hop_weight));
 }
 
 void
@@ -1318,48 +1242,6 @@ vl_api_ip_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
   REPLY_MACRO (VL_API_IP_ADD_DEL_ROUTE_REPLY);
 }
 
-void
-api_config_default_ip_route (u8 is_ipv6, u8 is_add, u32 vrf_id,
-                            u32 sw_if_index, u8 * next_hop_addr)
-{
-  vl_api_ip_add_del_route_t mp;
-  int rv;
-
-  memset (&mp, 0, sizeof (vl_api_ip_add_del_route_t));
-
-  /*
-   * Configure default IP route:
-   *  - ip route add 0.0.0.0/1 via <GW IP>
-   *  - ip route add 128.0.0.0/1 via <GW IP>
-   */
-  mp.next_hop_sw_if_index = ntohl (sw_if_index);
-  mp.vrf_id = vrf_id;
-  mp.resolve_attempts = ~0;
-  mp.resolve_if_needed = 1;
-  mp.is_add = is_add;
-  mp.is_ipv6 = is_ipv6;
-  mp.next_hop_weight = 1;
-
-  clib_memcpy (&mp.next_hop_address[0], next_hop_addr, 16);
-
-  if (is_ipv6)
-    rv = ip6_add_del_route_t_handler (&mp);
-  else
-    {
-      mp.dst_address_length = 1;
-
-      mp.dst_address[0] = 0;
-      rv = ip4_add_del_route_t_handler (&mp);
-
-      mp.dst_address[0] = 128;
-      rv |= ip4_add_del_route_t_handler (&mp);
-    }
-
-  if (rv)
-    clib_error_return (0, "failed to config default IP route");
-
-}
-
 static void
   vl_api_sw_interface_add_del_address_t_handler
   (vl_api_sw_interface_add_del_address_t * mp)
@@ -1397,6 +1279,7 @@ vl_api_sw_interface_set_table_t_handler (vl_api_sw_interface_set_table_t * mp)
   u32 sw_if_index = ntohl (mp->sw_if_index);
   vl_api_sw_interface_set_table_reply_t *rmp;
   stats_main_t *sm = &stats_main;
+  u32 fib_index;
 
   VALIDATE_SW_IF_INDEX (mp);
 
@@ -1404,35 +1287,20 @@ vl_api_sw_interface_set_table_t_handler (vl_api_sw_interface_set_table_t * mp)
 
   if (mp->is_ipv6)
     {
-      ip6_main_t *im = &ip6_main;
-      ip6_fib_t *fib = find_ip6_fib_by_table_index_or_id (im, table_id,
-                                                         IP6_ROUTE_FLAG_TABLE_ID);
-      if (fib)
-       {
-         vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
-         im->fib_index_by_sw_if_index[sw_if_index] = fib->index;
-       }
-      else
-       {
-         rv = VNET_API_ERROR_NO_SUCH_FIB;
-       }
+      fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
+                                                    table_id);
+
+      vec_validate (ip6_main.fib_index_by_sw_if_index, sw_if_index);
+      ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
     }
   else
     {
-      ip4_main_t *im = &ip4_main;
-      ip4_fib_t *fib = find_ip4_fib_by_table_index_or_id
-       (im, table_id, IP4_ROUTE_FLAG_TABLE_ID);
 
-      /* Truthfully this can't fail */
-      if (fib)
-       {
-         vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
-         im->fib_index_by_sw_if_index[sw_if_index] = fib->index;
-       }
-      else
-       {
-         rv = VNET_API_ERROR_NO_SUCH_FIB;
-       }
+      fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
+                                                    table_id);
+
+      vec_validate (ip4_main.fib_index_by_sw_if_index, sw_if_index);
+      ip4_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
     }
   dsunlock (sm);
 
@@ -1588,6 +1456,144 @@ static void
   REPLY_MACRO (VL_API_SW_INTERFACE_SET_L2_BRIDGE_REPLY);
 }
 
+static void
+  vl_api_sw_interface_set_dpdk_hqos_pipe_t_handler
+  (vl_api_sw_interface_set_dpdk_hqos_pipe_t * mp)
+{
+  vl_api_sw_interface_set_dpdk_hqos_pipe_reply_t *rmp;
+  int rv = 0;
+
+#if DPDK > 0
+  dpdk_main_t *dm = &dpdk_main;
+  dpdk_device_t *xd;
+
+  u32 sw_if_index = ntohl (mp->sw_if_index);
+  u32 subport = ntohl (mp->subport);
+  u32 pipe = ntohl (mp->pipe);
+  u32 profile = ntohl (mp->profile);
+  vnet_hw_interface_t *hw;
+
+  VALIDATE_SW_IF_INDEX (mp);
+
+  /* hw_if & dpdk device */
+  hw = vnet_get_sup_hw_interface (dm->vnet_main, sw_if_index);
+
+  xd = vec_elt_at_index (dm->devices, hw->dev_instance);
+
+  rv = rte_sched_pipe_config (xd->hqos_ht->hqos, subport, pipe, profile);
+
+  BAD_SW_IF_INDEX_LABEL;
+#else
+  clib_warning ("setting HQoS pipe parameters without DPDK not implemented");
+  rv = VNET_API_ERROR_UNIMPLEMENTED;
+#endif /* DPDK */
+
+  REPLY_MACRO (VL_API_SW_INTERFACE_SET_DPDK_HQOS_PIPE_REPLY);
+}
+
+static void
+  vl_api_sw_interface_set_dpdk_hqos_subport_t_handler
+  (vl_api_sw_interface_set_dpdk_hqos_subport_t * mp)
+{
+  vl_api_sw_interface_set_dpdk_hqos_subport_reply_t *rmp;
+  int rv = 0;
+
+#if DPDK > 0
+  dpdk_main_t *dm = &dpdk_main;
+  dpdk_device_t *xd;
+  struct rte_sched_subport_params p;
+
+  u32 sw_if_index = ntohl (mp->sw_if_index);
+  u32 subport = ntohl (mp->subport);
+  p.tb_rate = ntohl (mp->tb_rate);
+  p.tb_size = ntohl (mp->tb_size);
+  p.tc_rate[0] = ntohl (mp->tc_rate[0]);
+  p.tc_rate[1] = ntohl (mp->tc_rate[1]);
+  p.tc_rate[2] = ntohl (mp->tc_rate[2]);
+  p.tc_rate[3] = ntohl (mp->tc_rate[3]);
+  p.tc_period = ntohl (mp->tc_period);
+
+  vnet_hw_interface_t *hw;
+
+  VALIDATE_SW_IF_INDEX (mp);
+
+  /* hw_if & dpdk device */
+  hw = vnet_get_sup_hw_interface (dm->vnet_main, sw_if_index);
+
+  xd = vec_elt_at_index (dm->devices, hw->dev_instance);
+
+  rv = rte_sched_subport_config (xd->hqos_ht->hqos, subport, &p);
+
+  BAD_SW_IF_INDEX_LABEL;
+#else
+  clib_warning
+    ("setting HQoS subport parameters without DPDK not implemented");
+  rv = VNET_API_ERROR_UNIMPLEMENTED;
+#endif /* DPDK */
+
+  REPLY_MACRO (VL_API_SW_INTERFACE_SET_DPDK_HQOS_SUBPORT_REPLY);
+}
+
+static void
+  vl_api_sw_interface_set_dpdk_hqos_tctbl_t_handler
+  (vl_api_sw_interface_set_dpdk_hqos_tctbl_t * mp)
+{
+  vl_api_sw_interface_set_dpdk_hqos_tctbl_reply_t *rmp;
+  int rv = 0;
+
+#if DPDK > 0
+  dpdk_main_t *dm = &dpdk_main;
+  vlib_thread_main_t *tm = vlib_get_thread_main ();
+  dpdk_device_t *xd;
+
+  u32 sw_if_index = ntohl (mp->sw_if_index);
+  u32 entry = ntohl (mp->entry);
+  u32 tc = ntohl (mp->tc);
+  u32 queue = ntohl (mp->queue);
+  u32 val, i;
+
+  vnet_hw_interface_t *hw;
+
+  VALIDATE_SW_IF_INDEX (mp);
+
+  /* hw_if & dpdk device */
+  hw = vnet_get_sup_hw_interface (dm->vnet_main, sw_if_index);
+
+  xd = vec_elt_at_index (dm->devices, hw->dev_instance);
+
+  if (tc >= RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE)
+    {
+      clib_warning ("invalid traffic class !!");
+      rv = VNET_API_ERROR_INVALID_VALUE;
+      goto done;
+    }
+  if (queue >= RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS)
+    {
+      clib_warning ("invalid queue !!");
+      rv = VNET_API_ERROR_INVALID_VALUE;
+      goto done;
+    }
+
+  /* Detect the set of worker threads */
+  uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers");
+  vlib_thread_registration_t *tr = (vlib_thread_registration_t *) p[0];
+  int worker_thread_first = tr->first_index;
+  int worker_thread_count = tr->count;
+
+  val = tc * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + queue;
+  for (i = 0; i < worker_thread_count; i++)
+    xd->hqos_wt[worker_thread_first + i].hqos_tc_table[entry] = val;
+
+  BAD_SW_IF_INDEX_LABEL;
+done:
+#else
+  clib_warning ("setting HQoS DSCP table entry without DPDK not implemented");
+  rv = VNET_API_ERROR_UNIMPLEMENTED;
+#endif /* DPDK */
+
+  REPLY_MACRO (VL_API_SW_INTERFACE_SET_DPDK_HQOS_TCTBL_REPLY);
+}
+
 static void
 vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp)
 {
@@ -2215,10 +2221,10 @@ static int mpls_ethernet_add_del_tunnel_2_t_handler
   if (inner_fib_index == outer_fib_index)
     return VNET_API_ERROR_INVALID_VALUE;
 
-  lookup_result = ip4_fib_lookup_with_table
-    (im, outer_fib_index,
-     (ip4_address_t *) mp->next_hop_ip4_address_in_outer_vrf,
-     1 /* disable default route */ );
+  // FIXME not an ADJ
+  lookup_result = ip4_fib_table_lookup_lb (ip4_fib_get (outer_fib_index),
+                                          (ip4_address_t *)
+                                          mp->next_hop_ip4_address_in_outer_vrf);
 
   adj = ip_get_adjacency (lm, lookup_result);
   tx_sw_if_index = adj->rewrite_header.sw_if_index;
@@ -2401,14 +2407,18 @@ vl_api_ip_neighbor_add_del_t_handler (vl_api_ip_neighbor_add_del_t * mp,
 {
   vl_api_ip_neighbor_add_del_reply_t *rmp;
   vnet_main_t *vnm = vnet_get_main ();
-  u32 fib_index;
-  int rv = 0;
   stats_main_t *sm = &stats_main;
+  int rv = 0;
 
   VALIDATE_SW_IF_INDEX (mp);
 
   dslock (sm, 1 /* release hint */ , 7 /* tag */ );
 
+  /*
+   * there's no validation here of the ND/ARP entry being added.
+   * The expectation is that the FIB will ensure that nothing bad
+   * will come of adding bogus entries.
+   */
   if (mp->is_ipv6)
     {
       if (mp->is_add)
@@ -2424,56 +2434,21 @@ vl_api_ip_neighbor_add_del_t_handler (vl_api_ip_neighbor_add_del_t * mp,
     }
   else
     {
-      ip4_main_t *im = &ip4_main;
-      ip_lookup_main_t *lm = &im->lookup_main;
       ethernet_arp_ip4_over_ethernet_address_t a;
-      u32 ai;
-      ip_adjacency_t *nh_adj;
-
-      uword *p = hash_get (im->fib_index_by_table_id, ntohl (mp->vrf_id));
-      if (!p)
-       {
-         rv = VNET_API_ERROR_NO_SUCH_FIB;
-         goto out;
-       }
-      fib_index = p[0];
-
-      /*
-       * Unfortunately, folks have a penchant for
-       * adding interface addresses to the ARP cache, and
-       * wondering why the forwarder eventually ASSERTs...
-       */
-      ai = ip4_fib_lookup_with_table
-       (im, fib_index, (ip4_address_t *) (mp->dst_address),
-        1 /* disable default route */ );
-
-      if (ai != 0)
-       {
-         nh_adj = ip_get_adjacency (lm, ai);
-         /* Never allow manipulation of a local adj! */
-         if (nh_adj->lookup_next_index == IP_LOOKUP_NEXT_LOCAL)
-           {
-             clib_warning ("%U matches local adj",
-                           format_ip4_address,
-                           (ip4_address_t *) (mp->dst_address));
-             rv = VNET_API_ERROR_ADDRESS_MATCHES_INTERFACE_ADDRESS;
-             goto out;
-           }
-       }
 
       clib_memcpy (&a.ethernet, mp->mac_address, 6);
       clib_memcpy (&a.ip4, mp->dst_address, 4);
 
       if (mp->is_add)
        rv = vnet_arp_set_ip4_over_ethernet (vnm, ntohl (mp->sw_if_index),
-                                            fib_index, &a, mp->is_static);
+                                            &a, mp->is_static);
       else
-       rv = vnet_arp_unset_ip4_over_ethernet (vnm, ntohl (mp->sw_if_index),
-                                              fib_index, &a);
+       rv =
+         vnet_arp_unset_ip4_over_ethernet (vnm, ntohl (mp->sw_if_index), &a);
     }
 
   BAD_SW_IF_INDEX_LABEL;
-out:
+
   dsunlock (sm);
   REPLY_MACRO (VL_API_IP_NEIGHBOR_ADD_DEL_REPLY);
 }
@@ -2516,6 +2491,7 @@ vl_api_is_address_reachable_t_handler (vl_api_is_address_reachable_t * mp)
   else
     {
       lm = &im4->lookup_main;
+      // FIXME NOT an ADJ
       adj_index = ip4_fib_lookup (im4, sw_if_index, &addr.ip4);
     }
   if (adj_index == ~0)
@@ -2570,17 +2546,33 @@ vl_api_sw_interface_set_flags_t_handler (vl_api_sw_interface_set_flags_t * mp)
 
   VALIDATE_SW_IF_INDEX (mp);
 
-  flags = mp->admin_up_down ? VNET_SW_INTERFACE_FLAG_ADMIN_UP : 0;
-
-  error = vnet_sw_interface_set_flags (vnm, ntohl (mp->sw_if_index), flags);
-  if (error)
-    {
-      rv = -1;
-      clib_error_report (error);
-    }
+  flags = mp->admin_up_down ? VNET_SW_INTERFACE_FLAG_ADMIN_UP : 0;
+
+  error = vnet_sw_interface_set_flags (vnm, ntohl (mp->sw_if_index), flags);
+  if (error)
+    {
+      rv = -1;
+      clib_error_report (error);
+    }
+
+  BAD_SW_IF_INDEX_LABEL;
+  REPLY_MACRO (VL_API_SW_INTERFACE_SET_FLAGS_REPLY);
+}
+
+static void
+  vl_api_sw_interface_set_mpls_enable_t_handler
+  (vl_api_sw_interface_set_mpls_enable_t * mp)
+{
+  vl_api_sw_interface_set_mpls_enable_reply_t *rmp;
+  int rv = 0;
+
+  VALIDATE_SW_IF_INDEX (mp);
+
+  mpls_sw_interface_enable_disable (&mpls_main,
+                                   ntohl (mp->sw_if_index), mp->enable);
 
   BAD_SW_IF_INDEX_LABEL;
-  REPLY_MACRO (VL_API_SW_INTERFACE_SET_FLAGS_REPLY);
+  REPLY_MACRO (VL_API_SW_INTERFACE_SET_MPLS_ENABLE_REPLY);
 }
 
 static void
@@ -2887,12 +2879,12 @@ vl_api_vnet_get_summary_stats_t_handler (vl_api_vnet_get_summary_stats_t * mp)
   }
   vnet_interface_counter_unlock (im);
 
-  /* Note: in HOST byte order! */
-  rmp->total_pkts[VLIB_RX] = total_pkts[VLIB_RX];
-  rmp->total_bytes[VLIB_RX] = total_bytes[VLIB_RX];
-  rmp->total_pkts[VLIB_TX] = total_pkts[VLIB_TX];
-  rmp->total_bytes[VLIB_TX] = total_bytes[VLIB_TX];
-  rmp->vector_rate = vlib_last_vector_length_per_node (sm->vlib_main);
+  rmp->total_pkts[VLIB_RX] = clib_host_to_net_u64 (total_pkts[VLIB_RX]);
+  rmp->total_bytes[VLIB_RX] = clib_host_to_net_u64 (total_bytes[VLIB_RX]);
+  rmp->total_pkts[VLIB_TX] = clib_host_to_net_u64 (total_pkts[VLIB_TX]);
+  rmp->total_bytes[VLIB_TX] = clib_host_to_net_u64 (total_bytes[VLIB_TX]);
+  rmp->vector_rate =
+    clib_host_to_net_u64 (vlib_last_vector_length_per_node (sm->vlib_main));
 
   vl_msg_api_send_shmem (q, (u8 *) & rmp);
 }
@@ -2911,10 +2903,9 @@ ip4_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;
   ip4_main_t *im4 = &ip4_main;
-  static ip4_route_t *routes;
   static u32 *sw_if_indices_to_shut;
   stats_main_t *sm = &stats_main;
-  ip4_route_t *r;
+  fib_table_t *fib_table;
   ip4_fib_t *fib;
   u32 sw_if_index;
   int i;
@@ -2923,9 +2914,11 @@ ip4_reset_fib_t_handler (vl_api_reset_fib_t * mp)
 
   dslock (sm, 1 /* release hint */ , 8 /* tag */ );
 
-  vec_foreach (fib, im4->fibs)
-  {
-    vnet_sw_interface_t *si;
+  /* *INDENT-OFF* */
+  pool_foreach (fib_table, im4->fibs,
+  ({
+    fib = &fib_table->v4;
+    vnet_sw_interface_t * si;
 
     if (fib->table_id != target_fib_id)
       continue;
@@ -2945,100 +2938,37 @@ ip4_reset_fib_t_handler (vl_api_reset_fib_t * mp)
     vec_reset_length (sw_if_indices_to_shut);
 
     /* Shut down interfaces in this FIB / clean out intfc routes */
-    /* *INDENT-OFF* */
     pool_foreach (si, im->sw_interfaces,
     ({
       u32 sw_if_index = si->sw_if_index;
 
       if (sw_if_index < vec_len (im4->fib_index_by_sw_if_index)
           && (im4->fib_index_by_sw_if_index[si->sw_if_index] ==
-              fib - im4->fibs))
+              fib->index))
         vec_add1 (sw_if_indices_to_shut, si->sw_if_index);
     }));
-    /* *INDENT-ON* */
-
-    for (i = 0; i < vec_len (sw_if_indices_to_shut); i++)
-      {
-       sw_if_index = sw_if_indices_to_shut[i];
-       // vec_foreach (sw_if_index, sw_if_indices_to_shut) {
 
-       u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
-       flags &= ~(VNET_SW_INTERFACE_FLAG_ADMIN_UP);
-       vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
-      }
-
-    vec_reset_length (routes);
-
-    for (i = 0; i < ARRAY_LEN (fib->adj_index_by_dst_address); i++)
-      {
-       uword *hash = fib->adj_index_by_dst_address[i];
-       hash_pair_t *p;
-       ip4_route_t x;
-
-       x.address_length = i;
-
-        /* *INDENT-OFF* */
-        hash_foreach_pair (p, hash,
-        ({
-          x.address.data_u32 = p->key;
-          vec_add1 (routes, x);
-        }));
-        /* *INDENT-ON* */
-      }
+    for (i = 0; i < vec_len (sw_if_indices_to_shut); i++) {
+      sw_if_index = sw_if_indices_to_shut[i];
+      // vec_foreach (sw_if_index, sw_if_indices_to_shut) {
 
-    vec_foreach (r, routes)
-    {
-      ip4_add_del_route_args_t a;
+      u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
+      flags &= ~(VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+      vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
+    }
 
-      memset (&a, 0, sizeof (a));
-      a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL;
-      a.table_index_or_table_id = fib - im4->fibs;
-      a.dst_address = r->address;
-      a.dst_address_length = r->address_length;
-      a.adj_index = ~0;
+    fib_table_flush(fib->index, FIB_PROTOCOL_IP4, FIB_SOURCE_API);
+    fib_table_flush(fib->index, FIB_PROTOCOL_IP4, FIB_SOURCE_INTERFACE);
 
-      ip4_add_del_route (im4, &a);
-      ip4_maybe_remap_adjacencies (im4, fib - im4->fibs,
-                                  IP4_ROUTE_FLAG_FIB_INDEX);
-    }
     rv = 0;
     break;
-  }                            /* vec_foreach (fib) */
+    })); /* pool_foreach (fib) */
+    /* *INDENT-ON* */
 
   dsunlock (sm);
   return rv;
 }
 
-typedef struct
-{
-  ip6_address_t address;
-  u32 address_length;
-  u32 index;
-} ip6_route_t;
-
-typedef struct
-{
-  u32 fib_index;
-  ip6_route_t **routep;
-} add_routes_in_fib_arg_t;
-
-static void
-add_routes_in_fib (clib_bihash_kv_24_8_t * kvp, void *arg)
-{
-  add_routes_in_fib_arg_t *ap = arg;
-
-  if (kvp->key[2] >> 32 == ap->fib_index)
-    {
-      ip6_address_t *addr;
-      ip6_route_t *r;
-      addr = (ip6_address_t *) kvp;
-      vec_add2 (*ap->routep, r, 1);
-      r->address = addr[0];
-      r->address_length = kvp->key[2] & 0xFF;
-      r->index = kvp->value;
-    }
-}
-
 static int
 ip6_reset_fib_t_handler (vl_api_reset_fib_t * mp)
 {
@@ -3046,22 +2976,21 @@ ip6_reset_fib_t_handler (vl_api_reset_fib_t * mp)
   vnet_interface_main_t *im = &vnm->interface_main;
   ip6_main_t *im6 = &ip6_main;
   stats_main_t *sm = &stats_main;
-  static ip6_route_t *routes;
   static u32 *sw_if_indices_to_shut;
-  ip6_route_t *r;
+  fib_table_t *fib_table;
   ip6_fib_t *fib;
   u32 sw_if_index;
   int i;
   int rv = VNET_API_ERROR_NO_SUCH_FIB;
   u32 target_fib_id = ntohl (mp->vrf_id);
-  add_routes_in_fib_arg_t _a, *a = &_a;
-  clib_bihash_24_8_t *h = &im6->ip6_lookup_table;
 
   dslock (sm, 1 /* release hint */ , 9 /* tag */ );
 
-  vec_foreach (fib, im6->fibs)
-  {
-    vnet_sw_interface_t *si;
+  /* *INDENT-OFF* */
+  pool_foreach (fib_table, im6->fibs,
+  ({
+    vnet_sw_interface_t * si;
+    fib = &(fib_table->v6);
 
     if (fib->table_id != target_fib_id)
       continue;
@@ -3069,52 +2998,29 @@ ip6_reset_fib_t_handler (vl_api_reset_fib_t * mp)
     vec_reset_length (sw_if_indices_to_shut);
 
     /* Shut down interfaces in this FIB / clean out intfc routes */
-    /* *INDENT-OFF* */
     pool_foreach (si, im->sw_interfaces,
-    ({
-      if (im6->fib_index_by_sw_if_index[si->sw_if_index] ==
-          fib - im6->fibs)
-        vec_add1 (sw_if_indices_to_shut, si->sw_if_index);
-    }));
-    /* *INDENT-ON* */
-
-    for (i = 0; i < vec_len (sw_if_indices_to_shut); i++)
-      {
-       sw_if_index = sw_if_indices_to_shut[i];
-       // vec_foreach (sw_if_index, sw_if_indices_to_shut) {
+                  ({
+                    if (im6->fib_index_by_sw_if_index[si->sw_if_index] ==
+                        fib->index)
+                      vec_add1 (sw_if_indices_to_shut, si->sw_if_index);
+                  }));
 
-       u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
-       flags &= ~(VNET_SW_INTERFACE_FLAG_ADMIN_UP);
-       vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
-      }
-
-    vec_reset_length (routes);
-
-    a->fib_index = fib - im6->fibs;
-    a->routep = &routes;
-
-    clib_bihash_foreach_key_value_pair_24_8 (h, add_routes_in_fib, a);
+    for (i = 0; i < vec_len (sw_if_indices_to_shut); i++) {
+      sw_if_index = sw_if_indices_to_shut[i];
+      // vec_foreach (sw_if_index, sw_if_indices_to_shut) {
 
-    vec_foreach (r, routes)
-    {
-      ip6_add_del_route_args_t a;
+      u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
+      flags &= ~(VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+      vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
+    }
 
-      memset (&a, 0, sizeof (a));
-      a.flags = IP6_ROUTE_FLAG_FIB_INDEX | IP6_ROUTE_FLAG_DEL;
-      a.table_index_or_table_id = fib - im6->fibs;
-      a.dst_address = r->address;
-      a.dst_address_length = r->address_length;
-      a.adj_index = ~0;
+    fib_table_flush(fib->index, FIB_PROTOCOL_IP6, FIB_SOURCE_API);
+    fib_table_flush(fib->index, FIB_PROTOCOL_IP6, FIB_SOURCE_INTERFACE);
 
-      ip6_add_del_route (im6, &a);
-      ip6_maybe_remap_adjacencies (im6, fib - im6->fibs,
-                                  IP6_ROUTE_FLAG_FIB_INDEX);
-    }
     rv = 0;
-    /* Reinstall the neighbor / router discovery routes */
-    vnet_ip6_fib_init (im6, fib - im6->fibs);
     break;
-  }                            /* vec_foreach (fib) */
+  })); /* pool_foreach (fib) */
+  /* *INDENT-ON* */
 
   dsunlock (sm);
   return rv;
@@ -3431,7 +3337,7 @@ set_ip4_flow_hash (vl_api_set_ip_flow_hash_t * mp)
   vl_api_set_ip_flow_hash_reply_t *rmp;
   int rv;
   u32 table_id;
-  u32 flow_hash_config = 0;
+  flow_hash_config_t flow_hash_config = 0;
 
   table_id = ntohl (mp->vrf_id);
 
@@ -3492,11 +3398,15 @@ static void vl_api_sw_interface_set_unnumbered_t_handler
     {
       si->flags |= VNET_SW_INTERFACE_FLAG_UNNUMBERED;
       si->unnumbered_sw_if_index = sw_if_index;
+      ip4_sw_interface_enable_disable (sw_if_index, 1);
+      ip6_sw_interface_enable_disable (sw_if_index, 1);
     }
   else
     {
       si->flags &= ~(VNET_SW_INTERFACE_FLAG_UNNUMBERED);
       si->unnumbered_sw_if_index = (u32) ~ 0;
+      ip4_sw_interface_enable_disable (sw_if_index, 0);
+      ip6_sw_interface_enable_disable (sw_if_index, 0);
     }
 
 done:
@@ -3547,20 +3457,6 @@ vl_api_control_ping_t_handler (vl_api_control_ping_t * mp)
   /* *INDENT-ON* */
 }
 
-static void vl_api_noprint_control_ping_t_handler
-  (vl_api_noprint_control_ping_t * mp)
-{
-  vl_api_noprint_control_ping_reply_t *rmp;
-  int rv = 0;
-
-  /* *INDENT-OFF* */
-  REPLY_MACRO2(VL_API_NOPRINT_CONTROL_PING_REPLY,
-  ({
-    rmp->vpe_pid = ntohl (getpid());
-  }));
-  /* *INDENT-ON* */
-}
-
 static void
 shmem_cli_output (uword arg, u8 * buffer, uword buffer_bytes)
 {
@@ -3624,6 +3520,46 @@ vl_api_cli_request_t_handler (vl_api_cli_request_t * mp)
   vl_msg_api_send_shmem (q, (u8 *) & rp);
 }
 
+static void
+inband_cli_output (uword arg, u8 * buffer, uword buffer_bytes)
+{
+  u8 **mem_vecp = (u8 **) arg;
+  u8 *mem_vec = *mem_vecp;
+  u32 offset = vec_len (mem_vec);
+
+  vec_validate (mem_vec, offset + buffer_bytes - 1);
+  clib_memcpy (mem_vec + offset, buffer, buffer_bytes);
+  *mem_vecp = mem_vec;
+}
+
+static void
+vl_api_cli_inband_t_handler (vl_api_cli_inband_t * mp)
+{
+  vl_api_cli_inband_reply_t *rmp;
+  int rv = 0;
+  unix_shared_memory_queue_t *q;
+  vlib_main_t *vm = vlib_get_main ();
+  unformat_input_t input;
+  u8 *out_vec = 0;
+
+  q = vl_api_client_index_to_input_queue (mp->client_index);
+  if (!q)
+    return;
+
+  unformat_init_string (&input, (char *) mp->cmd, ntohl (mp->length));
+  vlib_cli_input (vm, &input, inband_cli_output, (uword) & out_vec);
+
+  u32 len = vec_len (out_vec);
+  /* *INDENT-OFF* */
+  REPLY_MACRO3(VL_API_CLI_INBAND_REPLY, len,
+  ({
+    rmp->length = htonl (len);
+    clib_memcpy (rmp->reply, out_vec, len);
+  }));
+  /* *INDENT-ON* */
+  vec_free (out_vec);
+}
+
 static void
 vl_api_set_arp_neighbor_limit_t_handler (vl_api_set_arp_neighbor_limit_t * mp)
 {
@@ -3655,7 +3591,7 @@ vl_api_set_arp_neighbor_limit_t_handler (vl_api_set_arp_neighbor_limit_t * mp)
 static void vl_api_sr_tunnel_add_del_t_handler
   (vl_api_sr_tunnel_add_del_t * mp)
 {
-#if IPV6SR == 0
+#if IP6SR == 0
   clib_warning ("unimplemented");
 #else
   ip6_sr_add_del_tunnel_args_t _a, *a = &_a;
@@ -3718,7 +3654,7 @@ out:
 static void vl_api_sr_policy_add_del_t_handler
   (vl_api_sr_policy_add_del_t * mp)
 {
-#if IPV6SR == 0
+#if IP6SR == 0
   clib_warning ("unimplemented");
 #else
   ip6_sr_add_del_policy_args_t _a, *a = &_a;
@@ -3772,7 +3708,7 @@ out:
 static void vl_api_sr_multicast_map_add_del_t_handler
   (vl_api_sr_multicast_map_add_del_t * mp)
 {
-#if IPV6SR == 0
+#if IP6SR == 0
   clib_warning ("unimplemented");
 #else
   ip6_sr_add_del_multicastmap_args_t _a, *a = &_a;
@@ -3928,8 +3864,14 @@ static void vl_api_classify_set_interface_l2_tables_t_handler
 
   VALIDATE_SW_IF_INDEX (mp);
 
-  rv = vnet_l2_classify_set_tables (sw_if_index, ip4_table_index,
-                                   ip6_table_index, other_table_index);
+  if (mp->is_input)
+    rv = vnet_l2_input_classify_set_tables (sw_if_index, ip4_table_index,
+                                           ip6_table_index,
+                                           other_table_index);
+  else
+    rv = vnet_l2_output_classify_set_tables (sw_if_index, ip4_table_index,
+                                            ip6_table_index,
+                                            other_table_index);
 
   if (rv == 0)
     {
@@ -3939,7 +3881,10 @@ static void vl_api_classify_set_interface_l2_tables_t_handler
       else
        enable = 0;
 
-      vnet_l2_classify_enable_disable (sw_if_index, enable);
+      if (mp->is_input)
+       vnet_l2_input_classify_enable_disable (sw_if_index, enable);
+      else
+       vnet_l2_output_classify_enable_disable (sw_if_index, enable);
     }
 
   BAD_SW_IF_INDEX_LABEL;
@@ -4027,16 +3972,20 @@ vl_api_create_vhost_user_if_t_handler (vl_api_create_vhost_user_if_t * mp)
 {
   int rv = 0;
   vl_api_create_vhost_user_if_reply_t *rmp;
-#if DPDK > 0
   u32 sw_if_index = (u32) ~ 0;
 
   vnet_main_t *vnm = vnet_get_main ();
   vlib_main_t *vm = vlib_get_main ();
 
-  rv = vhost_user_create_if (vnm, vm, (char *) mp->sock_filename,
-                            mp->is_server, &sw_if_index, (u64) ~ 0,
-                            mp->renumber, ntohl (mp->custom_dev_instance),
-                            (mp->use_custom_mac) ? mp->mac_address : NULL);
+#if DPDK > 0 && DPDK_VHOST_USER
+  rv = dpdk_vhost_user_create_if (
+#else
+  rv = vhost_user_create_if (
+#endif
+                             vnm, vm, (char *) mp->sock_filename,
+                             mp->is_server, &sw_if_index, (u64) ~ 0,
+                             mp->renumber, ntohl (mp->custom_dev_instance),
+                             (mp->use_custom_mac) ? mp->mac_address : NULL);
 
   /* *INDENT-OFF* */
   REPLY_MACRO2(VL_API_CREATE_VHOST_USER_IF_REPLY,
@@ -4044,10 +3993,6 @@ vl_api_create_vhost_user_if_t_handler (vl_api_create_vhost_user_if_t * mp)
     rmp->sw_if_index = ntohl (sw_if_index);
   }));
   /* *INDENT-ON* */
-#else
-  rv = VNET_API_ERROR_UNIMPLEMENTED;
-  REPLY_MACRO (VL_API_CREATE_VHOST_USER_IF_REPLY);
-#endif
 }
 
 static void
@@ -4055,19 +4000,19 @@ vl_api_modify_vhost_user_if_t_handler (vl_api_modify_vhost_user_if_t * mp)
 {
   int rv = 0;
   vl_api_modify_vhost_user_if_reply_t *rmp;
-#if DPDK > 0 && DPDK_VHOST_USER
   u32 sw_if_index = ntohl (mp->sw_if_index);
 
   vnet_main_t *vnm = vnet_get_main ();
   vlib_main_t *vm = vlib_get_main ();
 
-  rv = dpdk_vhost_user_modify_if (vnm, vm, (char *) mp->sock_filename,
-                                 mp->is_server, sw_if_index, (u64) ~ 0,
-                                 mp->renumber,
-                                 ntohl (mp->custom_dev_instance));
+#if DPDK > 0 && DPDK_VHOST_USER
+  rv = dpdk_vhost_user_modify_if (
 #else
-  rv = VNET_API_ERROR_UNIMPLEMENTED;
+  rv = vhost_user_modify_if (
 #endif
+                             vnm, vm, (char *) mp->sock_filename,
+                             mp->is_server, sw_if_index, (u64) ~ 0,
+                             mp->renumber, ntohl (mp->custom_dev_instance));
   REPLY_MACRO (VL_API_MODIFY_VHOST_USER_IF_REPLY);
 }
 
@@ -4076,14 +4021,17 @@ vl_api_delete_vhost_user_if_t_handler (vl_api_delete_vhost_user_if_t * mp)
 {
   int rv = 0;
   vl_api_delete_vhost_user_if_reply_t *rmp;
-#if DPDK > 0 && DPDK_VHOST_USER
   vpe_api_main_t *vam = &vpe_api_main;
   u32 sw_if_index = ntohl (mp->sw_if_index);
 
   vnet_main_t *vnm = vnet_get_main ();
   vlib_main_t *vm = vlib_get_main ();
 
+#if DPDK > 0 && DPDK_VHOST_USER
   rv = dpdk_vhost_user_delete_if (vnm, vm, sw_if_index);
+#else
+  rv = vhost_user_delete_if (vnm, vm, sw_if_index);
+#endif
 
   REPLY_MACRO (VL_API_DELETE_VHOST_USER_IF_REPLY);
   if (!rv)
@@ -4095,10 +4043,6 @@ vl_api_delete_vhost_user_if_t_handler (vl_api_delete_vhost_user_if_t * mp)
 
       send_sw_interface_flags_deleted (vam, q, sw_if_index);
     }
-#else
-  rv = VNET_API_ERROR_UNIMPLEMENTED;
-  REPLY_MACRO (VL_API_DELETE_VHOST_USER_IF_REPLY);
-#endif
 }
 
 static void
@@ -4108,7 +4052,6 @@ static void
   clib_warning ("BUG");
 }
 
-#if DPDK > 0 && DPDK_VHOST_USER
 static void
 send_sw_interface_vhost_user_details (vpe_api_main_t * am,
                                      unix_shared_memory_queue_t * q,
@@ -4135,13 +4078,11 @@ send_sw_interface_vhost_user_details (vpe_api_main_t * am,
 
   vl_msg_api_send_shmem (q, (u8 *) & mp);
 }
-#endif
 
 static void
   vl_api_sw_interface_vhost_user_dump_t_handler
   (vl_api_sw_interface_vhost_user_dump_t * mp)
 {
-#if DPDK > 0 && DPDK_VHOST_USER
   int rv = 0;
   vpe_api_main_t *am = &vpe_api_main;
   vnet_main_t *vnm = vnet_get_main ();
@@ -4154,7 +4095,11 @@ static void
   if (q == 0)
     return;
 
+#if DPDK > 0 && DPDK_VHOST_USER
   rv = dpdk_vhost_user_dump_ifs (vnm, vm, &ifaces);
+#else
+  rv = vhost_user_dump_ifs (vnm, vm, &ifaces);
+#endif
   if (rv)
     return;
 
@@ -4163,7 +4108,6 @@ static void
     send_sw_interface_vhost_user_details (am, q, vuid, mp->context);
   }
   vec_free (ifaces);
-#endif
 }
 
 static void
@@ -4784,13 +4728,13 @@ static void send_vxlan_tunnel_details
     {
       memcpy (rmp->src_address, &(t->src.ip6), 16);
       memcpy (rmp->dst_address, &(t->dst.ip6), 16);
-      rmp->encap_vrf_id = htonl (im6->fibs[t->encap_fib_index].table_id);
+      rmp->encap_vrf_id = htonl (im6->fibs[t->encap_fib_index].ft_table_id);
     }
   else
     {
       memcpy (rmp->src_address, &(t->src.ip4), 4);
       memcpy (rmp->dst_address, &(t->dst.ip4), 4);
-      rmp->encap_vrf_id = htonl (im4->fibs[t->encap_fib_index].table_id);
+      rmp->encap_vrf_id = htonl (im4->fibs[t->encap_fib_index].ft_table_id);
     }
   rmp->vni = htonl (t->vni);
   rmp->decap_next_index = htonl (t->decap_next_index);
@@ -4867,6 +4811,7 @@ static void vl_api_gre_add_del_tunnel_t_handler
   memset (a, 0, sizeof (*a));
 
   a->is_add = mp->is_add;
+  a->teb = mp->teb;
 
   /* ip addresses sent in network byte order */
   clib_memcpy (&(a->src), mp->src_address, 4);
@@ -4895,7 +4840,8 @@ static void send_gre_tunnel_details
   rmp->_vl_msg_id = ntohs (VL_API_GRE_TUNNEL_DETAILS);
   clib_memcpy (rmp->src_address, &(t->tunnel_src), 4);
   clib_memcpy (rmp->dst_address, &(t->tunnel_dst), 4);
-  rmp->outer_fib_id = htonl (im->fibs[t->outer_fib_index].table_id);
+  rmp->outer_fib_id = htonl (im->fibs[t->outer_fib_index].ft_table_id);
+  rmp->teb = t->teb;
   rmp->sw_if_index = htonl (t->sw_if_index);
   rmp->context = context;
 
@@ -5054,15 +5000,15 @@ static void send_vxlan_gpe_tunnel_details
     {
       memcpy (rmp->local, &(t->local.ip6), 16);
       memcpy (rmp->remote, &(t->remote.ip6), 16);
-      rmp->encap_vrf_id = htonl (im6->fibs[t->encap_fib_index].table_id);
-      rmp->decap_vrf_id = htonl (im6->fibs[t->decap_fib_index].table_id);
+      rmp->encap_vrf_id = htonl (im6->fibs[t->encap_fib_index].ft_table_id);
+      rmp->decap_vrf_id = htonl (im6->fibs[t->decap_fib_index].ft_table_id);
     }
   else
     {
       memcpy (rmp->local, &(t->local.ip4), 4);
       memcpy (rmp->remote, &(t->remote.ip4), 4);
-      rmp->encap_vrf_id = htonl (im4->fibs[t->encap_fib_index].table_id);
-      rmp->decap_vrf_id = htonl (im4->fibs[t->decap_fib_index].table_id);
+      rmp->encap_vrf_id = htonl (im4->fibs[t->encap_fib_index].ft_table_id);
+      rmp->decap_vrf_id = htonl (im4->fibs[t->decap_fib_index].ft_table_id);
     }
   rmp->vni = htonl (t->vni);
   rmp->protocol = t->protocol;
@@ -5128,7 +5074,7 @@ vl_api_lisp_add_del_locator_set_t_handler (vl_api_lisp_add_del_locator_set_t *
   vnet_lisp_add_del_locator_set_args_t _a, *a = &_a;
   locator_t locator;
   ls_locator_t *ls_loc;
-  u32 ls_index = ~0;
+  u32 ls_index = ~0, locator_num;
   u8 *locator_name = NULL;
   int i;
 
@@ -5139,9 +5085,10 @@ vl_api_lisp_add_del_locator_set_t_handler (vl_api_lisp_add_del_locator_set_t *
   a->name = locator_name;
   a->is_add = mp->is_add;
   a->local = 1;
+  locator_num = clib_net_to_host_u32 (mp->locator_num);
 
   memset (&locator, 0, sizeof (locator));
-  for (i = 0; i < mp->locator_num; i++)
+  for (i = 0; i < locator_num; i++)
     {
       ls_loc = &((ls_locator_t *) mp->locators)[i];
       VALIDATE_SW_IF_INDEX (ls_loc);
@@ -5160,7 +5107,12 @@ vl_api_lisp_add_del_locator_set_t_handler (vl_api_lisp_add_del_locator_set_t *
   vec_free (locator_name);
   vec_free (a->locators);
 
-  REPLY_MACRO (VL_API_LISP_ADD_DEL_LOCATOR_SET_REPLY);
+  /* *INDENT-OFF* */
+  REPLY_MACRO2 (VL_API_LISP_ADD_DEL_LOCATOR_SET_REPLY,
+  ({
+    rmp->ls_index = clib_host_to_net_u32 (ls_index);
+  }));
+  /* *INDENT-ON* */
 }
 
 static void
@@ -5421,17 +5373,59 @@ vl_api_lisp_gpe_add_del_iface_t_handler (vl_api_lisp_gpe_add_del_iface_t * mp)
 {
   vl_api_lisp_gpe_add_del_iface_reply_t *rmp;
   int rv = 0;
-  vnet_lisp_gpe_add_del_iface_args_t _a, *a = &_a;
 
-  a->is_add = mp->is_add;
-  a->dp_table = mp->dp_table;
-  a->vni = mp->vni;
-  a->is_l2 = mp->is_l2;
-  rv = vnet_lisp_gpe_add_del_iface (a, 0);
+  if (mp->is_l2)
+    {
+      if (mp->is_add)
+       {
+         if (~0 ==
+             lisp_gpe_tenant_l2_iface_add_or_lock (mp->vni, mp->dp_table))
+           rv = 1;
+       }
+      else
+       lisp_gpe_tenant_l2_iface_unlock (mp->vni);
+    }
+  else
+    {
+      if (mp->is_add)
+       {
+         if (~0 ==
+             lisp_gpe_tenant_l3_iface_add_or_lock (mp->vni, mp->dp_table))
+           rv = 1;
+       }
+      else
+       lisp_gpe_tenant_l3_iface_unlock (mp->vni);
+    }
 
   REPLY_MACRO (VL_API_LISP_GPE_ADD_DEL_IFACE_REPLY);
 }
 
+static void
+  vl_api_show_lisp_map_request_mode_t_handler
+  (vl_api_show_lisp_map_request_mode_t * mp)
+{
+  int rv = 0;
+  vl_api_show_lisp_map_request_mode_reply_t *rmp;
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO2(VL_API_SHOW_LISP_MAP_REQUEST_MODE_REPLY,
+  ({
+    rmp->mode = vnet_lisp_get_map_request_mode ();
+  }));
+  /* *INDENT-ON* */
+}
+
+static void
+vl_api_lisp_map_request_mode_t_handler (vl_api_lisp_map_request_mode_t * mp)
+{
+  vl_api_lisp_map_request_mode_reply_t *rmp;
+  int rv = 0;
+
+  rv = vnet_lisp_set_map_request_mode (mp->mode);
+
+  REPLY_MACRO (VL_API_LISP_MAP_REQUEST_MODE_REPLY);
+}
+
 static void
 vl_api_lisp_pitr_set_locator_set_t_handler (vl_api_lisp_pitr_set_locator_set_t
                                            * mp)
@@ -5476,6 +5470,7 @@ static void
   vl_api_lisp_add_del_remote_mapping_reply_t *rmp;
   int rv = 0;
   gid_address_t _eid, *eid = &_eid;
+  u32 rloc_num = clib_net_to_host_u32 (mp->rloc_num);
 
   memset (eid, 0, sizeof (eid[0]));
 
@@ -5484,14 +5479,12 @@ static void
   if (rv)
     goto send_reply;
 
-  rlocs = unformat_lisp_locs (mp->rlocs, mp->rloc_num);
-  if (0 == rlocs)
-    goto send_reply;
+  rlocs = unformat_lisp_locs (mp->rlocs, rloc_num);
 
   if (!mp->is_add)
     {
       vnet_lisp_add_del_adjacency_args_t _a, *a = &_a;
-      gid_address_copy (&a->deid, eid);
+      gid_address_copy (&a->reid, eid);
       a->is_add = 0;
       rv = vnet_lisp_add_del_adjacency (a);
       if (rv)
@@ -5503,7 +5496,7 @@ static void
   /* NOTE: for now this works as a static remote mapping, i.e.,
    * not authoritative and ttl infinite. */
   rv = vnet_lisp_add_del_mapping (eid, rlocs, mp->action, 0, ~0,
-                                 mp->is_add, 0);
+                                 mp->is_add, 1 /* is_static */ , 0);
 
   if (mp->del_all)
     vnet_lisp_clear_all_remote_adjacencies ();
@@ -5523,10 +5516,10 @@ vl_api_lisp_add_del_adjacency_t_handler (vl_api_lisp_add_del_adjacency_t * mp)
   int rv = 0;
   memset (a, 0, sizeof (a[0]));
 
-  rv = unformat_lisp_eid_api (&a->seid, clib_net_to_host_u32 (mp->vni),
-                             mp->eid_type, mp->seid, mp->seid_len);
-  rv |= unformat_lisp_eid_api (&a->deid, clib_net_to_host_u32 (mp->vni),
-                              mp->eid_type, mp->deid, mp->deid_len);
+  rv = unformat_lisp_eid_api (&a->leid, clib_net_to_host_u32 (mp->vni),
+                             mp->eid_type, mp->leid, mp->leid_len);
+  rv |= unformat_lisp_eid_api (&a->reid, clib_net_to_host_u32 (mp->vni),
+                              mp->eid_type, mp->reid, mp->reid_len);
 
   if (rv)
     goto send_reply;
@@ -5569,12 +5562,13 @@ send_lisp_locator_details (lisp_cp_main_t * lcm,
 static void
 vl_api_lisp_locator_dump_t_handler (vl_api_lisp_locator_dump_t * mp)
 {
+  u8 *ls_name = 0;
   unix_shared_memory_queue_t *q = 0;
   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
   locator_set_t *lsit = 0;
   locator_t *loc = 0;
   u32 ls_index = ~0, *locit = 0;
-  u8 filter;
+  uword *p = 0;
 
   q = vl_api_client_index_to_input_queue (mp->client_index);
   if (q == 0)
@@ -5582,22 +5576,31 @@ vl_api_lisp_locator_dump_t_handler (vl_api_lisp_locator_dump_t * mp)
       return;
     }
 
-  ls_index = htonl (mp->locator_set_index);
-
-  lsit = pool_elt_at_index (lcm->locator_set_pool, ls_index);
-
-  filter = mp->filter;
-  if (filter && !((1 == filter && lsit->local) ||
-                 (2 == filter && !lsit->local)))
+  if (mp->is_index_set)
+    ls_index = htonl (mp->ls_index);
+  else
     {
-      return;
+      /* make sure we get a proper C-string */
+      mp->ls_name[sizeof (mp->ls_name) - 1] = 0;
+      ls_name = format (0, "%s", mp->ls_name);
+      p = hash_get_mem (lcm->locator_set_index_by_name, ls_name);
+      if (!p)
+       goto out;
+      ls_index = p[0];
     }
 
+  if (pool_is_free_index (lcm->locator_set_pool, ls_index))
+    return;
+
+  lsit = pool_elt_at_index (lcm->locator_set_pool, ls_index);
+
   vec_foreach (locit, lsit->locator_indices)
   {
     loc = pool_elt_at_index (lcm->locator_pool, locit[0]);
     send_lisp_locator_details (lcm, loc, q, mp->context);
   };
+out:
+  vec_free (ls_name);
 }
 
 static void
@@ -5614,19 +5617,17 @@ send_lisp_locator_set_details (lisp_cp_main_t * lcm,
   rmp->_vl_msg_id = ntohs (VL_API_LISP_LOCATOR_SET_DETAILS);
   rmp->context = context;
 
-  rmp->local = lsit->local;
-  rmp->locator_set_index = htonl (ls_index);
+  rmp->ls_index = htonl (ls_index);
   if (lsit->local)
     {
       ASSERT (lsit->name != NULL);
-      strncpy ((char *) rmp->locator_set_name,
-              (char *) lsit->name, ARRAY_LEN (rmp->locator_set_name) - 1);
+      strncpy ((char *) rmp->ls_name, (char *) lsit->name,
+              vec_len (lsit->name));
     }
   else
     {
-      str = format (0, "remote-%d", ls_index);
-      strncpy ((char *) rmp->locator_set_name, (char *) str,
-              ARRAY_LEN (rmp->locator_set_name) - 1);
+      str = format (0, "<remote-%d>", ls_index);
+      strncpy ((char *) rmp->ls_name, (char *) str, vec_len (str));
       vec_free (str);
     }
 
@@ -5639,7 +5640,6 @@ vl_api_lisp_locator_set_dump_t_handler (vl_api_lisp_locator_set_dump_t * mp)
   unix_shared_memory_queue_t *q = NULL;
   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
   locator_set_t *lsit = NULL;
-  u32 index;
   u8 filter;
 
   q = vl_api_client_index_to_input_queue (mp->client_index);
@@ -5649,25 +5649,78 @@ vl_api_lisp_locator_set_dump_t_handler (vl_api_lisp_locator_set_dump_t * mp)
     }
 
   filter = mp->filter;
-  index = 0;
   /* *INDENT-OFF* */
   pool_foreach (lsit, lcm->locator_set_pool,
   ({
     if (filter && !((1 == filter && lsit->local) ||
-                    (2 == filter && !lsit->local))) {
-      index++;
-      continue;
-    }
-    send_lisp_locator_set_details(lcm, lsit, q, mp->context, index++);
+                    (2 == filter && !lsit->local)))
+      {
+        continue;
+      }
+    send_lisp_locator_set_details (lcm, lsit, q, mp->context,
+                                   lsit - lcm->locator_set_pool);
   }));
   /* *INDENT-ON* */
 }
 
+static void
+lisp_fid_put_api (u8 * dst, fid_address_t * src, u8 * prefix_length)
+{
+  ASSERT (prefix_length);
+  ip_prefix_t *ippref = &fid_addr_ippref (src);
+
+  switch (fid_addr_type (src))
+    {
+    case FID_ADDR_IP_PREF:
+      if (ip_prefix_version (ippref) == IP4)
+       clib_memcpy (dst, &ip_prefix_v4 (ippref), 4);
+      else
+       clib_memcpy (dst, &ip_prefix_v6 (ippref), 16);
+      prefix_length[0] = ip_prefix_len (ippref);
+      break;
+
+    case FID_ADDR_MAC:
+      prefix_length[0] = 0;
+      clib_memcpy (dst, fid_addr_mac (src), 6);
+      break;
+
+    default:
+      clib_warning ("Unknown FID type %d!", fid_addr_type (src));
+      break;
+    }
+}
+
+static u8
+fid_type_to_api_type (fid_address_t * fid)
+{
+  ip_prefix_t *ippref;
+
+  switch (fid_addr_type (fid))
+    {
+    case FID_ADDR_IP_PREF:
+      ippref = &fid_addr_ippref (fid);
+      if (ip_prefix_version (ippref) == IP4)
+       return 0;
+      else if (ip_prefix_version (ippref) == IP6)
+       return 1;
+      else
+       return ~0;
+
+    case FID_ADDR_MAC:
+      return 2;
+    }
+
+  return ~0;
+}
+
 static void
 send_lisp_eid_table_details (mapping_t * mapit,
                             unix_shared_memory_queue_t * q,
                             u32 context, u8 filter)
 {
+  fid_address_t *fid;
+  lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
+  locator_set_t *ls = 0;
   vl_api_lisp_eid_table_details_t *rmp = NULL;
   gid_address_t *gid = NULL;
   u8 *mac = 0;
@@ -5698,13 +5751,29 @@ send_lisp_eid_table_details (mapping_t * mapit,
   rmp = vl_msg_api_alloc (sizeof (*rmp));
   memset (rmp, 0, sizeof (*rmp));
   rmp->_vl_msg_id = ntohs (VL_API_LISP_EID_TABLE_DETAILS);
-  rmp->locator_set_index = mapit->locator_set_index;
+
+  ls = pool_elt_at_index (lcm->locator_set_pool, mapit->locator_set_index);
+  if (vec_len (ls->locator_indices) == 0)
+    rmp->locator_set_index = ~0;
+  else
+    rmp->locator_set_index = clib_host_to_net_u32 (mapit->locator_set_index);
+
   rmp->is_local = mapit->local;
-  rmp->ttl = mapit->ttl;
+  rmp->ttl = clib_host_to_net_u32 (mapit->ttl);
+  rmp->action = mapit->action;
   rmp->authoritative = mapit->authoritative;
 
   switch (gid_address_type (gid))
     {
+    case GID_ADDR_SRC_DST:
+      rmp->is_src_dst = 1;
+      fid = &gid_address_sd_src (gid);
+      rmp->eid_type = fid_type_to_api_type (fid);
+      lisp_fid_put_api (rmp->seid, &gid_address_sd_src (gid),
+                       &rmp->seid_prefix_len);
+      lisp_fid_put_api (rmp->eid, &gid_address_sd_dst (gid),
+                       &rmp->eid_prefix_len);
+      break;
     case GID_ADDR_IP_PREFIX:
       rmp->eid_prefix_len = ip_prefix_len (ip_prefix);
       if (ip_prefix_version (ip_prefix) == IP4)
@@ -5751,9 +5820,8 @@ vl_api_lisp_eid_table_dump_t_handler (vl_api_lisp_eid_table_dump_t * mp)
     {
       memset (eid, 0, sizeof (*eid));
 
-      unformat_lisp_eid_api (eid, mp->eid_type,
-                            clib_net_to_host_u32 (mp->vni), mp->eid,
-                            mp->prefix_length);
+      unformat_lisp_eid_api (eid, clib_net_to_host_u32 (mp->vni),
+                            mp->eid_type, mp->eid, mp->prefix_length);
 
       mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, eid);
       if ((u32) ~ 0 == mi)
@@ -5776,8 +5844,8 @@ vl_api_lisp_eid_table_dump_t_handler (vl_api_lisp_eid_table_dump_t * mp)
 }
 
 static void
-send_lisp_gpe_tunnel_details (lisp_gpe_tunnel_t * tunnel,
-                             unix_shared_memory_queue_t * q, u32 context)
+send_lisp_gpe_fwd_entry_details (lisp_gpe_fwd_entry_t * lfe,
+                                unix_shared_memory_queue_t * q, u32 context)
 {
   vl_api_lisp_gpe_tunnel_details_t *rmp;
   lisp_gpe_main_t *lgm = &lisp_gpe_main;
@@ -5786,21 +5854,17 @@ send_lisp_gpe_tunnel_details (lisp_gpe_tunnel_t * tunnel,
   memset (rmp, 0, sizeof (*rmp));
   rmp->_vl_msg_id = ntohs (VL_API_LISP_GPE_TUNNEL_DETAILS);
 
-  rmp->tunnels = tunnel - lgm->tunnels;
-
-  rmp->is_ipv6 = ip_addr_version (&tunnel->src) == IP6 ? 1 : 0;
-  ip_address_copy_addr (rmp->source_ip, &tunnel->src);
-  ip_address_copy_addr (rmp->destination_ip, &tunnel->dst);
-
-  rmp->encap_fib_id = htonl (tunnel->encap_fib_index);
-  rmp->decap_fib_id = htonl (tunnel->decap_fib_index);
-  rmp->dcap_next = htonl (tunnel->decap_next_index);
-  rmp->lisp_ver = tunnel->ver_res;
-  rmp->next_protocol = tunnel->next_protocol;
-  rmp->flags = tunnel->flags;
-  rmp->ver_res = tunnel->ver_res;
-  rmp->res = tunnel->res;
-  rmp->iid = htonl (tunnel->vni);
+  rmp->tunnels = lfe - lgm->lisp_fwd_entry_pool;
+
+  rmp->is_ipv6 = ip_prefix_version (&(lfe->key->rmt.ippref)) == IP6 ? 1 : 0;
+  ip_address_copy_addr (rmp->source_ip,
+                       &ip_prefix_addr (&(lfe->key->rmt.ippref)));
+  ip_address_copy_addr (rmp->destination_ip,
+                       &ip_prefix_addr (&(lfe->key->rmt.ippref)));
+
+  rmp->encap_fib_id = htonl (0);
+  rmp->decap_fib_id = htonl (lfe->eid_fib_index);
+  rmp->iid = htonl (lfe->key->vni);
   rmp->context = context;
 
   vl_msg_api_send_shmem (q, (u8 *) & rmp);
@@ -5811,9 +5875,9 @@ vl_api_lisp_gpe_tunnel_dump_t_handler (vl_api_lisp_gpe_tunnel_dump_t * mp)
 {
   unix_shared_memory_queue_t *q = NULL;
   lisp_gpe_main_t *lgm = &lisp_gpe_main;
-  lisp_gpe_tunnel_t *tunnel = NULL;
+  lisp_gpe_fwd_entry_t *lfe = NULL;
 
-  if (pool_elts (lgm->tunnels) == 0)
+  if (pool_elts (lgm->lisp_fwd_entry_pool) == 0)
     {
       return;
     }
@@ -5825,9 +5889,9 @@ vl_api_lisp_gpe_tunnel_dump_t_handler (vl_api_lisp_gpe_tunnel_dump_t * mp)
     }
 
   /* *INDENT-OFF* */
-  pool_foreach(tunnel, lgm->tunnels,
+  pool_foreach(lfe, lgm->lisp_fwd_entry_pool,
   ({
-    send_lisp_gpe_tunnel_details(tunnel, q, mp->context);
+    send_lisp_gpe_fwd_entry_details(lfe, q, mp->context);
   }));
   /* *INDENT-ON* */
 }
@@ -5874,50 +5938,109 @@ vl_api_lisp_map_resolver_dump_t_handler (vl_api_lisp_map_resolver_dump_t * mp)
   q = vl_api_client_index_to_input_queue (mp->client_index);
   if (q == 0)
     {
-      return;
+      return;
+    }
+
+  vec_foreach (mr, lcm->map_resolvers)
+  {
+    send_lisp_map_resolver_details (&mr->address, q, mp->context);
+  }
+}
+
+static void
+send_eid_table_map_pair (hash_pair_t * p,
+                        unix_shared_memory_queue_t * q, u32 context)
+{
+  vl_api_lisp_eid_table_map_details_t *rmp = NULL;
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id = ntohs (VL_API_LISP_EID_TABLE_MAP_DETAILS);
+
+  rmp->vni = clib_host_to_net_u32 (p->key);
+  rmp->dp_table = clib_host_to_net_u32 (p->value[0]);
+  rmp->context = context;
+  vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+static void
+vl_api_lisp_eid_table_map_dump_t_handler (vl_api_lisp_eid_table_map_dump_t *
+                                         mp)
+{
+  unix_shared_memory_queue_t *q = NULL;
+  lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
+  hash_pair_t *p;
+  uword *vni_table = 0;
+
+  q = vl_api_client_index_to_input_queue (mp->client_index);
+  if (q == 0)
+    {
+      return;
+    }
+
+  if (mp->is_l2)
+    {
+      vni_table = lcm->bd_id_by_vni;
+    }
+  else
+    {
+      vni_table = lcm->table_id_by_vni;
     }
 
-  vec_foreach (mr, lcm->map_resolvers)
-  {
-    send_lisp_map_resolver_details (&mr->address, q, mp->context);
-  }
+  /* *INDENT-OFF* */
+  hash_foreach_pair (p, vni_table,
+  ({
+    send_eid_table_map_pair (p, q, mp->context);
+  }));
+  /* *INDENT-ON* */
 }
 
 static void
-send_eid_table_map_pair (hash_pair_t * p,
-                        unix_shared_memory_queue_t * q, u32 context)
+send_eid_table_vni (u32 vni, unix_shared_memory_queue_t * q, u32 context)
 {
-  vl_api_lisp_eid_table_map_details_t *rmp = NULL;
+  vl_api_lisp_eid_table_vni_details_t *rmp = 0;
 
   rmp = vl_msg_api_alloc (sizeof (*rmp));
   memset (rmp, 0, sizeof (*rmp));
-  rmp->_vl_msg_id = ntohs (VL_API_LISP_EID_TABLE_MAP_DETAILS);
-
-  rmp->vni = clib_host_to_net_u32 (p->key);
-  rmp->vrf = clib_host_to_net_u32 (p->value[0]);
+  rmp->_vl_msg_id = ntohs (VL_API_LISP_EID_TABLE_VNI_DETAILS);
   rmp->context = context;
+  rmp->vni = clib_host_to_net_u32 (vni);
   vl_msg_api_send_shmem (q, (u8 *) & rmp);
 }
 
 static void
-vl_api_lisp_eid_table_map_dump_t_handler (vl_api_lisp_eid_table_map_dump_t *
+vl_api_lisp_eid_table_vni_dump_t_handler (vl_api_lisp_eid_table_vni_dump_t *
                                          mp)
 {
-  unix_shared_memory_queue_t *q = NULL;
-  lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
   hash_pair_t *p;
+  u32 *vnis = 0;
+  unix_shared_memory_queue_t *q = 0;
+  lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
 
   q = vl_api_client_index_to_input_queue (mp->client_index);
   if (q == 0)
     {
       return;
     }
+
   /* *INDENT-OFF* */
   hash_foreach_pair (p, lcm->table_id_by_vni,
   ({
-    send_eid_table_map_pair (p, q, mp->context);
+    hash_set (vnis, p->key, 0);
+  }));
+
+  hash_foreach_pair (p, lcm->bd_id_by_vni,
+  ({
+    hash_set (vnis, p->key, 0);
+  }));
+
+  hash_foreach_pair (p, vnis,
+  ({
+    send_eid_table_vni (p->key, q, mp->context);
   }));
   /* *INDENT-ON* */
+
+  hash_free (vnis);
 }
 
 static void
@@ -6059,29 +6182,68 @@ arp_change_data_callback (u32 pool_index, u8 * new_mac,
     return 1;
 
   event = pool_elt_at_index (am->arp_events, pool_index);
+  /* *INDENT-OFF* */
   if (memcmp (&event->new_mac, new_mac, sizeof (event->new_mac)))
     {
       clib_memcpy (event->new_mac, new_mac, sizeof (event->new_mac));
     }
   else
     {                          /* same mac */
-      if ((sw_if_index == event->sw_if_index) && ((address == 0) ||
-                                                 /* for BD case, also check IP address with 10 sec timeout */
-                                                 ((address == event->address)
-                                                  &&
-                                                  ((now -
-                                                    arp_event_last_time) <
-                                                   10.0))))
+      if (sw_if_index == event->sw_if_index &&
+         (!event->mac_ip ||
+          /* for BD case, also check IP address with 10 sec timeout */
+          (address == event->address &&
+           (now - arp_event_last_time) < 10.0)))
        return 1;
     }
+  /* *INDENT-ON* */
 
   arp_event_last_time = now;
   event->sw_if_index = sw_if_index;
-  if (address)
+  if (event->mac_ip)
     event->address = address;
   return 0;
 }
 
+static int
+nd_change_data_callback (u32 pool_index, u8 * new_mac,
+                        u32 sw_if_index, ip6_address_t * address)
+{
+  vpe_api_main_t *am = &vpe_api_main;
+  vlib_main_t *vm = am->vlib_main;
+  vl_api_ip6_nd_event_t *event;
+  static f64 nd_event_last_time;
+  f64 now = vlib_time_now (vm);
+
+  if (pool_is_free_index (am->nd_events, pool_index))
+    return 1;
+
+  event = pool_elt_at_index (am->nd_events, pool_index);
+
+  /* *INDENT-OFF* */
+  if (memcmp (&event->new_mac, new_mac, sizeof (event->new_mac)))
+    {
+      clib_memcpy (event->new_mac, new_mac, sizeof (event->new_mac));
+    }
+  else
+    {                          /* same mac */
+      if (sw_if_index == event->sw_if_index &&
+         (!event->mac_ip ||
+          /* for BD case, also check IP address with 10 sec timeout */
+          (ip6_address_is_equal (address,
+                                 (ip6_address_t *) event->address) &&
+           (now - nd_event_last_time) < 10.0)))
+       return 1;
+    }
+  /* *INDENT-ON* */
+
+  nd_event_last_time = now;
+  event->sw_if_index = sw_if_index;
+  if (event->mac_ip)
+    clib_memcpy (event->address, address, sizeof (event->address));
+  return 0;
+}
+
 static int
 arp_change_delete_callback (u32 pool_index, u8 * notused)
 {
@@ -6094,6 +6256,18 @@ arp_change_delete_callback (u32 pool_index, u8 * notused)
   return 0;
 }
 
+static int
+nd_change_delete_callback (u32 pool_index, u8 * notused)
+{
+  vpe_api_main_t *am = &vpe_api_main;
+
+  if (pool_is_free_index (am->nd_events, pool_index))
+    return 1;
+
+  pool_put_index (am->nd_events, pool_index);
+  return 0;
+}
+
 static void
 vl_api_want_ip4_arp_events_t_handler (vl_api_want_ip4_arp_events_t * mp)
 {
@@ -6113,6 +6287,8 @@ vl_api_want_ip4_arp_events_t_handler (vl_api_want_ip4_arp_events_t * mp)
       event->context = mp->context;
       event->address = mp->address;
       event->pid = mp->pid;
+      if (mp->address == 0)
+       event->mac_ip = 1;
 
       rv = vnet_add_del_ip4_arp_change_event
        (vnm, arp_change_data_callback,
@@ -6131,6 +6307,45 @@ vl_api_want_ip4_arp_events_t_handler (vl_api_want_ip4_arp_events_t * mp)
   REPLY_MACRO (VL_API_WANT_IP4_ARP_EVENTS_REPLY);
 }
 
+static void
+vl_api_want_ip6_nd_events_t_handler (vl_api_want_ip6_nd_events_t * mp)
+{
+  vpe_api_main_t *am = &vpe_api_main;
+  vnet_main_t *vnm = vnet_get_main ();
+  vl_api_want_ip6_nd_events_reply_t *rmp;
+  vl_api_ip6_nd_event_t *event;
+  int rv;
+
+  if (mp->enable_disable)
+    {
+      pool_get (am->nd_events, event);
+      memset (event, 0, sizeof (*event));
+
+      event->_vl_msg_id = ntohs (VL_API_IP6_ND_EVENT);
+      event->client_index = mp->client_index;
+      event->context = mp->context;
+      clib_memcpy (event->address, mp->address, 16);
+      event->pid = mp->pid;
+      if (ip6_address_is_zero ((ip6_address_t *) mp->address))
+       event->mac_ip = 1;
+
+      rv = vnet_add_del_ip6_nd_change_event
+       (vnm, nd_change_data_callback,
+        mp->pid, mp->address /* addr, in net byte order */ ,
+        vpe_resolver_process_node.index,
+        IP6_ND_EVENT, event - am->nd_events, 1 /* is_add */ );
+    }
+  else
+    {
+      rv = vnet_add_del_ip6_nd_change_event
+       (vnm, nd_change_delete_callback,
+        mp->pid, mp->address /* addr, in net byte order */ ,
+        vpe_resolver_process_node.index,
+        IP6_ND_EVENT, ~0 /* pool index */ , 0 /* is_add */ );
+    }
+  REPLY_MACRO (VL_API_WANT_IP6_ND_EVENTS_REPLY);
+}
+
 static void vl_api_input_acl_set_interface_t_handler
   (vl_api_input_acl_set_interface_t * mp)
 {
@@ -6738,56 +6953,30 @@ vl_api_get_node_graph_t_handler (vl_api_get_node_graph_t * mp)
   /* *INDENT-ON* */
 }
 
-static void vl_api_trace_profile_add_t_handler
-  (vl_api_trace_profile_add_t * mp)
+static void
+vl_api_ioam_enable_t_handler (vl_api_ioam_enable_t * mp)
 {
   int rv = 0;
-  vl_api_trace_profile_add_reply_t *rmp;
+  vl_api_ioam_enable_reply_t *rmp;
   clib_error_t *error;
 
   /* Ignoring the profile id as currently a single profile
    * is supported */
-  error = ip6_ioam_trace_profile_set (mp->trace_num_elt, mp->trace_type,
-                                     ntohl (mp->node_id),
-                                     ntohl (mp->trace_app_data),
-                                     mp->pow_enable, mp->trace_tsp,
-                                     mp->trace_ppc);
+  error = ip6_ioam_enable (mp->trace_enable, mp->pow_enable, mp->trace_ppc);
   if (error)
     {
       clib_error_report (error);
       rv = clib_error_get_code (error);
     }
 
-  REPLY_MACRO (VL_API_TRACE_PROFILE_ADD_REPLY);
-}
-
-static void vl_api_trace_profile_apply_t_handler
-  (vl_api_trace_profile_apply_t * mp)
-{
-  int rv = 0;
-  vl_api_trace_profile_apply_reply_t *rmp;
-
-  if (mp->enable != 0)
-    {
-      rv = ip6_ioam_set_destination ((ip6_address_t *) (&mp->dest_ipv6),
-                                    ntohl (mp->prefix_length),
-                                    ntohl (mp->vrf_id),
-                                    mp->trace_op == IOAM_HBYH_ADD,
-                                    mp->trace_op == IOAM_HBYH_POP,
-                                    mp->trace_op == IOAM_HBYH_MOD);
-    }
-  else
-    {
-      //ip6_ioam_clear_destination(&ip6, mp->prefix_length, mp->vrf_id);
-    }
-  REPLY_MACRO (VL_API_TRACE_PROFILE_APPLY_REPLY);
+  REPLY_MACRO (VL_API_IOAM_ENABLE_REPLY);
 }
 
-static void vl_api_trace_profile_del_t_handler
-  (vl_api_trace_profile_del_t * mp)
+static void
+vl_api_ioam_disable_t_handler (vl_api_ioam_disable_t * mp)
 {
   int rv = 0;
-  vl_api_trace_profile_del_reply_t *rmp;
+  vl_api_ioam_disable_reply_t *rmp;
   clib_error_t *error;
 
   error = clear_ioam_rewrite_fn ();
@@ -6797,7 +6986,7 @@ static void vl_api_trace_profile_del_t_handler
       rv = clib_error_get_code (error);
     }
 
-  REPLY_MACRO (VL_API_TRACE_PROFILE_DEL_REPLY);
+  REPLY_MACRO (VL_API_IOAM_DISABLE_REPLY);
 }
 
 static void
@@ -7301,7 +7490,6 @@ vl_api_mpls_fib_encap_dump_t_handler (vl_api_mpls_fib_encap_dump_t * mp)
   show_mpls_fib_t *records = 0;
   show_mpls_fib_t *s;
   mpls_main_t *mm = &mpls_main;
-  ip4_main_t *im = &ip4_main;
   ip4_fib_t *rx_fib;
 
   q = vl_api_client_index_to_input_queue (mp->client_index);
@@ -7331,7 +7519,7 @@ vl_api_mpls_fib_encap_dump_t_handler (vl_api_mpls_fib_encap_dump_t * mp)
   vlib_cli_output (vm, "%=6s%=16s%=16s", "Table", "Dest address", "Labels");
   vec_foreach (s, records)
   {
-    rx_fib = vec_elt_at_index (im->fibs, s->fib_index);
+    rx_fib = ip4_fib_get (s->fib_index);
     vlib_cli_output (vm, "%=6d%=16U%=16U", rx_fib->table_id,
                     format_ip4_address, &s->dest, format_mpls_encap_index,
                     mm, s->entry_index);
@@ -7386,7 +7574,6 @@ vl_api_mpls_fib_decap_dump_t_handler (vl_api_mpls_fib_decap_dump_t * mp)
   show_mpls_fib_t *records = 0;
   show_mpls_fib_t *s;
   mpls_main_t *mm = &mpls_main;
-  ip4_main_t *im = &ip4_main;
   ip4_fib_t *rx_fib;
   ip4_fib_t *tx_fib;
   u32 tx_table_id;
@@ -7421,9 +7608,9 @@ vl_api_mpls_fib_decap_dump_t_handler (vl_api_mpls_fib_decap_dump_t * mp)
   {
     mpls_decap_t *d;
     d = pool_elt_at_index (mm->decaps, s->entry_index);
-    if (d->next_index == MPLS_INPUT_NEXT_IP4_INPUT)
+    if (d->next_index == MPLS_LOOKUP_NEXT_IP4_INPUT)
       {
-       tx_fib = vec_elt_at_index (im->fibs, d->tx_fib_index);
+       tx_fib = ip4_fib_get (d->tx_fib_index);
        tx_table_id = tx_fib->table_id;
        swif_tag = "     ";
       }
@@ -7432,7 +7619,7 @@ vl_api_mpls_fib_decap_dump_t_handler (vl_api_mpls_fib_decap_dump_t * mp)
        tx_table_id = d->tx_fib_index;
        swif_tag = "(i)  ";
       }
-    rx_fib = vec_elt_at_index (im->fibs, s->fib_index);
+    rx_fib = ip4_fib_get (s->fib_index);
 
     vlib_cli_output (vm, "%=10d%=10d%=5s%=6d%=6d", rx_fib->table_id,
                     tx_table_id, swif_tag, s->label, s->s_bit);
@@ -7619,6 +7806,8 @@ vl_api_classify_session_dump_t_handler (vl_api_classify_session_dump_t * mp)
   vnet_classify_table_t *t;
 
   q = vl_api_client_index_to_input_queue (mp->client_index);
+  if (!q)
+    return;
 
   /* *INDENT-OFF* */
   pool_foreach (t, cm->tables,
@@ -7658,15 +7847,16 @@ vl_api_classify_session_dump_t_handler (vl_api_classify_session_dump_t * mp)
 }
 
 static void
-vl_api_ipfix_enable_t_handler (vl_api_ipfix_enable_t * mp)
+vl_api_set_ipfix_exporter_t_handler (vl_api_set_ipfix_exporter_t * mp)
 {
   vlib_main_t *vm = vlib_get_main ();
   flow_report_main_t *frm = &flow_report_main;
-  vl_api_ipfix_enable_reply_t *rmp;
+  vl_api_set_ipfix_exporter_reply_t *rmp;
   ip4_address_t collector, src;
   u16 collector_port = UDP_DST_PORT_ipfix;
   u32 path_mtu;
   u32 template_interval;
+  u8 udp_checksum;
   u32 fib_id;
   u32 fib_index = ~0;
   int rv = 0;
@@ -7679,13 +7869,20 @@ vl_api_ipfix_enable_t_handler (vl_api_ipfix_enable_t * mp)
   fib_id = ntohl (mp->vrf_id);
 
   ip4_main_t *im = &ip4_main;
-  uword *p = hash_get (im->fib_index_by_table_id, fib_id);
-  if (!p)
+  if (fib_id == ~0)
     {
-      rv = VNET_API_ERROR_NO_SUCH_FIB;
-      goto out;
+      fib_index = ~0;
+    }
+  else
+    {
+      uword *p = hash_get (im->fib_index_by_table_id, fib_id);
+      if (!p)
+       {
+         rv = VNET_API_ERROR_NO_SUCH_FIB;
+         goto out;
+       }
+      fib_index = p[0];
     }
-  fib_index = p[0];
 
   path_mtu = ntohl (mp->path_mtu);
   if (path_mtu == ~0)
@@ -7693,6 +7890,7 @@ vl_api_ipfix_enable_t_handler (vl_api_ipfix_enable_t * mp)
   template_interval = ntohl (mp->template_interval);
   if (template_interval == ~0)
     template_interval = 20;
+  udp_checksum = mp->udp_checksum;
 
   if (collector.as_u32 == 0)
     {
@@ -7730,20 +7928,23 @@ vl_api_ipfix_enable_t_handler (vl_api_ipfix_enable_t * mp)
   frm->fib_index = fib_index;
   frm->path_mtu = path_mtu;
   frm->template_interval = template_interval;
+  frm->udp_checksum = udp_checksum;
 
   /* Turn on the flow reporting process */
   vlib_process_signal_event (vm, flow_report_process_node.index, 1, 0);
 
 out:
-  REPLY_MACRO (VL_API_IPFIX_ENABLE_REPLY);
+  REPLY_MACRO (VL_API_SET_IPFIX_EXPORTER_REPLY);
 }
 
 static void
-vl_api_ipfix_dump_t_handler (vl_api_ipfix_dump_t * mp)
+vl_api_ipfix_exporter_dump_t_handler (vl_api_ipfix_exporter_dump_t * mp)
 {
   flow_report_main_t *frm = &flow_report_main;
   unix_shared_memory_queue_t *q;
-  vl_api_ipfix_details_t *rmp;
+  vl_api_ipfix_exporter_details_t *rmp;
+  ip4_main_t *im = &ip4_main;
+  u32 vrf_id;
 
   q = vl_api_client_index_to_input_queue (mp->client_index);
   if (!q)
@@ -7751,20 +7952,191 @@ vl_api_ipfix_dump_t_handler (vl_api_ipfix_dump_t * mp)
 
   rmp = vl_msg_api_alloc (sizeof (*rmp));
   memset (rmp, 0, sizeof (*rmp));
-  rmp->_vl_msg_id = ntohs (VL_API_IPFIX_DETAILS);
+  rmp->_vl_msg_id = ntohs (VL_API_IPFIX_EXPORTER_DETAILS);
   rmp->context = mp->context;
   memcpy (rmp->collector_address, frm->ipfix_collector.data,
          sizeof (frm->ipfix_collector.data));
   rmp->collector_port = htons (frm->collector_port);
   memcpy (rmp->src_address, frm->src_address.data,
          sizeof (frm->src_address.data));
-  rmp->fib_index = htonl (frm->fib_index);
+  if (frm->fib_index == ~0)
+    vrf_id = ~0;
+  else
+    vrf_id = im->fibs[frm->fib_index].ft_table_id;
+  rmp->vrf_id = htonl (vrf_id);
   rmp->path_mtu = htonl (frm->path_mtu);
   rmp->template_interval = htonl (frm->template_interval);
+  rmp->udp_checksum = (frm->udp_checksum != 0);
+
+  vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+static void
+  vl_api_set_ipfix_classify_stream_t_handler
+  (vl_api_set_ipfix_classify_stream_t * mp)
+{
+  vl_api_set_ipfix_classify_stream_reply_t *rmp;
+  flow_report_classify_main_t *fcm = &flow_report_classify_main;
+  flow_report_main_t *frm = &flow_report_main;
+  u32 domain_id = 0;
+  u32 src_port = UDP_DST_PORT_ipfix;
+  int rv = 0;
+
+  domain_id = ntohl (mp->domain_id);
+  src_port = ntohs (mp->src_port);
+
+  if (fcm->src_port != 0 &&
+      (fcm->domain_id != domain_id || fcm->src_port != (u16) src_port))
+    {
+      int rv = vnet_stream_change (frm, fcm->domain_id, fcm->src_port,
+                                  domain_id, (u16) src_port);
+      ASSERT (rv == 0);
+    }
+
+  fcm->domain_id = domain_id;
+  fcm->src_port = (u16) src_port;
+
+  REPLY_MACRO (VL_API_SET_IPFIX_CLASSIFY_STREAM_REPLY);
+}
+
+static void
+  vl_api_ipfix_classify_stream_dump_t_handler
+  (vl_api_ipfix_classify_stream_dump_t * mp)
+{
+  flow_report_classify_main_t *fcm = &flow_report_classify_main;
+  unix_shared_memory_queue_t *q;
+  vl_api_ipfix_classify_stream_details_t *rmp;
+
+  q = vl_api_client_index_to_input_queue (mp->client_index);
+  if (!q)
+    return;
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id = ntohs (VL_API_IPFIX_CLASSIFY_STREAM_DETAILS);
+  rmp->context = mp->context;
+  rmp->domain_id = htonl (fcm->domain_id);
+  rmp->src_port = htons (fcm->src_port);
 
   vl_msg_api_send_shmem (q, (u8 *) & rmp);
 }
 
+static void
+  vl_api_ipfix_classify_table_add_del_t_handler
+  (vl_api_ipfix_classify_table_add_del_t * mp)
+{
+  vl_api_ipfix_classify_table_add_del_reply_t *rmp;
+  flow_report_classify_main_t *fcm = &flow_report_classify_main;
+  flow_report_main_t *frm = &flow_report_main;
+  vnet_flow_report_add_del_args_t args;
+  ipfix_classify_table_t *table;
+  int is_add;
+  u32 classify_table_index;
+  u8 ip_version;
+  u8 transport_protocol;
+  int rv = 0;
+
+  classify_table_index = ntohl (mp->table_id);
+  ip_version = mp->ip_version;
+  transport_protocol = mp->transport_protocol;
+  is_add = mp->is_add;
+
+  if (fcm->src_port == 0)
+    {
+      /* call set_ipfix_classify_stream first */
+      rv = VNET_API_ERROR_UNSPECIFIED;
+      goto out;
+    }
+
+  memset (&args, 0, sizeof (args));
+
+  table = 0;
+  int i;
+  for (i = 0; i < vec_len (fcm->tables); i++)
+    if (ipfix_classify_table_index_valid (i))
+      if (fcm->tables[i].classify_table_index == classify_table_index)
+       {
+         table = &fcm->tables[i];
+         break;
+       }
+
+  if (is_add)
+    {
+      if (table)
+       {
+         rv = VNET_API_ERROR_VALUE_EXIST;
+         goto out;
+       }
+      table = ipfix_classify_add_table ();
+      table->classify_table_index = classify_table_index;
+    }
+  else
+    {
+      if (!table)
+       {
+         rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+         goto out;
+       }
+    }
+
+  table->ip_version = ip_version;
+  table->transport_protocol = transport_protocol;
+
+  args.opaque.as_uword = table - fcm->tables;
+  args.rewrite_callback = ipfix_classify_template_rewrite;
+  args.flow_data_callback = ipfix_classify_send_flows;
+  args.is_add = is_add;
+  args.domain_id = fcm->domain_id;
+  args.src_port = fcm->src_port;
+
+  rv = vnet_flow_report_add_del (frm, &args);
+
+  /* If deleting, or add failed */
+  if (is_add == 0 || (rv && is_add))
+    ipfix_classify_delete_table (table - fcm->tables);
+
+out:
+  REPLY_MACRO (VL_API_SET_IPFIX_CLASSIFY_STREAM_REPLY);
+}
+
+static void
+send_ipfix_classify_table_details (u32 table_index,
+                                  unix_shared_memory_queue_t * q,
+                                  u32 context)
+{
+  flow_report_classify_main_t *fcm = &flow_report_classify_main;
+  vl_api_ipfix_classify_table_details_t *mp;
+
+  ipfix_classify_table_t *table = &fcm->tables[table_index];
+
+  mp = vl_msg_api_alloc (sizeof (*mp));
+  memset (mp, 0, sizeof (*mp));
+  mp->_vl_msg_id = ntohs (VL_API_IPFIX_CLASSIFY_TABLE_DETAILS);
+  mp->context = context;
+  mp->table_id = htonl (table->classify_table_index);
+  mp->ip_version = table->ip_version;
+  mp->transport_protocol = table->transport_protocol;
+
+  vl_msg_api_send_shmem (q, (u8 *) & mp);
+}
+
+static void
+  vl_api_ipfix_classify_table_dump_t_handler
+  (vl_api_ipfix_classify_table_dump_t * mp)
+{
+  flow_report_classify_main_t *fcm = &flow_report_classify_main;
+  unix_shared_memory_queue_t *q;
+  u32 i;
+
+  q = vl_api_client_index_to_input_queue (mp->client_index);
+  if (!q)
+    return;
+
+  for (i = 0; i < vec_len (fcm->tables); i++)
+    if (ipfix_classify_table_index_valid (i))
+      send_ipfix_classify_table_details (i, q, mp->context);
+}
+
 static void
 vl_api_pg_create_interface_t_handler (vl_api_pg_create_interface_t * mp)
 {
@@ -8085,6 +8457,53 @@ static void vl_api_ipsec_gre_tunnel_dump_t_handler
     }
 }
 
+static void
+vl_api_delete_subif_t_handler (vl_api_delete_subif_t * mp)
+{
+  vl_api_delete_subif_reply_t *rmp;
+  int rv;
+
+  rv = vnet_delete_sub_interface (ntohl (mp->sw_if_index));
+
+  REPLY_MACRO (VL_API_DELETE_SUBIF_REPLY);
+}
+
+static void
+  vl_api_l2_interface_pbb_tag_rewrite_t_handler
+  (vl_api_l2_interface_pbb_tag_rewrite_t * mp)
+{
+  vl_api_l2_interface_pbb_tag_rewrite_reply_t *rmp;
+  vnet_main_t *vnm = vnet_get_main ();
+  vlib_main_t *vm = vlib_get_main ();
+  u32 vtr_op;
+  int rv = 0;
+
+  VALIDATE_SW_IF_INDEX (mp);
+
+  vtr_op = ntohl (mp->vtr_op);
+
+  switch (vtr_op)
+    {
+    case L2_VTR_DISABLED:
+    case L2_VTR_PUSH_2:
+    case L2_VTR_POP_2:
+    case L2_VTR_TRANSLATE_2_1:
+      break;
+
+    default:
+      rv = VNET_API_ERROR_INVALID_VALUE;
+      goto bad_sw_if_index;
+    }
+
+  rv = l2pbb_configure (vm, vnm, ntohl (mp->sw_if_index), vtr_op,
+                       mp->b_dmac, mp->b_smac, ntohs (mp->b_vlanid),
+                       ntohl (mp->i_sid), ntohs (mp->outer_tag));
+
+  BAD_SW_IF_INDEX_LABEL;
+
+  REPLY_MACRO (VL_API_L2_INTERFACE_PBB_TAG_REWRITE_REPLY);
+}
+
 #define BOUNCE_HANDLER(nn)                                              \
 static void vl_api_##nn##_t_handler (                                   \
     vl_api_##nn##_t *mp)                                                \
@@ -8352,28 +8771,50 @@ format_arp_event (u8 * s, va_list * args)
 {
   vl_api_ip4_arp_event_t *event = va_arg (*args, vl_api_ip4_arp_event_t *);
 
-  s = format (s, "pid %d: %U", event->pid,
-             format_ip4_address, &event->address);
+  s = format (s, "pid %d: ", event->pid);
+  if (event->mac_ip)
+    s = format (s, "bd mac/ip4 binding events");
+  else
+    s = format (s, "resolution for %U", format_ip4_address, &event->address);
+  return s;
+}
+
+static u8 *
+format_nd_event (u8 * s, va_list * args)
+{
+  vl_api_ip6_nd_event_t *event = va_arg (*args, vl_api_ip6_nd_event_t *);
+
+  s = format (s, "pid %d: ", event->pid);
+  if (event->mac_ip)
+    s = format (s, "bd mac/ip6 binding events");
+  else
+    s = format (s, "resolution for %U", format_ip6_address, event->address);
   return s;
 }
 
 static clib_error_t *
-show_ip4_arp_events_fn (vlib_main_t * vm,
-                       unformat_input_t * input, vlib_cli_command_t * cmd)
+show_ip_arp_nd_events_fn (vlib_main_t * vm,
+                         unformat_input_t * input, vlib_cli_command_t * cmd)
 {
   vpe_api_main_t *am = &vpe_api_main;
-  vl_api_ip4_arp_event_t *event;
+  vl_api_ip4_arp_event_t *arp_event;
+  vl_api_ip6_nd_event_t *nd_event;
 
-  if (pool_elts (am->arp_events) == 0)
+  if ((pool_elts (am->arp_events) == 0) && (pool_elts (am->nd_events) == 0))
     {
-      vlib_cli_output (vm, "No active arp event registrations");
+      vlib_cli_output (vm, "No active arp or nd event registrations");
       return 0;
     }
 
   /* *INDENT-OFF* */
-  pool_foreach (event, am->arp_events,
+  pool_foreach (arp_event, am->arp_events,
+  ({
+    vlib_cli_output (vm, "%U", format_arp_event, arp_event);
+  }));
+
+  pool_foreach (nd_event, am->nd_events,
   ({
-    vlib_cli_output (vm, "%U", format_arp_event, event);
+    vlib_cli_output (vm, "%U", format_nd_event, nd_event);
   }));
   /* *INDENT-ON* */
 
@@ -8381,10 +8822,10 @@ show_ip4_arp_events_fn (vlib_main_t * vm,
 }
 
 /* *INDENT-OFF* */
-VLIB_CLI_COMMAND (show_ip4_arp_events, static) = {
-  .path = "show arp event registrations",
-  .function = show_ip4_arp_events_fn,
-  .short_help = "Show arp event registrations",
+VLIB_CLI_COMMAND (show_ip_arp_nd_events, static) = {
+  .path = "show arp-nd-event registrations",
+  .function = show_ip_arp_nd_events_fn,
+  .short_help = "Show ip4 arp and ip6 nd event registrations",
 };
 /* *INDENT-ON* */