linux-cp: Basic MPLS support.
[vpp.git] / src / plugins / linux-cp / lcp_interface.c
index 6eb9406..fab048a 100644 (file)
@@ -39,7 +39,7 @@
 #include <vlibapi/api_helper_macros.h>
 #include <vnet/ipsec/ipsec_punt.h>
 
-static vlib_log_class_t lcp_itf_pair_logger;
+vlib_log_class_t lcp_itf_pair_logger;
 
 /**
  * Pool of LIP objects
@@ -73,14 +73,6 @@ lcp_itf_pair_register_vft (lcp_itf_pair_vft_t *lcp_itf_vft)
   vec_add1 (lcp_itf_vfts, *lcp_itf_vft);
 }
 
-#define LCP_ITF_PAIR_DBG(...)                                                 \
-  vlib_log_notice (lcp_itf_pair_logger, __VA_ARGS__);
-
-#define LCP_ITF_PAIR_INFO(...)                                                \
-  vlib_log_notice (lcp_itf_pair_logger, __VA_ARGS__);
-
-#define LCP_ITF_PAIR_ERR(...) vlib_log_err (lcp_itf_pair_logger, __VA_ARGS__);
-
 u8 *
 format_lcp_itf_pair (u8 *s, va_list *args)
 {
@@ -139,6 +131,13 @@ lcp_itf_pair_show (u32 phy_sw_if_index)
   ns = lcp_get_default_ns ();
   vlib_cli_output (vm, "lcp default netns '%s'\n",
                   ns ? (char *) ns : "<unset>");
+  vlib_cli_output (vm, "lcp lcp-auto-subint %s\n",
+                  lcp_auto_subint () ? "on" : "off");
+  vlib_cli_output (vm, "lcp lcp-sync %s\n", lcp_sync () ? "on" : "off");
+  vlib_cli_output (vm, "lcp del-static-on-link-down %s\n",
+                  lcp_get_del_static_on_link_down () ? "on" : "off");
+  vlib_cli_output (vm, "lcp del-dynamic-on-link-down %s\n",
+                  lcp_get_del_dynamic_on_link_down () ? "on" : "off");
 
   if (phy_sw_if_index == ~0)
     {
@@ -157,6 +156,8 @@ lcp_itf_pair_get (u32 index)
 {
   if (!lcp_itf_pair_pool)
     return NULL;
+  if (index == INDEX_INVALID)
+    return NULL;
 
   return pool_elt_at_index (lcp_itf_pair_pool, index);
 }
@@ -174,25 +175,6 @@ lcp_itf_pair_find_by_vif (u32 vif_index)
   return INDEX_INVALID;
 }
 
-int
-lcp_itf_pair_add_sub (u32 vif, u8 *host_if_name, u32 sub_sw_if_index,
-                     u32 phy_sw_if_index, u8 *ns)
-{
-  lcp_itf_pair_t *lip;
-
-  lip = lcp_itf_pair_get (lcp_itf_pair_find_by_phy (phy_sw_if_index));
-  if (!lip)
-    {
-      LCP_ITF_PAIR_DBG ("lcp_itf_pair_add_sub: can't find LCP of parent %U",
-                       format_vnet_sw_if_index_name, vnet_get_main (),
-                       phy_sw_if_index);
-      return VNET_API_ERROR_INVALID_SW_IF_INDEX;
-    }
-
-  return lcp_itf_pair_add (lip->lip_host_sw_if_index, sub_sw_if_index,
-                          host_if_name, vif, lip->lip_host_type, ns);
-}
-
 const char *lcp_itf_l3_feat_names[N_LCP_ITF_HOST][N_AF] = {
   [LCP_ITF_HOST_TAP] = {
     [AF_IP4] = "linux-cp-xc-ip4",
@@ -248,17 +230,23 @@ lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index, u8 *host_name,
   index_t lipi;
   lcp_itf_pair_t *lip;
 
+  if (host_sw_if_index == ~0)
+    {
+      LCP_ITF_PAIR_ERR ("pair_add: Cannot add LIP - invalid host");
+      return VNET_API_ERROR_INVALID_SW_IF_INDEX;
+    }
+
   lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
 
+  if (lipi != INDEX_INVALID)
+    return VNET_API_ERROR_VALUE_EXIST;
+
   LCP_ITF_PAIR_INFO ("add: host:%U phy:%U, host_if:%v vif:%d ns:%s",
                     format_vnet_sw_if_index_name, vnet_get_main (),
                     host_sw_if_index, format_vnet_sw_if_index_name,
                     vnet_get_main (), phy_sw_if_index, host_name, host_index,
                     ns);
 
-  if (lipi != INDEX_INVALID)
-    return VNET_API_ERROR_VALUE_EXIST;
-
   /*
    * Create a new pair.
    */
@@ -279,9 +267,6 @@ lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index, u8 *host_name,
   lip->lip_vif_index = host_index;
   lip->lip_namespace = vec_dup (ns);
 
-  if (lip->lip_host_sw_if_index == ~0)
-    return 0;
-
   /*
    * First use of this host interface.
    * Enable the x-connect feature on the host to send
@@ -327,10 +312,13 @@ lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index, u8 *host_name,
     }
   else
     {
-      vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 1, NULL,
-                                  0);
-      vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 1, NULL,
-                                  0);
+      if (hash_elts (lip_db_by_vif) == 1)
+       {
+         vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 1,
+                                      NULL, 0);
+         vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 1,
+                                      NULL, 0);
+       }
     }
 
   /* invoke registered callbacks for pair addition */
@@ -421,10 +409,11 @@ lcp_itf_pair_del (u32 phy_sw_if_index)
 
   lip = lcp_itf_pair_get (lipi);
 
-  LCP_ITF_PAIR_INFO ("pair delete: {%U, %U, %v}", format_vnet_sw_if_index_name,
-                    vnet_get_main (), lip->lip_phy_sw_if_index,
-                    format_vnet_sw_if_index_name, vnet_get_main (),
-                    lip->lip_host_sw_if_index, lip->lip_host_name);
+  LCP_ITF_PAIR_NOTICE (
+    "pair_del: host:%U phy:%U host_if:%v vif:%d ns:%v",
+    format_vnet_sw_if_index_name, vnet_get_main (), lip->lip_host_sw_if_index,
+    format_vnet_sw_if_index_name, vnet_get_main (), lip->lip_phy_sw_if_index,
+    lip->lip_host_name, lip->lip_vif_index, lip->lip_namespace);
 
   /* invoke registered callbacks for pair deletion */
   vec_foreach (vft, lcp_itf_vfts)
@@ -453,12 +442,14 @@ lcp_itf_pair_del (u32 phy_sw_if_index)
     }
   else
     {
-      vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 0, NULL,
-                                  0);
-      vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 0, NULL,
-                                  0);
+      if (hash_elts (lip_db_by_vif) == 1)
+       {
+         vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 0,
+                                      NULL, 0);
+         vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 0,
+                                      NULL, 0);
+       }
     }
-
   lip_db_by_phy[phy_sw_if_index] = INDEX_INVALID;
   lip_db_by_host[lip->lip_host_sw_if_index] = INDEX_INVALID;
   hash_unset (lip_db_by_vif, lip->lip_vif_index);
@@ -475,24 +466,45 @@ lcp_itf_pair_delete_by_index (index_t lipi)
 {
   u32 host_sw_if_index;
   lcp_itf_pair_t *lip;
-  u8 *host_name;
+  u8 *host_name, *ns;
 
   lip = lcp_itf_pair_get (lipi);
 
   host_name = vec_dup (lip->lip_host_name);
   host_sw_if_index = lip->lip_host_sw_if_index;
+  ns = vec_dup (lip->lip_namespace);
 
   lcp_itf_pair_del (lip->lip_phy_sw_if_index);
 
   if (vnet_sw_interface_is_sub (vnet_get_main (), host_sw_if_index))
     {
+      int curr_ns_fd = -1;
+      int vif_ns_fd = -1;
+      if (ns)
+       {
+         curr_ns_fd = clib_netns_open (NULL /* self */);
+         vif_ns_fd = clib_netns_open ((u8 *) ns);
+         if (vif_ns_fd != -1)
+           clib_setns (vif_ns_fd);
+       }
+
       lcp_netlink_del_link ((const char *) host_name);
+      if (vif_ns_fd != -1)
+       close (vif_ns_fd);
+
+      if (curr_ns_fd != -1)
+       {
+         clib_setns (curr_ns_fd);
+         close (curr_ns_fd);
+       }
+
       vnet_delete_sub_interface (host_sw_if_index);
     }
   else
     tap_delete_if (vlib_get_main (), host_sw_if_index);
 
   vec_free (host_name);
+  vec_free (ns);
 }
 
 int
@@ -510,6 +522,23 @@ lcp_itf_pair_delete (u32 phy_sw_if_index)
   return 0;
 }
 
+/**
+ * lcp_itf_interface_add_del
+ *
+ * Registered to receive interface Add and delete notifications
+ */
+static clib_error_t *
+lcp_itf_interface_add_del (vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
+{
+  if (!is_add)
+    /* remove any interface pair we have for this interface */
+    lcp_itf_pair_delete (sw_if_index);
+
+  return (NULL);
+}
+
+VNET_SW_INTERFACE_ADD_DEL_FUNCTION (lcp_itf_interface_add_del);
+
 void
 lcp_itf_pair_walk (lcp_itf_pair_walk_cb_t cb, void *ctx)
 {
@@ -522,58 +551,16 @@ lcp_itf_pair_walk (lcp_itf_pair_walk_cb_t cb, void *ctx)
     };
 }
 
-typedef struct lcp_itf_pair_names_t_
-{
-  u8 *lipn_host_name;
-  u8 *lipn_phy_name;
-  u8 *lipn_namespace;
-  u32 lipn_phy_sw_if_index;
-} lcp_itf_pair_names_t;
-
-static lcp_itf_pair_names_t *lipn_names;
-
 static clib_error_t *
 lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input)
 {
-  u8 *host, *phy;
-  u8 *ns;
   u8 *default_ns;
 
-  host = phy = ns = default_ns = NULL;
+  default_ns = NULL;
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
-      vec_reset_length (host);
-
-      if (unformat (input, "pair %s %s %s", &phy, &host, &ns))
-       {
-         lcp_itf_pair_names_t *lipn;
-
-         if (vec_len (ns) > LCP_NS_LEN)
-           {
-             return clib_error_return (0,
-                                       "linux-cp namespace must"
-                                       " be less than %d characters",
-                                       LCP_NS_LEN);
-           }
-
-         vec_add2 (lipn_names, lipn, 1);
-
-         lipn->lipn_host_name = vec_dup (host);
-         lipn->lipn_phy_name = vec_dup (phy);
-         lipn->lipn_namespace = vec_dup (ns);
-       }
-      else if (unformat (input, "pair %v %v", &phy, &host))
-       {
-         lcp_itf_pair_names_t *lipn;
-
-         vec_add2 (lipn_names, lipn, 1);
-
-         lipn->lipn_host_name = vec_dup (host);
-         lipn->lipn_phy_name = vec_dup (phy);
-         lipn->lipn_namespace = 0;
-       }
-      else if (unformat (input, "default netns %v", &default_ns))
+      if (unformat (input, "default netns %v", &default_ns))
        {
          vec_add1 (default_ns, 0);
          if (lcp_set_default_ns (default_ns) < 0)
@@ -584,14 +571,18 @@ lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input)
                                        LCP_NS_LEN);
            }
        }
-      else if (unformat (input, "interface-auto-create"))
-       lcp_set_auto_intf (1 /* is_auto */);
+      else if (unformat (input, "lcp-auto-subint"))
+       lcp_set_auto_subint (1 /* is_auto */);
+      else if (unformat (input, "lcp-sync"))
+       lcp_set_sync (1 /* is_auto */);
+      else if (unformat (input, "del-static-on-link-down"))
+       lcp_set_del_static_on_link_down (1 /* is_del */);
+      else if (unformat (input, "del-dynamic-on-link-down"))
+       lcp_set_del_dynamic_on_link_down (1 /* is_del */);
       else
        return clib_error_return (0, "interfaces not found");
     }
 
-  vec_free (host);
-  vec_free (phy);
   vec_free (default_ns);
 
   return NULL;
@@ -636,7 +627,7 @@ lcp_validate_if_name (u8 *name)
   return 1;
 }
 
-static void
+void
 lcp_itf_set_link_state (const lcp_itf_pair_t *lip, u8 state)
 {
   int curr_ns_fd, vif_ns_fd;
@@ -654,6 +645,8 @@ lcp_itf_set_link_state (const lcp_itf_pair_t *lip, u8 state)
        clib_setns (vif_ns_fd);
     }
 
+  /* Set the same link state on the netlink interface
+   */
   vnet_netlink_set_link_state (lip->lip_vif_index, state);
 
   if (vif_ns_fd != -1)
@@ -668,6 +661,58 @@ lcp_itf_set_link_state (const lcp_itf_pair_t *lip, u8 state)
   return;
 }
 
+void
+lcp_itf_set_interface_addr (const lcp_itf_pair_t *lip)
+{
+  ip4_main_t *im4 = &ip4_main;
+  ip6_main_t *im6 = &ip6_main;
+  ip_lookup_main_t *lm4 = &im4->lookup_main;
+  ip_lookup_main_t *lm6 = &im6->lookup_main;
+  ip_interface_address_t *ia = 0;
+  int vif_ns_fd = -1;
+  int curr_ns_fd = -1;
+
+  if (!lip)
+    return;
+
+  if (lip->lip_namespace)
+    {
+      curr_ns_fd = clib_netns_open (NULL /* self */);
+      vif_ns_fd = clib_netns_open (lip->lip_namespace);
+      if (vif_ns_fd != -1)
+       clib_setns (vif_ns_fd);
+    }
+
+  /* Sync any IP4 addressing info into LCP */
+  foreach_ip_interface_address (
+    lm4, ia, lip->lip_phy_sw_if_index, 1 /* honor unnumbered */, ({
+      ip4_address_t *r4 = ip_interface_address_get_address (lm4, ia);
+      LCP_ITF_PAIR_NOTICE ("set_interface_addr: %U add ip4 %U/%d",
+                          format_lcp_itf_pair, lip, format_ip4_address, r4,
+                          ia->address_length);
+      vnet_netlink_add_ip4_addr (lip->lip_vif_index, r4, ia->address_length);
+    }));
+
+  /* Sync any IP6 addressing info into LCP */
+  foreach_ip_interface_address (
+    lm6, ia, lip->lip_phy_sw_if_index, 1 /* honor unnumbered */, ({
+      ip6_address_t *r6 = ip_interface_address_get_address (lm6, ia);
+      LCP_ITF_PAIR_NOTICE ("set_interface_addr: %U add ip6 %U/%d",
+                          format_lcp_itf_pair, lip, format_ip6_address, r6,
+                          ia->address_length);
+      vnet_netlink_add_ip6_addr (lip->lip_vif_index, r6, ia->address_length);
+    }));
+
+  if (vif_ns_fd != -1)
+    close (vif_ns_fd);
+
+  if (curr_ns_fd != -1)
+    {
+      clib_setns (curr_ns_fd);
+      close (curr_ns_fd);
+    }
+}
+
 typedef struct
 {
   u32 vlan;
@@ -723,6 +768,9 @@ lcp_itf_pair_find_by_outer_vlan (u32 sup_if_index, u16 vlan, bool dot1ad)
   return lip_db_by_phy[match.matched_sw_if_index];
 }
 
+static clib_error_t *lcp_itf_pair_link_up_down (vnet_main_t *vnm,
+                                               u32 hw_if_index, u32 flags);
+
 int
 lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
                     lip_host_type_t host_if_type, u8 *ns,
@@ -730,7 +778,7 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
 {
   vlib_main_t *vm;
   vnet_main_t *vnm;
-  u32 vif_index = 0, host_sw_if_index;
+  u32 vif_index = 0, host_sw_if_index = ~0;
   const vnet_sw_interface_t *sw;
   const vnet_hw_interface_t *hw;
   const lcp_itf_pair_t *lip;
@@ -757,6 +805,14 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
       return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     }
 
+  if (hw->hw_class_index != ethernet_hw_interface_class.index &&
+      host_if_type == LCP_ITF_HOST_TAP)
+    {
+      LCP_ITF_PAIR_ERR (
+       "pair_create: don't create TAP for non-eth interface; use tun");
+      return VNET_API_ERROR_INVALID_ARGUMENT;
+    }
+
   /*
    * Use interface-specific netns if supplied.
    * Otherwise, use netns if defined, otherwise use the OS default.
@@ -775,9 +831,8 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
       u16 vlan, proto;
       u32 parent_vif_index;
 
-      // TODO(pim) replace with vnet_sw_interface_supports_addressing()
-      if (sw->type == VNET_SW_INTERFACE_TYPE_SUB &&
-         sw->sub.eth.flags.exact_match == 0)
+      err = vnet_sw_interface_supports_addressing (vnm, phy_sw_if_index);
+      if (err)
        {
          LCP_ITF_PAIR_ERR ("pair_create: can't create LCP for a "
                            "sub-interface without exact-match set");
@@ -904,7 +959,7 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
            outer_vlan, inner_vlan, format_vnet_sw_if_index_name, vnm,
            lip->lip_host_sw_if_index);
          err = clib_error_return (
-           0, "failed to create tap subinti: %d.%d. on %U", outer_vlan,
+           0, "failed to create tap subint: %d.%d. on %U", outer_vlan,
            inner_vlan, format_vnet_sw_if_index_name, vnm,
            lip->lip_host_sw_if_index);
        }
@@ -925,14 +980,18 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
     {
       tap_create_if_args_t args = {
        .num_rx_queues = clib_max (1, vlib_num_workers ()),
+       .num_tx_queues = 1,
        .id = hw->hw_if_index,
        .sw_if_index = ~0,
        .rx_ring_sz = 256,
        .tx_ring_sz = 256,
        .host_if_name = host_if_name,
        .host_namespace = 0,
+       .rv = 0,
+       .error = NULL,
       };
       ethernet_interface_t *ei;
+      u32 host_sw_mtu_size;
 
       if (host_if_type == LCP_ITF_HOST_TUN)
        args.tap_flags |= TAP_FLAG_TUN;
@@ -942,39 +1001,37 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
          mac_address_copy (&args.host_mac_addr, &ei->address.mac);
        }
 
-      if (sw->mtu[VNET_MTU_L3])
+      /*
+       * The TAP interface does copy forward the host MTU based on the VPP
+       * interface's L3 MTU, but it should also ensure that the VPP tap
+       * interface has an MTU that is greater-or-equal to those. Considering
+       * users can set the interfaces at runtime (set interface mtu packet ...)
+       * ensure that the tap MTU is large enough, taking the VPP interface L3
+       * if it's set, and otherwise a sensible default.
+       */
+      host_sw_mtu_size = sw->mtu[VNET_MTU_L3];
+      if (host_sw_mtu_size)
        {
          args.host_mtu_set = 1;
-         args.host_mtu_size = sw->mtu[VNET_MTU_L3];
+         args.host_mtu_size = host_sw_mtu_size;
        }
+      else
+       host_sw_mtu_size = ETHERNET_MAX_PACKET_BYTES;
 
       if (ns && ns[0] != 0)
        args.host_namespace = ns;
 
       vm = vlib_get_main ();
       tap_create_if (vm, &args);
-
       if (args.rv < 0)
        {
          LCP_ITF_PAIR_ERR ("pair_create: could not create tap, retval:%d",
                            args.rv);
+         clib_error_free (args.error);
          return args.rv;
        }
 
-      /*
-       * The TAP interface does copy forward the host MTU based on the VPP
-       * interface's L3 MTU, but it should also ensure that the VPP tap
-       * interface has an MTU that is greater-or-equal to those. Considering
-       * users can set the interfaces at runtime (set interface mtu packet ...)
-       * ensure that the tap MTU is large enough, taking the VPP interface L3
-       * if it's set, and otherwise a sensible default.
-       */
-      if (sw->mtu[VNET_MTU_L3])
-       vnet_sw_interface_set_mtu (vnm, args.sw_if_index,
-                                  sw->mtu[VNET_MTU_L3]);
-      else
-       vnet_sw_interface_set_mtu (vnm, args.sw_if_index,
-                                  ETHERNET_MAX_PACKET_BYTES);
+      vnet_sw_interface_set_mtu (vnm, args.sw_if_index, host_sw_mtu_size);
 
       /*
        * get the hw and ethernet of the tap
@@ -1020,13 +1077,24 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
    * The TAP is shared by many interfaces, always keep it up.
    * This controls whether the host can RX/TX.
    */
-
+  sw = vnet_get_sw_interface (vnm, phy_sw_if_index);
   lip = lcp_itf_pair_get (lcp_itf_pair_find_by_vif (vif_index));
   LCP_ITF_PAIR_INFO ("pair create: %U sw-flags %u hw-flags %u",
                     format_lcp_itf_pair, lip, sw->flags, hw->flags);
   vnet_sw_interface_admin_up (vnm, host_sw_if_index);
   lcp_itf_set_link_state (lip, sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP);
 
+  /*
+   * Reflect current link state and link speed of the hardware interface on the
+   * TAP interface.
+   */
+  if (host_if_type == LCP_ITF_HOST_TAP &&
+      !vnet_sw_interface_is_sub (vnm, phy_sw_if_index))
+    {
+      hw = vnet_get_sup_hw_interface (vnm, phy_sw_if_index);
+      lcp_itf_pair_link_up_down (vnm, hw->hw_if_index, hw->flags);
+    }
+
   if (host_sw_if_indexp)
     *host_sw_if_indexp = host_sw_if_index;
 
@@ -1089,70 +1157,6 @@ lcp_itf_pair_replace_end (void)
   return (0);
 }
 
-static uword
-lcp_itf_pair_process (vlib_main_t *vm, vlib_node_runtime_t *rt,
-                     vlib_frame_t *f)
-{
-  uword *event_data = 0;
-  uword *lipn_index;
-
-  while (1)
-    {
-      vlib_process_wait_for_event (vm);
-
-      vlib_process_get_events (vm, &event_data);
-
-      vec_foreach (lipn_index, event_data)
-       {
-         lcp_itf_pair_names_t *lipn;
-
-         lipn = &lipn_names[*lipn_index];
-         lcp_itf_pair_create (lipn->lipn_phy_sw_if_index,
-                              lipn->lipn_host_name, LCP_ITF_HOST_TAP,
-                              lipn->lipn_namespace, NULL);
-       }
-
-      vec_reset_length (event_data);
-    }
-
-  return 0;
-}
-
-VLIB_REGISTER_NODE (lcp_itf_pair_process_node, static) = {
-  .function = lcp_itf_pair_process,
-  .name = "linux-cp-itf-process",
-  .type = VLIB_NODE_TYPE_PROCESS,
-};
-
-static clib_error_t *
-lcp_itf_phy_add (vnet_main_t *vnm, u32 sw_if_index, u32 is_create)
-{
-  lcp_itf_pair_names_t *lipn;
-  vlib_main_t *vm = vlib_get_main ();
-  vnet_hw_interface_t *hw;
-
-  if (!is_create || vnet_sw_interface_is_sub (vnm, sw_if_index))
-    return NULL;
-
-  hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
-
-  vec_foreach (lipn, lipn_names)
-    {
-      if (!vec_cmp (hw->name, lipn->lipn_phy_name))
-       {
-         lipn->lipn_phy_sw_if_index = sw_if_index;
-
-         vlib_process_signal_event (vm, lcp_itf_pair_process_node.index, 0,
-                                    lipn - lipn_names);
-         break;
-       }
-    }
-
-  return NULL;
-}
-
-VNET_SW_INTERFACE_ADD_DEL_FUNCTION (lcp_itf_phy_add);
-
 static clib_error_t *
 lcp_itf_pair_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
 {
@@ -1179,7 +1183,8 @@ lcp_itf_pair_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
       tap_set_carrier (si->hw_if_index,
                       (flags & VNET_HW_INTERFACE_FLAG_LINK_UP));
 
-      if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
+      if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP &&
+         hi->link_speed != UINT32_MAX)
        {
          tap_set_speed (si->hw_if_index, hi->link_speed / 1000);
        }
@@ -1191,13 +1196,15 @@ lcp_itf_pair_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lcp_itf_pair_link_up_down);
 
 static clib_error_t *
-lcp_itf_pair_init (vlib_main_t *vm)
+lcp_interface_init (vlib_main_t *vm)
 {
   vlib_punt_hdl_t punt_hdl = vlib_punt_client_register ("linux-cp");
 
   /* punt IKE */
   vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0],
                      "linux-cp-punt");
+  vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP6_SPI_UDP_0],
+                     "linux-cp-punt");
 
   /* punt all unknown ports */
   udp_punt_unknown (vm, 0, 1);
@@ -1210,7 +1217,7 @@ lcp_itf_pair_init (vlib_main_t *vm)
   return NULL;
 }
 
-VLIB_INIT_FUNCTION (lcp_itf_pair_init) = {
+VLIB_INIT_FUNCTION (lcp_interface_init) = {
   .runs_after = VLIB_INITS ("vnet_interface_init", "tcp_init", "udp_init"),
 };