udev: support to update flow control parameter

Closes #14770.
This commit is contained in:
Yu Watanabe 2020-02-07 20:06:44 +09:00
parent 5d3b801764
commit a34811e4ef
7 changed files with 90 additions and 0 deletions

View File

@ -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>

View File

@ -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,

View File

@ -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_;

View File

@ -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)

View File

@ -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");

View File

@ -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);
};

View File

@ -41,3 +41,6 @@ CombinedChannels=
Advertise=
RxBufferSize=
TxBufferSize=
RxFlowControl=
TxFlowControl=
AutoNegotiationFlowControl=