tap: allow change of carrier state on host
[vpp.git] / src / vnet / devices / tap / tap.c
index 4a02c5a..94a91e5 100644 (file)
@@ -109,8 +109,11 @@ tap_free (vlib_main_t * vm, virtio_if_t * vif)
     virtio_vring_free_tx (vm, vif, TX_QUEUE (i));
   /* *INDENT-ON* */
 
-  _IOCTL (vif->tap_fds[0], TUNSETPERSIST, (void *) (uintptr_t) 0);
-  tap_log_dbg (vif, "TUNSETPERSIST: unset");
+  if (vif->tap_fds)
+    {
+      _IOCTL (vif->tap_fds[0], TUNSETPERSIST, (void *) (uintptr_t) 0);
+      tap_log_dbg (vif, "TUNSETPERSIST: unset");
+    }
 error:
   vec_foreach_index (i, vif->tap_fds) close (vif->tap_fds[i]);
 
@@ -207,7 +210,7 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args)
        {
          host_if_name = (char *) args->host_if_name;
          clib_memcpy (ifr.ifr_name, host_if_name,
-                      clib_min (IFNAMSIZ, strlen (host_if_name)));
+                      clib_min (IFNAMSIZ, vec_len (host_if_name)));
        }
       else
        {
@@ -748,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;
@@ -955,19 +964,19 @@ tap_dump_ifs (tap_interface_details_t ** out_tapids)
       {
         clib_memcpy(tapid->host_if_name, vif->host_if_name,
                     MIN (ARRAY_LEN (tapid->host_if_name) - 1,
-                    strlen ((const char *) vif->host_if_name)));
+                    vec_len (vif->host_if_name)));
       }
     if (vif->net_ns)
       {
         clib_memcpy(tapid->host_namespace, vif->net_ns,
                     MIN (ARRAY_LEN (tapid->host_namespace) - 1,
-                    strlen ((const char *) vif->net_ns)));
+                    vec_len (vif->net_ns)));
       }
     if (vif->host_bridge)
       {
         clib_memcpy(tapid->host_bridge, vif->host_bridge,
                     MIN (ARRAY_LEN (tapid->host_bridge) - 1,
-                    strlen ((const char *) vif->host_bridge)));
+                    vec_len (vif->host_bridge)));
       }
     if (vif->host_ip4_prefix_len)
       clib_memcpy(tapid->host_ip4_addr.as_u8, &vif->host_ip4_addr, 4);
@@ -984,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)
 {