tap: allow change of carrier state on host 45/28645/4
authorMatthew Smith <mgsmith@netgate.com>
Fri, 24 Jul 2020 18:38:03 +0000 (13:38 -0500)
committerMatthew Smith <mgsmith@netgate.com>
Thu, 5 Nov 2020 17:41:01 +0000 (17:41 +0000)
Type: feature

Add a function to adjust the link state of the host side of a tap
interface. If an application (e.g. route protocol daemons) running on
the host uses netlink to monitor interface state, a plugin
could use this function to communicate a loss of connectivity
to the application by making the interface appear to go down.

Requires a somewhat recent kernel. E.g. it does not have any effect
on CentOS 7 but it works on CentOS 8.

Change-Id: I677ee7889d2eb142e2395bea98f0b4d7e7e7f810
Signed-off-by: Matthew Smith <mgsmith@netgate.com>
src/vnet/devices/tap/tap.c
src/vnet/devices/tap/tap.h
src/vnet/devices/virtio/virtio.c
src/vnet/devices/virtio/virtio.h

index aa9182a..94a91e5 100644 (file)
@@ -751,6 +751,12 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args)
   vif->flags |= VIRTIO_IF_FLAG_ADMIN_UP;
   vnet_hw_interface_set_flags (vnm, vif->hw_if_index,
                               VNET_HW_INTERFACE_FLAG_LINK_UP);
+  /*
+   * Host tun/tap driver link carrier state is "up" at creation. The
+   * driver never changes this unless the backend (VPP) changes it using
+   * TUNSETCARRIER ioctl(). See tap_set_carrier().
+   */
+  vif->host_carrier_up = 1;
   vif->cxq_vring = NULL;
 
   goto done;
@@ -987,6 +993,41 @@ tap_dump_ifs (tap_interface_details_t ** out_tapids)
   return 0;
 }
 
+/*
+ * Set host tap/tun interface carrier state so it will appear to host
+ * applications that the interface's link state changed.
+ *
+ * If the kernel we're building against does not have support for the
+ * TUNSETCARRIER ioctl command, do nothing.
+ */
+int
+tap_set_carrier (u32 hw_if_index, u32 carrier_up)
+{
+  int ret = 0;
+#ifdef TUNSETCARRIER
+  vnet_main_t *vnm = vnet_get_main ();
+  vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
+  virtio_main_t *mm = &virtio_main;
+  virtio_if_t *vif;
+  int *fd;
+
+  vif = pool_elt_at_index (mm->interfaces, hi->dev_instance);
+  vec_foreach (fd, vif->tap_fds)
+  {
+    ret = ioctl (*fd, TUNSETCARRIER, &carrier_up);
+    if (ret < 0)
+      {
+       clib_warning ("ioctl (TUNSETCARRIER) returned %d", ret);
+       break;
+      }
+  }
+  if (!ret)
+    vif->host_carrier_up = (carrier_up != 0);
+#endif
+
+  return ret;
+}
+
 static clib_error_t *
 tap_mtu_config (vlib_main_t * vm, unformat_input_t * input)
 {
index 46f13a4..4228328 100644 (file)
@@ -108,6 +108,8 @@ int
 tap_csum_offload_enable_disable (vlib_main_t * vm, u32 sw_if_index,
                                 int enable_disable);
 int tap_dump_ifs (tap_interface_details_t ** out_tapids);
+int tap_set_carrier (u32 hw_if_index, u32 carrier_up);
+
 
 #endif /* _VNET_DEVICES_VIRTIO_TAP_H_ */
 
index 8209a46..925ad09 100644 (file)
@@ -345,6 +345,7 @@ virtio_show (vlib_main_t * vm, u32 * hw_if_indices, u8 show_descr, u32 type)
          if (type == VIRTIO_IF_TYPE_TAP)
            vlib_cli_output (vm, "  host-mac-addr: %U",
                             format_ethernet_address, vif->host_mac_addr);
+         vlib_cli_output (vm, "  host-carrier-up: %u", vif->host_carrier_up);
 
          vec_foreach_index (i, vif->vhost_fds)
            str = format (str, " %d", vif->vhost_fds[i]);
index 86660a1..fda7236 100644 (file)
@@ -169,6 +169,7 @@ typedef struct
       ip4_address_t host_ip4_addr;
       u8 host_ip4_prefix_len;
       u8 host_ip6_prefix_len;
+      u8 host_carrier_up;      /* host tun/tap driver link carrier state */
     };
     struct                     /* native virtio */
     {