summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/vnet/devices/tap/tap.c82
-rw-r--r--src/vnet/devices/tap/tap.h2
2 files changed, 83 insertions, 1 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");
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_ */