vnet: store hw interface speed in kbps instead of using flags
[vpp.git] / src / vnet / interface.c
index 2a1e70e..37f27ea 100644 (file)
 #include <vnet/plugin/plugin.h>
 #include <vnet/fib/ip6_fib.h>
 #include <vnet/adj/adj.h>
+#include <vnet/adj/adj_mcast.h>
+#include <vnet/l2/l2_input.h>
 
-#define VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE (1 << 0)
-#define VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE (1 << 1)
+typedef enum vnet_interface_helper_flags_t_
+{
+  VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE = (1 << 0),
+  VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE = (1 << 1),
+} vnet_interface_helper_flags_t;
 
 static clib_error_t *vnet_hw_interface_set_flags_helper (vnet_main_t * vnm,
                                                         u32 hw_if_index,
-                                                        u32 flags,
-                                                        u32 helper_flags);
+                                                        vnet_hw_interface_flags_t
+                                                        flags,
+                                                        vnet_interface_helper_flags_t
+                                                        helper_flags);
 
 static clib_error_t *vnet_sw_interface_set_flags_helper (vnet_main_t * vnm,
                                                         u32 sw_if_index,
-                                                        u32 flags,
-                                                        u32 helper_flags);
+                                                        vnet_sw_interface_flags_t
+                                                        flags,
+                                                        vnet_interface_helper_flags_t
+                                                        helper_flags);
 
 static clib_error_t *vnet_hw_interface_set_class_helper (vnet_main_t * vnm,
                                                         u32 hw_if_index,
@@ -100,52 +109,17 @@ unserialize_vec_vnet_sw_hw_interface_state (serialize_main_t * m,
     }
 }
 
-static void
-serialize_vnet_sw_hw_interface_set_flags (serialize_main_t * m, va_list * va)
-{
-  vnet_sw_hw_interface_state_t *s =
-    va_arg (*va, vnet_sw_hw_interface_state_t *);
-  serialize (m, serialize_vec_vnet_sw_hw_interface_state, s, 1);
-}
-
-static void
-unserialize_vnet_sw_interface_set_flags (serialize_main_t * m, va_list * va)
-{
-  CLIB_UNUSED (mc_main_t * mc) = va_arg (*va, mc_main_t *);
-  vnet_sw_hw_interface_state_t s;
-
-  unserialize (m, unserialize_vec_vnet_sw_hw_interface_state, &s, 1);
-
-  vnet_sw_interface_set_flags_helper
-    (vnet_get_main (), s.sw_hw_if_index, s.flags,
-     /* helper_flags no redistribution */ 0);
-}
-
-static void
-unserialize_vnet_hw_interface_set_flags (serialize_main_t * m, va_list * va)
+static vnet_sw_interface_flags_t
+vnet_hw_interface_flags_to_sw (vnet_hw_interface_flags_t hwf)
 {
-  CLIB_UNUSED (mc_main_t * mc) = va_arg (*va, mc_main_t *);
-  vnet_sw_hw_interface_state_t s;
+  vnet_sw_interface_flags_t swf = VNET_SW_INTERFACE_FLAG_NONE;
 
-  unserialize (m, unserialize_vec_vnet_sw_hw_interface_state, &s, 1);
+  if (hwf & VNET_HW_INTERFACE_FLAG_LINK_UP)
+    swf |= VNET_SW_INTERFACE_FLAG_ADMIN_UP;
 
-  vnet_hw_interface_set_flags_helper
-    (vnet_get_main (), s.sw_hw_if_index, s.flags,
-     /* helper_flags no redistribution */ 0);
+  return (swf);
 }
 
-MC_SERIALIZE_MSG (vnet_sw_interface_set_flags_msg, static) =
-{
-.name = "vnet_sw_interface_set_flags",.serialize =
-    serialize_vnet_sw_hw_interface_set_flags,.unserialize =
-    unserialize_vnet_sw_interface_set_flags,};
-
-MC_SERIALIZE_MSG (vnet_hw_interface_set_flags_msg, static) =
-{
-.name = "vnet_hw_interface_set_flags",.serialize =
-    serialize_vnet_sw_hw_interface_set_flags,.unserialize =
-    unserialize_vnet_hw_interface_set_flags,};
-
 void
 serialize_vnet_interface_state (serialize_main_t * m, va_list * va)
 {
@@ -187,7 +161,7 @@ serialize_vnet_interface_state (serialize_main_t * m, va_list * va)
       {
        vec_add2 (sts, st, 1);
        st->sw_hw_if_index = hif->hw_if_index;
-       st->flags = hif->flags;
+       st->flags = vnet_hw_interface_flags_to_sw(hif->flags);
       }
   }));
   /* *INDENT-ON* */
@@ -197,6 +171,17 @@ serialize_vnet_interface_state (serialize_main_t * m, va_list * va)
   vec_free (sts);
 }
 
+static vnet_hw_interface_flags_t
+vnet_sw_interface_flags_to_hw (vnet_sw_interface_flags_t swf)
+{
+  vnet_hw_interface_flags_t hwf = VNET_HW_INTERFACE_FLAG_NONE;
+
+  if (swf & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
+    hwf |= VNET_HW_INTERFACE_FLAG_LINK_UP;
+
+  return (hwf);
+}
+
 void
 unserialize_vnet_interface_state (serialize_main_t * m, va_list * va)
 {
@@ -232,8 +217,11 @@ unserialize_vnet_interface_state (serialize_main_t * m, va_list * va)
 
   vec_unserialize (m, &sts, unserialize_vec_vnet_sw_hw_interface_state);
   vec_foreach (st, sts)
-    vnet_hw_interface_set_flags_helper (vnm, st->sw_hw_if_index, st->flags,
-                                       /* no distribute */ 0);
+  {
+    vnet_hw_interface_set_flags_helper
+      (vnm, st->sw_hw_if_index, vnet_sw_interface_flags_to_hw (st->flags),
+       /* no distribute */ 0);
+  }
   vec_free (sts);
 }
 
@@ -304,22 +292,20 @@ call_sw_interface_add_del_callbacks (vnet_main_t * vnm, u32 sw_if_index,
 
 static clib_error_t *
 vnet_hw_interface_set_flags_helper (vnet_main_t * vnm, u32 hw_if_index,
-                                   u32 flags, u32 helper_flags)
+                                   vnet_hw_interface_flags_t flags,
+                                   vnet_interface_helper_flags_t
+                                   helper_flags)
 {
   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
   vnet_hw_interface_class_t *hw_class =
     vnet_get_hw_interface_class (vnm, hi->hw_class_index);
-  vnet_device_class_t *dev_class =
-    vnet_get_device_class (vnm, hi->dev_class_index);
-  vlib_main_t *vm = vnm->vlib_main;
   u32 mask;
   clib_error_t *error = 0;
   u32 is_create =
     (helper_flags & VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE) != 0;
 
   mask =
-    (VNET_HW_INTERFACE_FLAG_LINK_UP | VNET_HW_INTERFACE_FLAG_DUPLEX_MASK |
-     VNET_HW_INTERFACE_FLAG_SPEED_MASK);
+    (VNET_HW_INTERFACE_FLAG_LINK_UP | VNET_HW_INTERFACE_FLAG_DUPLEX_MASK);
   flags &= mask;
 
   /* Call hardware interface add/del callbacks. */
@@ -330,19 +316,6 @@ vnet_hw_interface_set_flags_helper (vnet_main_t * vnm, u32 hw_if_index,
   if (!is_create && (hi->flags & mask) == flags)
     goto done;
 
-  /* Some interface classes do not redistribute (e.g. are local). */
-  if (!dev_class->redistribute)
-    helper_flags &= ~VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE;
-
-  if (vm->mc_main
-      && (helper_flags & VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE))
-    {
-      vnet_sw_hw_interface_state_t s;
-      s.sw_hw_if_index = hw_if_index;
-      s.flags = flags;
-      mc_serialize (vm->mc_main, &vnet_hw_interface_set_flags_msg, &s);
-    }
-
   if ((hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) !=
       (flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
     {
@@ -368,10 +341,11 @@ done:
 
 static clib_error_t *
 vnet_sw_interface_set_flags_helper (vnet_main_t * vnm, u32 sw_if_index,
-                                   u32 flags, u32 helper_flags)
+                                   vnet_sw_interface_flags_t flags,
+                                   vnet_interface_helper_flags_t
+                                   helper_flags)
 {
   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
-  vlib_main_t *vm = vnm->vlib_main;
   u32 mask;
   clib_error_t *error = 0;
   u32 is_create =
@@ -423,7 +397,7 @@ vnet_sw_interface_set_flags_helper (vnet_main_t * vnm, u32 sw_if_index,
            }
        }
 
-      /* Donot change state for slave link of bonded interfaces */
+      /* Do not change state for slave link of bonded interfaces */
       if (si->flags & VNET_SW_INTERFACE_FLAG_BOND_SLAVE)
        {
          error = clib_error_return
@@ -449,16 +423,6 @@ vnet_sw_interface_set_flags_helper (vnet_main_t * vnm, u32 sw_if_index,
              ~VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE;
        }
 
-      if (vm->mc_main
-         && (helper_flags &
-             VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE))
-       {
-         vnet_sw_hw_interface_state_t s;
-         s.sw_hw_if_index = sw_if_index;
-         s.flags = flags;
-         mc_serialize (vm->mc_main, &vnet_sw_interface_set_flags_msg, &s);
-       }
-
       /* set the flags now before invoking the registered clients
        * so that the state they query is consistent with the state here notified */
       old_flags = si->flags;
@@ -468,10 +432,13 @@ vnet_sw_interface_set_flags_helper (vnet_main_t * vnm, u32 sw_if_index,
        error = call_elf_section_interface_callbacks
          (vnm, sw_if_index, flags,
           vnm->sw_interface_admin_up_down_functions);
-      si->flags = old_flags;
 
       if (error)
-       goto done;
+       {
+         /* restore flags on error */
+         si->flags = old_flags;
+         goto done;
+       }
 
       if (si->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
        {
@@ -482,6 +449,13 @@ vnet_sw_interface_set_flags_helper (vnet_main_t * vnm, u32 sw_if_index,
          vnet_device_class_t *dev_class =
            vnet_get_device_class (vnm, hi->dev_class_index);
 
+         if ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) &&
+             (si->flags & VNET_SW_INTERFACE_FLAG_ERROR))
+           {
+             error = clib_error_return (0, "Interface in the error state");
+             goto done;
+           }
+
          /* save the si admin up flag */
          old_flags = si->flags;
 
@@ -527,7 +501,8 @@ done:
 }
 
 clib_error_t *
-vnet_hw_interface_set_flags (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
+vnet_hw_interface_set_flags (vnet_main_t * vnm, u32 hw_if_index,
+                            vnet_hw_interface_flags_t flags)
 {
   return vnet_hw_interface_set_flags_helper
     (vnm, hw_if_index, flags,
@@ -535,7 +510,8 @@ vnet_hw_interface_set_flags (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
 }
 
 clib_error_t *
-vnet_sw_interface_set_flags (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
+vnet_sw_interface_set_flags (vnet_main_t * vnm, u32 sw_if_index,
+                            vnet_sw_interface_flags_t flags)
 {
   return vnet_sw_interface_set_flags_helper
     (vnm, sw_if_index, flags,
@@ -638,11 +614,13 @@ vnet_delete_sw_interface (vnet_main_t * vnm, u32 sw_if_index)
     {
       config = vec_elt_at_index (l2input_main.configs, sw_if_index);
       if (config->xconnect)
-       set_int_l2_mode (vm, vnm, MODE_L3, config->output_sw_if_index, 0, 0,
-                        0, 0);
+       set_int_l2_mode (vm, vnm, MODE_L3, config->output_sw_if_index, 0,
+                        L2_BD_PORT_TYPE_NORMAL, 0, 0);
       if (config->xconnect || config->bridge)
-       set_int_l2_mode (vm, vnm, MODE_L3, sw_if_index, 0, 0, 0, 0);
+       set_int_l2_mode (vm, vnm, MODE_L3, sw_if_index, 0,
+                        L2_BD_PORT_TYPE_NORMAL, 0, 0);
     }
+  vnet_clear_sw_interface_tag (vnm, sw_if_index);
 
   /* Bring down interface in case it is up. */
   if (sw->flags != 0)
@@ -653,6 +631,87 @@ vnet_delete_sw_interface (vnet_main_t * vnm, u32 sw_if_index)
   pool_put (im->sw_interfaces, sw);
 }
 
+static clib_error_t *
+call_sw_interface_mtu_change_callbacks (vnet_main_t * vnm, u32 sw_if_index)
+{
+  return call_elf_section_interface_callbacks
+    (vnm, sw_if_index, 0, vnm->sw_interface_mtu_change_functions);
+}
+
+void
+vnet_sw_interface_set_mtu (vnet_main_t * vnm, u32 sw_if_index, u32 mtu)
+{
+  vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
+
+  if (si->mtu[VNET_MTU_L3] != mtu)
+    {
+      si->mtu[VNET_MTU_L3] = mtu;
+      call_sw_interface_mtu_change_callbacks (vnm, sw_if_index);
+    }
+}
+
+void
+vnet_sw_interface_set_protocol_mtu (vnet_main_t * vnm, u32 sw_if_index,
+                                   u32 mtu[])
+{
+  vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
+  bool changed = false;
+  int i;
+
+  for (i = 0; i < VNET_N_MTU; i++)
+    {
+      if (si->mtu[i] != mtu[i])
+       {
+         si->mtu[i] = mtu[i];
+         changed = true;
+       }
+    }
+  /* Notify interested parties */
+  if (changed)
+    call_sw_interface_mtu_change_callbacks (vnm, sw_if_index);
+}
+
+void
+vnet_sw_interface_ip_directed_broadcast (vnet_main_t * vnm,
+                                        u32 sw_if_index, u8 enable)
+{
+  vnet_sw_interface_t *si;
+
+  si = vnet_get_sw_interface (vnm, sw_if_index);
+
+  if (enable)
+    si->flags |= VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST;
+  else
+    si->flags &= ~VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST;
+
+  ip4_directed_broadcast (sw_if_index, enable);
+}
+
+/*
+ * Reflect a change in hardware MTU on protocol MTUs
+ */
+static walk_rc_t
+sw_interface_walk_callback (vnet_main_t * vnm, u32 sw_if_index, void *ctx)
+{
+  u32 *link_mtu = ctx;
+  vnet_sw_interface_set_mtu (vnm, sw_if_index, *link_mtu);
+  return WALK_CONTINUE;
+}
+
+void
+vnet_hw_interface_set_mtu (vnet_main_t * vnm, u32 hw_if_index, u32 mtu)
+{
+  vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
+
+  if (hi->max_packet_bytes != mtu)
+    {
+      hi->max_packet_bytes = mtu;
+      ethernet_set_flags (vnm, hw_if_index, ETHERNET_INTERFACE_FLAG_MTU);
+      vnet_hw_interface_walk_sw (vnm, hw_if_index, sw_interface_walk_callback,
+                                &mtu);
+    }
+}
+
 static void
 setup_tx_node (vlib_main_t * vm,
               u32 node_index, vnet_device_class_t * dev_class)
@@ -693,12 +752,14 @@ vnet_register_interface (vnet_main_t * vnm,
   vnet_feature_config_main_t *fcm;
   vnet_config_main_t *cm;
   u32 hw_index, i;
-  char *tx_node_name, *output_node_name;
+  char *tx_node_name = NULL, *output_node_name = NULL;
 
   pool_get (im->hw_interfaces, hw);
+  clib_memset (hw, 0, sizeof (*hw));
 
   hw_index = hw - im->hw_interfaces;
   hw->hw_if_index = hw_index;
+  hw->default_rx_mode = VNET_HW_INTERFACE_RX_MODE_POLLING;
 
   if (dev_class->format_device_name)
     hw->name = format (0, "%U", dev_class->format_device_name, dev_instance);
@@ -732,9 +793,10 @@ vnet_register_interface (vnet_main_t * vnm,
 
   hw->max_rate_bits_per_sec = 0;
   hw->min_packet_bytes = 0;
-  hw->per_packet_overhead_bytes = 0;
-  hw->max_l3_packet_bytes[VLIB_RX] = ~0;
-  hw->max_l3_packet_bytes[VLIB_TX] = ~0;
+  vnet_sw_interface_set_mtu (vnm, hw->sw_if_index, 0);
+
+  if (dev_class->tx_function == 0)
+    goto no_output_nodes;      /* No output/tx nodes to create */
 
   tx_node_name = (char *) format (0, "%v-tx", hw->name);
   output_node_name = (char *) format (0, "%v-output", hw->name);
@@ -743,7 +805,6 @@ vnet_register_interface (vnet_main_t * vnm,
   if (vec_len (im->deleted_hw_interface_nodes) > 0)
     {
       vnet_hw_interface_nodes_t *hn;
-      vnet_interface_output_runtime_t *rt;
       vlib_node_t *node;
       vlib_node_runtime_t *nrt;
 
@@ -755,35 +816,46 @@ vnet_register_interface (vnet_main_t * vnm,
       vlib_node_rename (vm, hw->tx_node_index, "%v", tx_node_name);
       vlib_node_rename (vm, hw->output_node_index, "%v", output_node_name);
 
-      rt = vlib_node_get_runtime_data (vm, hw->output_node_index);
-      ASSERT (rt->is_deleted == 1);
-      rt->is_deleted = 0;
-      rt->hw_if_index = hw_index;
-      rt->sw_if_index = hw->sw_if_index;
-      rt->dev_instance = hw->dev_instance;
+      /* *INDENT-OFF* */
+      foreach_vlib_main ({
+        vnet_interface_output_runtime_t *rt;
 
-      rt = vlib_node_get_runtime_data (vm, hw->tx_node_index);
-      rt->hw_if_index = hw_index;
-      rt->sw_if_index = hw->sw_if_index;
-      rt->dev_instance = hw->dev_instance;
+       rt = vlib_node_get_runtime_data (this_vlib_main, hw->output_node_index);
+       ASSERT (rt->is_deleted == 1);
+       rt->is_deleted = 0;
+       rt->hw_if_index = hw_index;
+       rt->sw_if_index = hw->sw_if_index;
+       rt->dev_instance = hw->dev_instance;
+
+       rt = vlib_node_get_runtime_data (this_vlib_main, hw->tx_node_index);
+       rt->hw_if_index = hw_index;
+       rt->sw_if_index = hw->sw_if_index;
+       rt->dev_instance = hw->dev_instance;
+      });
+      /* *INDENT-ON* */
 
       /* The new class may differ from the old one.
        * Functions have to be updated. */
       node = vlib_get_node (vm, hw->output_node_index);
-      node->function = dev_class->flatten_output_chains ?
-       vnet_interface_output_node_flatten_multiarch_select () :
-       vnet_interface_output_node_multiarch_select ();
+      node->function = vnet_interface_output_node_multiarch_select ();
       node->format_trace = format_vnet_interface_output_trace;
-      nrt = vlib_node_get_runtime (vm, hw->output_node_index);
-      nrt->function = node->function;
+      /* *INDENT-OFF* */
+      foreach_vlib_main ({
+        nrt = vlib_node_get_runtime (this_vlib_main, hw->output_node_index);
+        nrt->function = node->function;
+      });
+      /* *INDENT-ON* */
 
       node = vlib_get_node (vm, hw->tx_node_index);
       node->function = dev_class->tx_function;
       node->format_trace = dev_class->format_tx_trace;
-      nrt = vlib_node_get_runtime (vm, hw->tx_node_index);
-      nrt->function = node->function;
+      /* *INDENT-OFF* */
+      foreach_vlib_main ({
+        nrt = vlib_node_get_runtime (this_vlib_main, hw->tx_node_index);
+        nrt->function = node->function;
+      });
+      /* *INDENT-ON* */
 
-      vlib_worker_thread_node_runtime_update ();
       _vec_len (im->deleted_hw_interface_nodes) -= 1;
     }
   else
@@ -796,7 +868,7 @@ vnet_register_interface (vnet_main_t * vnm,
        .is_deleted = 0,
       };
 
-      memset (&r, 0, sizeof (r));
+      clib_memset (&r, 0, sizeof (r));
       r.type = VLIB_NODE_TYPE_INTERNAL;
       r.runtime_data = &rt;
       r.runtime_data_bytes = sizeof (rt);
@@ -815,9 +887,7 @@ vnet_register_interface (vnet_main_t * vnm,
 
       r.flags = 0;
       r.name = output_node_name;
-      r.function = dev_class->flatten_output_chains ?
-       vnet_interface_output_node_flatten_multiarch_select () :
-       vnet_interface_output_node_multiarch_select ();
+      r.function = vnet_interface_output_node_multiarch_select ();
       r.format_trace = format_vnet_interface_output_trace;
 
       {
@@ -864,11 +934,14 @@ vnet_register_interface (vnet_main_t * vnm,
   setup_output_node (vm, hw->output_node_index, hw_class);
   setup_tx_node (vm, hw->tx_node_index, dev_class);
 
+no_output_nodes:
   /* Call all up/down callbacks with zero flags when interface is created. */
   vnet_sw_interface_set_flags_helper (vnm, hw->sw_if_index, /* flags */ 0,
                                      VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE);
   vnet_hw_interface_set_flags_helper (vnm, hw_index, /* flags */ 0,
                                      VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE);
+  vec_free (tx_node_name);
+  vec_free (output_node_name);
 
   return hw_index;
 }
@@ -879,7 +952,8 @@ vnet_delete_hw_interface (vnet_main_t * vnm, u32 hw_if_index)
   vnet_interface_main_t *im = &vnm->interface_main;
   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
   vlib_main_t *vm = vnm->vlib_main;
-
+  vnet_device_class_t *dev_class = vnet_get_device_class (vnm,
+                                                         hw->dev_class_index);
   /* If it is up, mark it down. */
   if (hw->flags != 0)
     vnet_hw_interface_set_flags (vnm, hw_if_index, /* flags */ 0);
@@ -887,38 +961,56 @@ vnet_delete_hw_interface (vnet_main_t * vnm, u32 hw_if_index)
   /* Call delete callbacks. */
   call_hw_interface_add_del_callbacks (vnm, hw_if_index, /* is_create */ 0);
 
-  /* Delete software interface corresponding to hardware interface. */
-  vnet_delete_sw_interface (vnm, hw->sw_if_index);
-
   /* Delete any sub-interfaces. */
   {
     u32 id, sw_if_index;
     /* *INDENT-OFF* */
-    hash_foreach (id, sw_if_index, hw->sub_interface_sw_if_index_by_id, ({
+    hash_foreach (id, sw_if_index, hw->sub_interface_sw_if_index_by_id,
+    ({
+      vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
+      u64 sup_and_sub_key =
+       ((u64) (si->sup_sw_if_index) << 32) | (u64) si->sub.id;
+      hash_unset_mem_free (&im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
       vnet_delete_sw_interface (vnm, sw_if_index);
     }));
+    hash_free (hw->sub_interface_sw_if_index_by_id);
     /* *INDENT-ON* */
   }
 
-  {
-    vnet_hw_interface_nodes_t *dn;
-    vnet_interface_output_runtime_t *rt =
-      vlib_node_get_runtime_data (vm, hw->output_node_index);
-
-    /* Mark node runtime as deleted so output node (if called) will drop packets. */
-    rt->is_deleted = 1;
-
-    vlib_node_rename (vm, hw->output_node_index,
-                     "interface-%d-output-deleted", hw_if_index);
-    vlib_node_rename (vm, hw->tx_node_index, "interface-%d-tx-deleted",
-                     hw_if_index);
-    vec_add2 (im->deleted_hw_interface_nodes, dn, 1);
-    dn->tx_node_index = hw->tx_node_index;
-    dn->output_node_index = hw->output_node_index;
-  }
+  /* Delete software interface corresponding to hardware interface. */
+  vnet_delete_sw_interface (vnm, hw->sw_if_index);
+
+  if (dev_class->tx_function)
+    {
+      /* Put output/tx nodes into recycle pool */
+      vnet_hw_interface_nodes_t *dn;
+
+      /* *INDENT-OFF* */
+      foreach_vlib_main
+       ({
+         vnet_interface_output_runtime_t *rt =
+           vlib_node_get_runtime_data (this_vlib_main, hw->output_node_index);
+
+         /* Mark node runtime as deleted so output node (if called)
+          * will drop packets. */
+         rt->is_deleted = 1;
+       });
+      /* *INDENT-ON* */
+
+      vlib_node_rename (vm, hw->output_node_index,
+                       "interface-%d-output-deleted", hw_if_index);
+      vlib_node_rename (vm, hw->tx_node_index, "interface-%d-tx-deleted",
+                       hw_if_index);
+      vec_add2 (im->deleted_hw_interface_nodes, dn, 1);
+      dn->tx_node_index = hw->tx_node_index;
+      dn->output_node_index = hw->output_node_index;
+    }
 
   hash_unset_mem (im->hw_interface_by_name, hw->name);
   vec_free (hw->name);
+  vec_free (hw->hw_address);
+  vec_free (hw->input_node_thread_index_by_queue);
+  vec_free (hw->dq_runtime_index_by_queue);
 
   pool_put (im->hw_interfaces, hw);
 }
@@ -932,53 +1024,55 @@ vnet_hw_interface_walk_sw (vnet_main_t * vnm,
   u32 id, sw_if_index;
 
   hi = vnet_get_hw_interface (vnm, hw_if_index);
-  /* the super first, then the and sub interfaces */
-  fn (vnm, hi->sw_if_index, ctx);
+  /* the super first, then the sub interfaces */
+  if (WALK_STOP == fn (vnm, hi->sw_if_index, ctx))
+    return;
 
   /* *INDENT-OFF* */
   hash_foreach (id, sw_if_index,
                 hi->sub_interface_sw_if_index_by_id,
   ({
-    fn (vnm, sw_if_index, ctx);
+    if (WALK_STOP == fn (vnm, sw_if_index, ctx))
+      break;
   }));
   /* *INDENT-ON* */
 }
 
-static void
-serialize_vnet_hw_interface_set_class (serialize_main_t * m, va_list * va)
+void
+vnet_hw_interface_walk (vnet_main_t * vnm,
+                       vnet_hw_interface_walk_t fn, void *ctx)
 {
-  u32 hw_if_index = va_arg (*va, u32);
-  char *hw_class_name = va_arg (*va, char *);
-  serialize_integer (m, hw_if_index, sizeof (hw_if_index));
-  serialize_cstring (m, hw_class_name);
-}
+  vnet_interface_main_t *im;
+  vnet_hw_interface_t *hi;
 
-static void
-unserialize_vnet_hw_interface_set_class (serialize_main_t * m, va_list * va)
-{
-  CLIB_UNUSED (mc_main_t * mc) = va_arg (*va, mc_main_t *);
-  vnet_main_t *vnm = vnet_get_main ();
-  u32 hw_if_index;
-  char *hw_class_name;
-  uword *p;
-  clib_error_t *error;
+  im = &vnm->interface_main;
 
-  unserialize_integer (m, &hw_if_index, sizeof (hw_if_index));
-  unserialize_cstring (m, &hw_class_name);
-  p =
-    hash_get (vnm->interface_main.hw_interface_class_by_name, hw_class_name);
-  ASSERT (p != 0);
-  error = vnet_hw_interface_set_class_helper (vnm, hw_if_index, p[0],
-                                             /* redistribute */ 0);
-  if (error)
-    clib_error_report (error);
+  /* *INDENT-OFF* */
+  pool_foreach (hi, im->hw_interfaces,
+  ({
+    if (WALK_STOP == fn(vnm, hi->hw_if_index, ctx))
+      break;
+  }));
+  /* *INDENT-ON* */
 }
 
-MC_SERIALIZE_MSG (vnet_hw_interface_set_class_msg, static) =
+void
+vnet_sw_interface_walk (vnet_main_t * vnm,
+                       vnet_sw_interface_walk_t fn, void *ctx)
 {
-.name = "vnet_hw_interface_set_class",.serialize =
-    serialize_vnet_hw_interface_set_class,.unserialize =
-    unserialize_vnet_hw_interface_set_class,};
+  vnet_interface_main_t *im;
+  vnet_sw_interface_t *si;
+
+  im = &vnm->interface_main;
+
+  /* *INDENT-OFF* */
+  pool_foreach (si, im->sw_interfaces,
+  {
+    if (WALK_STOP == fn (vnm, si, ctx))
+      break;
+  });
+  /* *INDENT-ON* */
+}
 
 void
 vnet_hw_interface_init_for_class (vnet_main_t * vnm, u32 hw_if_index,
@@ -1031,13 +1125,6 @@ vnet_hw_interface_set_class_helper (vnet_main_t * vnm, u32 hw_if_index,
                                  "%v class cannot be changed from %s to %s",
                                  hi->name, old_class->name, new_class->name);
 
-      if (vnm->vlib_main->mc_main)
-       {
-         mc_serialize (vnm->vlib_main->mc_main,
-                       &vnet_hw_interface_set_class_msg, hw_if_index,
-                       new_class->name);
-         return 0;
-       }
     }
 
   if (old_class->hw_class_change)
@@ -1075,11 +1162,6 @@ vnet_hw_interface_rx_redirect_to_node_helper (vnet_main_t * vnm,
   vnet_device_class_t *dev_class = vnet_get_device_class
     (vnm, hi->dev_class_index);
 
-  if (redistribute)
-    {
-      /* $$$$ fixme someday maybe */
-      ASSERT (vnm->vlib_main->mc_main == 0);
-    }
   if (dev_class->rx_redirect_to_node)
     {
       dev_class->rx_redirect_to_node (vnm, hw_if_index, node_index);
@@ -1127,6 +1209,11 @@ vnet_hw_interface_compare (vnet_main_t * vnm,
 int
 vnet_sw_interface_is_p2p (vnet_main_t * vnm, u32 sw_if_index)
 {
+  vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
+  if ((si->type == VNET_SW_INTERFACE_TYPE_P2P) ||
+      (si->type == VNET_SW_INTERFACE_TYPE_PIPE))
+    return 1;
+
   vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
   vnet_hw_interface_class_t *hc =
     vnet_get_hw_interface_class (vnm, hw->hw_class_index);
@@ -1141,6 +1228,7 @@ vnet_interface_init (vlib_main_t * vm)
   vnet_interface_main_t *im = &vnm->interface_main;
   vlib_buffer_t *b = 0;
   vnet_buffer_opaque_t *o = 0;
+  clib_error_t *error;
 
   /*
    * Keep people from shooting themselves in the foot.
@@ -1164,21 +1252,19 @@ vnet_interface_init (vlib_main_t * vm)
   im->sw_if_counter_lock[0] = 1;       /* should be no need */
 
   vec_validate (im->sw_if_counters, VNET_N_SIMPLE_INTERFACE_COUNTER - 1);
-  im->sw_if_counters[VNET_INTERFACE_COUNTER_DROP].name = "drops";
-  im->sw_if_counters[VNET_INTERFACE_COUNTER_PUNT].name = "punts";
-  im->sw_if_counters[VNET_INTERFACE_COUNTER_IP4].name = "ip4";
-  im->sw_if_counters[VNET_INTERFACE_COUNTER_IP6].name = "ip6";
-  im->sw_if_counters[VNET_INTERFACE_COUNTER_RX_NO_BUF].name = "rx-no-buf";
-  im->sw_if_counters[VNET_INTERFACE_COUNTER_RX_MISS].name = "rx-miss";
-  im->sw_if_counters[VNET_INTERFACE_COUNTER_RX_ERROR].name = "rx-error";
-  im->sw_if_counters[VNET_INTERFACE_COUNTER_TX_ERROR].name = "tx-error";
-
-  vec_validate (im->combined_sw_if_counters,
-               VNET_N_COMBINED_INTERFACE_COUNTER - 1);
-  im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_RX].name = "rx";
-  im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX].name = "tx";
-
-  im->sw_if_counter_lock[0] = 0;
+#define _(E,n,p)                                                       \
+  im->sw_if_counters[VNET_INTERFACE_COUNTER_##E].name = #n;            \
+  im->sw_if_counters[VNET_INTERFACE_COUNTER_##E].stat_segment_name = "/" #p "/" #n;
+  foreach_simple_interface_counter_name
+#undef _
+    vec_validate (im->combined_sw_if_counters,
+                 VNET_N_COMBINED_INTERFACE_COUNTER - 1);
+#define _(E,n,p)                                                       \
+  im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_##E].name = #n;   \
+  im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_##E].stat_segment_name = "/" #p "/" #n;
+  foreach_combined_interface_counter_name
+#undef _
+    im->sw_if_counter_lock[0] = 0;
 
   im->device_class_by_name = hash_create_string ( /* size */ 0,
                                                 sizeof (uword));
@@ -1191,6 +1277,27 @@ vnet_interface_init (vlib_main_t * vm)
       {
        c->index = vec_len (im->device_classes);
        hash_set_mem (im->device_class_by_name, c->name, c->index);
+
+       if (c->tx_fn_registrations)
+         {
+           vlib_node_fn_registration_t *fnr = c->tx_fn_registrations;
+           int priority = -1;
+
+           /* to avoid confusion, please remove ".tx_function" statement
+              from VNET_DEVICE_CLASS() if using function candidates */
+           ASSERT (c->tx_function == 0);
+
+           while (fnr)
+             {
+               if (fnr->priority > priority)
+                 {
+                   priority = fnr->priority;
+                   c->tx_function = fnr->function;
+                 }
+               fnr = fnr->next_registration;
+             }
+         }
+
        vec_add1 (im->device_classes, c[0]);
        c = c->next_class_registration;
       }
@@ -1221,15 +1328,17 @@ vnet_interface_init (vlib_main_t * vm)
       }
   }
 
-  {
-    clib_error_t *error;
+  if ((error = vlib_call_init_function (vm, vnet_interface_cli_init)))
+    return error;
 
-    if ((error = vlib_call_init_function (vm, vnet_interface_cli_init)))
-      return error;
+  vnm->interface_tag_by_sw_if_index = hash_create (0, sizeof (uword));
 
+#if VLIB_BUFFER_TRACE_TRAJECTORY > 0
+  if ((error = vlib_call_init_function (vm, trajectory_trace_init)))
     return error;
-  }
-  vnm->interface_tag_by_sw_if_index = hash_create (0, sizeof (uword));
+#endif
+
+  return 0;
 }
 
 VLIB_INIT_FUNCTION (vnet_interface_init);
@@ -1302,19 +1411,22 @@ vnet_rename_interface (vnet_main_t * vnm, u32 hw_if_index, char *new_name)
 
 static clib_error_t *
 vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm,
-                                            u32 hw_if_index, u64 mac_address)
+                                            u32 hw_if_index,
+                                            const u8 * mac_address)
 {
   clib_error_t *error = 0;
   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
 
   if (hi->hw_address)
     {
+      u8 *old_address = vec_dup (hi->hw_address);
       vnet_device_class_t *dev_class =
        vnet_get_device_class (vnm, hi->dev_class_index);
       if (dev_class->mac_addr_change_function)
        {
          error =
-           dev_class->mac_addr_change_function (hi, (char *) &mac_address);
+           dev_class->mac_addr_change_function (hi, old_address,
+                                                mac_address);
        }
       if (!error)
        {
@@ -1323,7 +1435,7 @@ vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm,
          hw_class = vnet_get_hw_interface_class (vnm, hi->hw_class_index);
 
          if (NULL != hw_class->mac_addr_change_function)
-           hw_class->mac_addr_change_function (hi, (char *) &mac_address);
+           hw_class->mac_addr_change_function (hi, old_address, mac_address);
        }
       else
        {
@@ -1331,6 +1443,7 @@ vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm,
            clib_error_return (0,
                               "MAC Address Change is not supported on this interface");
        }
+      vec_free (old_address);
     }
   else
     {
@@ -1344,12 +1457,57 @@ vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm,
 
 clib_error_t *
 vnet_hw_interface_change_mac_address (vnet_main_t * vnm, u32 hw_if_index,
-                                     u64 mac_address)
+                                     const u8 * mac_address)
 {
   return vnet_hw_interface_change_mac_address_helper
     (vnm, hw_if_index, mac_address);
 }
 
+/* update the unnumbered state of an interface*/
+void
+vnet_sw_interface_update_unnumbered (u32 unnumbered_sw_if_index,
+                                    u32 ip_sw_if_index, u8 enable)
+{
+  vnet_main_t *vnm = vnet_get_main ();
+  vnet_sw_interface_t *si;
+  u32 was_unnum;
+
+  si = vnet_get_sw_interface (vnm, unnumbered_sw_if_index);
+  was_unnum = (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED);
+
+  if (enable)
+    {
+      si->flags |= VNET_SW_INTERFACE_FLAG_UNNUMBERED;
+      si->unnumbered_sw_if_index = ip_sw_if_index;
+
+      ip4_main.lookup_main.if_address_pool_index_by_sw_if_index
+       [unnumbered_sw_if_index] =
+       ip4_main.
+       lookup_main.if_address_pool_index_by_sw_if_index[ip_sw_if_index];
+      ip6_main.
+       lookup_main.if_address_pool_index_by_sw_if_index
+       [unnumbered_sw_if_index] =
+       ip6_main.
+       lookup_main.if_address_pool_index_by_sw_if_index[ip_sw_if_index];
+    }
+  else
+    {
+      si->flags &= ~(VNET_SW_INTERFACE_FLAG_UNNUMBERED);
+      si->unnumbered_sw_if_index = (u32) ~ 0;
+
+      ip4_main.lookup_main.if_address_pool_index_by_sw_if_index
+       [unnumbered_sw_if_index] = ~0;
+      ip6_main.lookup_main.if_address_pool_index_by_sw_if_index
+       [unnumbered_sw_if_index] = ~0;
+    }
+
+  if (was_unnum != (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
+    {
+      ip4_sw_interface_enable_disable (unnumbered_sw_if_index, enable);
+      ip6_sw_interface_enable_disable (unnumbered_sw_if_index, enable);
+    }
+}
+
 vnet_l3_packet_type_t
 vnet_link_to_l3_proto (vnet_link_t link)
 {
@@ -1360,7 +1518,7 @@ vnet_link_to_l3_proto (vnet_link_t link)
     case VNET_LINK_IP6:
       return (VNET_L3_PACKET_TYPE_IP6);
     case VNET_LINK_MPLS:
-      return (VNET_L3_PACKET_TYPE_MPLS_UNICAST);
+      return (VNET_L3_PACKET_TYPE_MPLS);
     case VNET_LINK_ARP:
       return (VNET_L3_PACKET_TYPE_ARP);
     case VNET_LINK_ETHERNET:
@@ -1372,6 +1530,22 @@ vnet_link_to_l3_proto (vnet_link_t link)
   return (0);
 }
 
+vnet_mtu_t
+vnet_link_to_mtu (vnet_link_t link)
+{
+  switch (link)
+    {
+    case VNET_LINK_IP4:
+      return (VNET_MTU_IP4);
+    case VNET_LINK_IP6:
+      return (VNET_MTU_IP6);
+    case VNET_LINK_MPLS:
+      return (VNET_MTU_MPLS);
+    default:
+      return (VNET_MTU_L3);
+    }
+}
+
 u8 *
 default_build_rewrite (vnet_main_t * vnm,
                       u32 sw_if_index,
@@ -1383,15 +1557,105 @@ default_build_rewrite (vnet_main_t * vnm,
 void
 default_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
 {
-  u8 *rewrite;
+  ip_adjacency_t *adj;
+
+  adj = adj_get (ai);
+
+  switch (adj->lookup_next_index)
+    {
+    case IP_LOOKUP_NEXT_GLEAN:
+      adj_glean_update_rewrite (ai);
+      break;
+    case IP_LOOKUP_NEXT_ARP:
+    case IP_LOOKUP_NEXT_BCAST:
+      /*
+       * default rewrite in neighbour adj
+       */
+      adj_nbr_update_rewrite
+       (ai,
+        ADJ_NBR_REWRITE_FLAG_COMPLETE,
+        vnet_build_rewrite_for_sw_interface (vnm,
+                                             sw_if_index,
+                                             adj_get_link_type (ai), NULL));
+      break;
+    case IP_LOOKUP_NEXT_MCAST:
+      /*
+       * mcast traffic also uses default rewrite string with no mcast
+       * switch time updates.
+       */
+      adj_mcast_update_rewrite
+       (ai,
+        vnet_build_rewrite_for_sw_interface (vnm,
+                                             sw_if_index,
+                                             adj_get_link_type (ai),
+                                             NULL), 0);
+      break;
+    case IP_LOOKUP_NEXT_DROP:
+    case IP_LOOKUP_NEXT_PUNT:
+    case IP_LOOKUP_NEXT_LOCAL:
+    case IP_LOOKUP_NEXT_REWRITE:
+    case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
+    case IP_LOOKUP_NEXT_MIDCHAIN:
+    case IP_LOOKUP_NEXT_ICMP_ERROR:
+    case IP_LOOKUP_N_NEXT:
+      ASSERT (0);
+      break;
+    }
+}
+
+int collect_detailed_interface_stats_flag = 0;
+
+void
+collect_detailed_interface_stats_flag_set (void)
+{
+  collect_detailed_interface_stats_flag = 1;
+}
 
-  rewrite = vnet_build_rewrite_for_sw_interface (vnm, sw_if_index,
-                                                adj_get_link_type (ai),
-                                                NULL);
+void
+collect_detailed_interface_stats_flag_clear (void)
+{
+  collect_detailed_interface_stats_flag = 0;
+}
 
-  adj_nbr_update_rewrite (ai, ADJ_NBR_REWRITE_FLAG_COMPLETE, rewrite);
+static clib_error_t *
+collect_detailed_interface_stats_cli (vlib_main_t * vm,
+                                     unformat_input_t * input,
+                                     vlib_cli_command_t * cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  clib_error_t *error = NULL;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return clib_error_return (0, "expected enable | disable");
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "enable") || unformat (line_input, "on"))
+       collect_detailed_interface_stats_flag_set ();
+      else if (unformat (line_input, "disable")
+              || unformat (line_input, "off"))
+       collect_detailed_interface_stats_flag_clear ();
+      else
+       {
+         error = clib_error_return (0, "unknown input `%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+done:
+  unformat_free (line_input);
+  return error;
 }
 
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (collect_detailed_interface_stats_command, static) = {
+  .path = "interface collect detailed-stats",
+  .short_help = "interface collect detailed-stats <enable|disable>",
+  .function = collect_detailed_interface_stats_cli,
+};
+/* *INDENT-ON* */
 
 /*
  * fd.io coding-style-patch-verification: ON