mirror of
https://github.com/systemd/systemd
synced 2024-10-15 12:34:37 +00:00
parent
5d3b801764
commit
a34811e4ef
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -41,3 +41,6 @@ CombinedChannels=
|
|||
Advertise=
|
||||
RxBufferSize=
|
||||
TxBufferSize=
|
||||
RxFlowControl=
|
||||
TxFlowControl=
|
||||
AutoNegotiationFlowControl=
|
||||
|
|
Loading…
Reference in a new issue