aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/devices/tap/tap.c
diff options
context:
space:
mode:
authorAlexander Chernavin <achernavin@netgate.com>2020-09-04 09:24:20 -0400
committerNeale Ranns <nranns@cisco.com>2020-11-09 09:46:58 +0000
commita6c34a19dffc75a15aea5356b551d2b6bba570c0 (patch)
tree6ce7b2aa481d205f30c55080ce1bedb0630be661 /src/vnet/devices/tap/tap.c
parentf6422ffbc82c55f50d06c8c7a2e230db7001ee35 (diff)
tap: add function to set speed
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
Diffstat (limited to 'src/vnet/devices/tap/tap.c')
-rw-r--r--src/vnet/devices/tap/tap.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/src/vnet/devices/tap/tap.c b/src/vnet/devices/tap/tap.c
index 94a91e5509a..b65879c42fc 100644
--- a/src/vnet/devices/tap/tap.c
+++ b/src/vnet/devices/tap/tap.c
@@ -18,10 +18,13 @@
#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");