From a6c34a19dffc75a15aea5356b551d2b6bba570c0 Mon Sep 17 00:00:00 2001 From: Alexander Chernavin Date: Fri, 4 Sep 2020 09:24:20 -0400 Subject: [PATCH] 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 Change-Id: I259a52b736022bdd805e8d92dcd1bfd5c58f6f96 --- src/vnet/devices/tap/tap.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++ src/vnet/devices/tap/tap.h | 2 +- 2 files changed, 83 insertions(+), 1 deletion(-) 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 #include +#include #include #include #include #include +#include +#include #include #include #include @@ -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 } configuration. */ VLIB_CONFIG_FUNCTION (tap_mtu_config, "tap"); diff --git a/src/vnet/devices/tap/tap.h b/src/vnet/devices/tap/tap.h index 42283281448..2efaa511a49 100644 --- a/src/vnet/devices/tap/tap.h +++ b/src/vnet/devices/tap/tap.h @@ -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_ */ -- 2.16.6