summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/systemd.link.xml24
-rw-r--r--src/shared/ethtool-util.c49
-rw-r--r--src/shared/ethtool-util.h1
-rw-r--r--src/udev/net/link-config-gperf.gperf3
-rw-r--r--src/udev/net/link-config.c7
-rw-r--r--src/udev/net/link-config.h3
-rw-r--r--test/fuzz/fuzz-link-parser/directives.link3
7 files changed, 90 insertions, 0 deletions
diff --git a/man/systemd.link.xml b/man/systemd.link.xml
index 1dca495a03..e04618340b 100644
--- a/man/systemd.link.xml
+++ b/man/systemd.link.xml
@@ -700,6 +700,30 @@
<para>Takes a integer. Specifies the NIC transmit ring buffer size. When unset, the kernel's default will be used.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>RxFlowControl=</varname></term>
+ <listitem>
+ <para>Takes a boolean. When set, enables the receive flow control, also known as the ethernet
+ receive PAUSE message (generate and send ethernet PAUSE frames). When unset, the kernel's
+ default will be used.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>TxFlowControl=</varname></term>
+ <listitem>
+ <para>Takes a boolean. When set, enables the transmit flow control, also known as the ethernet
+ transmit PAUSE message (respond to received ethernet PAUSE frames). When unset, the kernel's
+ default will be used.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>AutoNegotiationFlowControl=</varname></term>
+ <listitem>
+ <para>Takes a boolean. When set, the auto negotiation enables the interface to exchange state
+ advertisements with the connected peer so that the two devices can agree on the ethernet
+ PAUSE configuration. 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 00a71d64a6..fe29af24d0 100644
--- a/src/shared/ethtool-util.c
+++ b/src/shared/ethtool-util.c
@@ -851,6 +851,55 @@ int ethtool_set_channels(int *fd, const char *ifname, netdev_channels *channels)
return 0;
}
+int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int autoneg) {
+ struct ethtool_pauseparam ecmd = {
+ .cmd = ETHTOOL_GPAUSEPARAM
+ };
+ 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 (rx >= 0 && ecmd.rx_pause != (uint32_t) rx) {
+ ecmd.rx_pause = rx;
+ need_update = true;
+ }
+
+ if (tx >= 0 && ecmd.tx_pause != (uint32_t) tx) {
+ ecmd.tx_pause = tx;
+ need_update = true;
+ }
+
+ if (autoneg >= 0 && ecmd.autoneg != (uint32_t) autoneg) {
+ ecmd.autoneg = autoneg;
+ need_update = true;
+ }
+
+ if (need_update) {
+ ecmd.cmd = ETHTOOL_SPAUSEPARAM;
+
+ r = ioctl(*fd, SIOCETHTOOL, &ifr);
+ if (r < 0)
+ return -errno;
+ }
+
+ return 0;
+}
+
int config_parse_channel(const char *unit,
const char *filename,
unsigned line,
diff --git a/src/shared/ethtool-util.h b/src/shared/ethtool-util.h
index c1d5d7590e..55c41f5bc7 100644
--- a/src/shared/ethtool-util.h
+++ b/src/shared/ethtool-util.h
@@ -103,6 +103,7 @@ int ethtool_set_glinksettings(int *ethtool_fd, const char *ifname,
int autonegotiation, uint32_t advertise[static N_ADVERTISE],
uint64_t speed, Duplex duplex, NetDevPort port);
int ethtool_set_channels(int *ethtool_fd, const char *ifname, netdev_channels *channels);
+int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int autoneg);
const char *duplex_to_string(Duplex d) _const_;
Duplex duplex_from_string(const char *d) _pure_;
diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf
index 43d1c59b94..2784246dd7 100644
--- a/src/udev/net/link-config-gperf.gperf
+++ b/src/udev/net/link-config-gperf.gperf
@@ -60,3 +60,6 @@ Link.CombinedChannels, config_parse_channel, 0,
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)
+Link.RxFlowControl, config_parse_tristate, 0, offsetof(link_config, rx_flow_control)
+Link.TxFlowControl, config_parse_tristate, 0, offsetof(link_config, tx_flow_control)
+Link.AutoNegotiationFlowControl, config_parse_tristate, 0, offsetof(link_config, autoneg_flow_control)
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 0332e99269..9c82759818 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -148,6 +148,9 @@ int link_load_one(link_config_ctx *ctx, const char *filename) {
.duplex = _DUP_INVALID,
.port = _NET_DEV_PORT_INVALID,
.autonegotiation = -1,
+ .rx_flow_control = -1,
+ .tx_flow_control = -1,
+ .autoneg_flow_control = -1,
};
for (i = 0; i < ELEMENTSOF(link->features); i++)
@@ -409,6 +412,10 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
log_warning_errno(r, "Could not set ring buffer of %s: %m", old_name);
}
+ r = ethtool_set_flow_control(&ctx->ethtool_fd, old_name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
+ if (r < 0)
+ log_warning_errno(r, "Could not set flow control 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 a85bd4b46b..827ebf436c 100644
--- a/src/udev/net/link-config.h
+++ b/src/udev/net/link-config.h
@@ -62,6 +62,9 @@ struct link_config {
int features[_NET_DEV_FEAT_MAX];
netdev_channels channels;
netdev_ring_param ring;
+ int rx_flow_control;
+ int tx_flow_control;
+ int autoneg_flow_control;
LIST_FIELDS(link_config, links);
};
diff --git a/test/fuzz/fuzz-link-parser/directives.link b/test/fuzz/fuzz-link-parser/directives.link
index b304ad0ddb..fe71d26d89 100644
--- a/test/fuzz/fuzz-link-parser/directives.link
+++ b/test/fuzz/fuzz-link-parser/directives.link
@@ -41,3 +41,6 @@ CombinedChannels=
Advertise=
RxBufferSize=
TxBufferSize=
+RxFlowControl=
+TxFlowControl=
+AutoNegotiationFlowControl=