summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSusant Sahani <ssahani@vmware.com>2019-09-23 16:51:02 +0200
committerYu Watanabe <watanabe.yu+github@gmail.com>2019-09-24 16:33:35 +0200
commit224ded670feeb59f7231e6102a5bee5d3b653a8a (patch)
tree6f7d4645dd9fa5275dc3acaf2b199a9338d98508
parent68c2b5ddb1881c40201c1d86a7852dd5c5c06a76 (diff)
downloadsystemd-224ded670feeb59f7231e6102a5bee5d3b653a8a.tar.gz
link: Add support to configure NIC ring buffer size
-rw-r--r--man/systemd.link.xml13
-rw-r--r--src/shared/ethtool-util.c90
-rw-r--r--src/shared/ethtool-util.h11
-rw-r--r--src/udev/net/link-config-gperf.gperf2
-rw-r--r--src/udev/net/link-config.c6
-rw-r--r--src/udev/net/link-config.h1
-rw-r--r--test/fuzz/fuzz-link-parser/directives.link2
7 files changed, 125 insertions, 0 deletions
diff --git a/man/systemd.link.xml b/man/systemd.link.xml
index 7ea9a71107..5013e7e9b5 100644
--- a/man/systemd.link.xml
+++ b/man/systemd.link.xml
@@ -624,6 +624,19 @@
<para>Sets the number of combined set channels (a number between 1 and 4294967295).</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>RxBufferSize=</varname></term>
+ <listitem>
+ <para>Takes a integer. Specifies the NIC receive ring buffer size. When unset, the kernel's default will be used.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>TxBufferSize=</varname></term>
+ <listitem>
+ <para>Takes a integer. Specifies the NIC transmit ring buffer size. When unset, the kernel's default will be used.</para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</refsect1>
diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c
index b0961df72e..4cab2ef6b0 100644
--- a/src/shared/ethtool-util.c
+++ b/src/shared/ethtool-util.c
@@ -365,6 +365,54 @@ int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol) {
return 0;
}
+int ethtool_set_nic_buffer_size(int *fd, const char *ifname, netdev_ring_param *ring) {
+ struct ethtool_ringparam ecmd = {
+ .cmd = ETHTOOL_GRINGPARAM
+ };
+ struct ifreq ifr = {
+ .ifr_data = (void*) &ecmd
+ };
+ bool need_update = false;
+ int r;
+
+ if (*fd < 0) {
+ r = ethtool_connect_or_warn(fd, true);
+ if (r < 0)
+ return r;
+ }
+
+ strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
+
+ r = ioctl(*fd, SIOCETHTOOL, &ifr);
+ if (r < 0)
+ return -errno;
+
+ if (ring->rx_pending_set) {
+ if (ecmd.rx_pending != ring->rx_pending) {
+ ecmd.rx_pending = ring->rx_pending;
+ need_update = true;
+ }
+ }
+
+ if (ring->tx_pending_set) {
+ if (ecmd.tx_pending != ring->rx_pending) {
+ ecmd.tx_pending = ring->tx_pending;
+ need_update = true;
+ }
+ }
+
+ if (need_update) {
+ ecmd.cmd = ETHTOOL_SRINGPARAM;
+
+ r = ioctl(*fd, SIOCETHTOOL, &ifr);
+ if (r < 0)
+ return -errno;
+ }
+
+ return 0;
+}
+
+
static int get_stringset(int fd, struct ifreq *ifr, int stringset_id, struct ethtool_gstrings **gstrings) {
_cleanup_free_ struct ethtool_gstrings *strings = NULL;
struct {
@@ -858,3 +906,45 @@ int config_parse_advertise(const char *unit,
return 0;
}
+
+int config_parse_nic_buffer_size(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ netdev_ring_param *ring = data;
+ uint32_t k;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = safe_atou32(rvalue, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse interface buffer value, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (k < 1) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid %s value, ignoring: %s", lvalue, rvalue);
+ return 0;
+ }
+
+ if (streq(lvalue, "RxBufferSize")) {
+ ring->rx_pending = k;
+ ring->rx_pending_set = true;
+ } else if (streq(lvalue, "TxBufferSize")) {
+ ring->tx_pending = k;
+ ring->tx_pending_set = true;
+ }
+
+ return 0;
+}
diff --git a/src/shared/ethtool-util.h b/src/shared/ethtool-util.h
index 8b32b243f3..5dd7800852 100644
--- a/src/shared/ethtool-util.h
+++ b/src/shared/ethtool-util.h
@@ -79,12 +79,22 @@ typedef struct netdev_channels {
bool combined_count_set;
} netdev_channels;
+typedef struct netdev_ring_param {
+ uint32_t rx_pending;
+ uint32_t tx_pending;
+
+ bool rx_pending_set;
+ bool tx_pending_set;
+} netdev_ring_param;
+
+
int ethtool_get_driver(int *fd, const char *ifname, char **ret);
int ethtool_get_link_info(int *fd, const char *ifname,
int *ret_autonegotiation, size_t *ret_speed,
Duplex *ret_duplex, NetDevPort *ret_port);
int ethtool_set_speed(int *fd, const char *ifname, unsigned speed, Duplex duplex);
int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol);
+int ethtool_set_nic_buffer_size(int *fd, const char *ifname, netdev_ring_param *ring);
int ethtool_set_features(int *fd, const char *ifname, int *features);
int ethtool_set_glinksettings(int *fd, const char *ifname,
int autonegotiation, uint32_t advertise[static N_ADVERTISE],
@@ -108,3 +118,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_wol);
CONFIG_PARSER_PROTOTYPE(config_parse_port);
CONFIG_PARSER_PROTOTYPE(config_parse_channel);
CONFIG_PARSER_PROTOTYPE(config_parse_advertise);
+CONFIG_PARSER_PROTOTYPE(config_parse_nic_buffer_size);
diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf
index a3d7dec88c..c6ff796efc 100644
--- a/src/udev/net/link-config-gperf.gperf
+++ b/src/udev/net/link-config-gperf.gperf
@@ -53,3 +53,5 @@ Link.TxChannels, config_parse_channel, 0,
Link.OtherChannels, config_parse_channel, 0, offsetof(link_config, channels)
Link.CombinedChannels, config_parse_channel, 0, offsetof(link_config, channels)
Link.Advertise, config_parse_advertise, 0, offsetof(link_config, advertise)
+Link.RxBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring)
+Link.TxBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring)
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index d44af64d5e..cced62cab2 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -381,6 +381,12 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
log_warning_errno(r, "Could not set channels of %s: %m", old_name);
}
+ if (config->ring.rx_pending_set || config->ring.tx_pending_set) {
+ r = ethtool_set_nic_buffer_size(&ctx->ethtool_fd, old_name, &config->ring);
+ if (r < 0)
+ log_warning_errno(r, "Could not set ring buffer of %s: %m", old_name);
+ }
+
r = sd_device_get_ifindex(device, &ifindex);
if (r < 0)
return log_device_warning_errno(device, r, "Could not find ifindex: %m");
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
index cd99cd54d4..52a02b9b09 100644
--- a/src/udev/net/link-config.h
+++ b/src/udev/net/link-config.h
@@ -58,6 +58,7 @@ struct link_config {
NetDevPort port;
int features[_NET_DEV_FEAT_MAX];
netdev_channels channels;
+ netdev_ring_param ring;
LIST_FIELDS(link_config, links);
};
diff --git a/test/fuzz/fuzz-link-parser/directives.link b/test/fuzz/fuzz-link-parser/directives.link
index 61155063a8..e7d0737ace 100644
--- a/test/fuzz/fuzz-link-parser/directives.link
+++ b/test/fuzz/fuzz-link-parser/directives.link
@@ -34,3 +34,5 @@ TxChannels=
OtherChannels=
CombinedChannels=
Advertise=
+RxBufferSize=
+TxBufferSize=