tap: add function to set speed 84/28684/3
authorAlexander Chernavin <achernavin@netgate.com>
Fri, 4 Sep 2020 13:24:20 +0000 (09:24 -0400)
committerNeale Ranns <nranns@cisco.com>
Mon, 9 Nov 2020 09:46:58 +0000 (09:46 +0000)
A plugin can set the speed on a host interface making it possible for
host applications to be aware of the actual interface speed, not the
one that the driver reports by default.

With this change, add a function to set speed on a host interface.

Type: feature
Signed-off-by: Alexander Chernavin <achernavin@netgate.com>
Change-Id: I259a52b736022bdd805e8d92dcd1bfd5c58f6f96

src/vnet/devices/tap/tap.c
src/vnet/devices/tap/tap.h

index 94a91e5..b65879c 100644 (file)
 #define _GNU_SOURCE
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/socket.h>
 #include <fcntl.h>
 #include <net/if.h>
 #include <linux/if_tun.h>
 #include <sys/ioctl.h>
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
 #include <sys/eventfd.h>
 #include <net/if_arp.h>
 #include <sched.h>
@@ -1045,6 +1048,85 @@ tap_mtu_config (vlib_main_t * vm, unformat_input_t * input)
   return 0;
 }
 
+/*
+ * Set host tap/tun interface speed in Mbps.
+ */
+int
+tap_set_speed (u32 hw_if_index, u32 speed)
+{
+  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 old_netns_fd = -1;
+  int nfd = -1;
+  int ctl_fd = -1;
+  struct ifreq ifr;
+  struct ethtool_cmd ecmd;
+  int ret = -1;
+
+  vif = pool_elt_at_index (mm->interfaces, hi->dev_instance);
+
+  if (vif->net_ns)
+    {
+      old_netns_fd = open ("/proc/self/ns/net", O_RDONLY);
+      if ((nfd = open_netns_fd ((char *) vif->net_ns)) == -1)
+       {
+         clib_warning ("Cannot open netns");
+         goto done;
+       }
+      if (setns (nfd, CLONE_NEWNET) == -1)
+       {
+         clib_warning ("Cannot set ns");
+         goto done;
+       }
+    }
+
+  if ((ctl_fd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
+    {
+      clib_warning ("Cannot open control socket");
+      goto done;
+    }
+
+  ecmd.cmd = ETHTOOL_GSET;
+  clib_memset (&ifr, 0, sizeof (ifr));
+  clib_memcpy (ifr.ifr_name, vif->host_if_name,
+              strlen ((const char *) vif->host_if_name));
+  ifr.ifr_data = (void *) &ecmd;
+  if ((ret = ioctl (ctl_fd, SIOCETHTOOL, &ifr)) < 0)
+    {
+      clib_warning ("Cannot get device settings");
+      goto done;
+    }
+
+  if (ethtool_cmd_speed (&ecmd) != speed)
+    {
+      ecmd.cmd = ETHTOOL_SSET;
+      ethtool_cmd_speed_set (&ecmd, speed);
+      if ((ret = ioctl (ctl_fd, SIOCETHTOOL, &ifr)) < 0)
+       {
+         clib_warning ("Cannot set device settings");
+         goto done;
+       }
+    }
+
+done:
+  if (old_netns_fd != -1)
+    {
+      if (setns (old_netns_fd, CLONE_NEWNET) == -1)
+       {
+         clib_warning ("Cannot set old ns");
+       }
+      close (old_netns_fd);
+    }
+  if (nfd != -1)
+    close (nfd);
+  if (ctl_fd != -1)
+    close (ctl_fd);
+
+  return ret;
+}
+
 /* tap { host-mtu <size> } configuration. */
 VLIB_CONFIG_FUNCTION (tap_mtu_config, "tap");
 
index 4228328..2efaa51 100644 (file)
@@ -109,7 +109,7 @@ 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);
-
+int tap_set_speed (u32 hw_if_index, u32 speed);
 
 #endif /* _VNET_DEVICES_VIRTIO_TAP_H_ */