link: Add support to configure channels of the specified network device (#8882)
closes #8856
This commit is contained in:
committed by
Zbigniew Jędrzejewski-Szmek
parent
6b1ca2a948
commit
5f94520221
@@ -525,6 +525,30 @@
|
||||
Defaults to "unset".</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>RxChannels=</varname></term>
|
||||
<listitem>
|
||||
<para>Sets the number of receive channels (a number between 1 and 4294967295) .</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>TxChannels=</varname></term>
|
||||
<listitem>
|
||||
<para>Sets the number of transmit channels (a number between 1 and 4294967295).</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>OtherChannels=</varname></term>
|
||||
<listitem>
|
||||
<para>Sets the number of other channels (a number between 1 and 4294967295).</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>CombinedChannels=</varname></term>
|
||||
<listitem>
|
||||
<para>Sets the number of combined set channels (a number between 1 and 4294967295).</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
||||
@@ -568,3 +568,105 @@ int ethtool_set_glinksettings(int *fd, const char *ifname, struct link_config *l
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int config_parse_channel(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) {
|
||||
link_config *config = 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 channel value, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (k < 1) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Invalid %s value, ignoring: %s", lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (streq(lvalue, "RxChannels")) {
|
||||
config->channels.rx_count = k;
|
||||
config->channels.rx_count_set = true;
|
||||
} else if (streq(lvalue, "TxChannels")) {
|
||||
config->channels.tx_count = k;
|
||||
config->channels.tx_count_set = true;
|
||||
} else if (streq(lvalue, "OtherChannels")) {
|
||||
config->channels.other_count = k;
|
||||
config->channels.other_count_set = true;
|
||||
} else if (streq(lvalue, "CombinedChannels")) {
|
||||
config->channels.combined_count = k;
|
||||
config->channels.combined_count_set = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ethtool_set_channels(int *fd, const char *ifname, netdev_channels *channels) {
|
||||
struct ethtool_channels ecmd = {
|
||||
.cmd = ETHTOOL_GCHANNELS
|
||||
};
|
||||
struct ifreq ifr = {
|
||||
.ifr_data = (void*) &ecmd
|
||||
};
|
||||
|
||||
bool need_update = false;
|
||||
int r;
|
||||
|
||||
if (*fd < 0) {
|
||||
r = ethtool_connect(fd);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
|
||||
}
|
||||
|
||||
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
|
||||
|
||||
r = ioctl(*fd, SIOCETHTOOL, &ifr);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
if (channels->rx_count_set && ecmd.rx_count != channels->rx_count) {
|
||||
ecmd.rx_count = channels->rx_count;
|
||||
need_update = true;
|
||||
}
|
||||
|
||||
if (channels->tx_count_set && ecmd.tx_count != channels->tx_count) {
|
||||
ecmd.tx_count = channels->tx_count;
|
||||
need_update = true;
|
||||
}
|
||||
|
||||
if (channels->other_count_set && ecmd.other_count != channels->other_count) {
|
||||
ecmd.other_count = channels->other_count;
|
||||
need_update = true;
|
||||
}
|
||||
|
||||
if (channels->combined_count_set && ecmd.combined_count != channels->combined_count) {
|
||||
ecmd.combined_count = channels->combined_count;
|
||||
need_update = true;
|
||||
}
|
||||
|
||||
if (need_update) {
|
||||
ecmd.cmd = ETHTOOL_SCHANNELS;
|
||||
|
||||
r = ioctl(*fd, SIOCETHTOOL, &ifr);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -72,6 +72,18 @@ struct ethtool_link_usettings {
|
||||
} link_modes;
|
||||
};
|
||||
|
||||
typedef struct netdev_channels {
|
||||
uint32_t rx_count;
|
||||
uint32_t tx_count;
|
||||
uint32_t other_count;
|
||||
uint32_t combined_count;
|
||||
|
||||
bool rx_count_set;
|
||||
bool tx_count_set;
|
||||
bool other_count_set;
|
||||
bool combined_count_set;
|
||||
} netdev_channels;
|
||||
|
||||
int ethtool_connect(int *ret);
|
||||
|
||||
int ethtool_get_driver(int *fd, const char *ifname, char **ret);
|
||||
@@ -79,6 +91,7 @@ int ethtool_set_speed(int *fd, const char *ifname, unsigned int speed, Duplex du
|
||||
int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol);
|
||||
int ethtool_set_features(int *fd, const char *ifname, NetDevFeature *features);
|
||||
int ethtool_set_glinksettings(int *fd, const char *ifname, struct link_config *link);
|
||||
int ethtool_set_channels(int *fd, const char *ifname, netdev_channels *channels);
|
||||
|
||||
const char *duplex_to_string(Duplex d) _const_;
|
||||
Duplex duplex_from_string(const char *d) _pure_;
|
||||
@@ -92,3 +105,4 @@ NetDevPort port_from_string(const char *port) _pure_;
|
||||
int config_parse_duplex(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);
|
||||
int config_parse_wol(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);
|
||||
int config_parse_port(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);
|
||||
int config_parse_channel(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);
|
||||
|
||||
@@ -47,3 +47,7 @@ Link.TCP6SegmentationOffload, config_parse_tristate, 0,
|
||||
Link.UDPSegmentationOffload, config_parse_warn_compat, DISABLED_LEGACY, 0
|
||||
Link.GenericReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_GRO])
|
||||
Link.LargeReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_LRO])
|
||||
Link.RxChannels, config_parse_channel, 0, 0
|
||||
Link.TxChannels, config_parse_channel, 0, 0
|
||||
Link.OtherChannels, config_parse_channel, 0, 0
|
||||
Link.CombinedChannels, config_parse_channel, 0, 0
|
||||
|
||||
@@ -393,6 +393,12 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Could not set offload features of %s: %m", old_name);
|
||||
|
||||
if (config->channels.rx_count_set || config->channels.tx_count_set || config->channels.other_count_set || config->channels.combined_count_set) {
|
||||
r = ethtool_set_channels(&ctx->ethtool_fd, old_name, &config->channels);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Could not set channels of %s: %m", old_name);
|
||||
}
|
||||
|
||||
ifindex = udev_device_get_ifindex(device);
|
||||
if (ifindex <= 0) {
|
||||
log_warning("Could not find ifindex");
|
||||
|
||||
@@ -62,6 +62,7 @@ struct link_config {
|
||||
WakeOnLan wol;
|
||||
NetDevPort port;
|
||||
NetDevFeature features[_NET_DEV_FEAT_MAX];
|
||||
netdev_channels channels;
|
||||
|
||||
LIST_FIELDS(link_config, links);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user