udev/net: add support for the equivalent of "ethtool advertise" to .link files

This work adds support for the equivalent of "ethtool advertise" to .link files?
http://lists.freedesktop.org/archives/systemd-devel/2015-April/030112.html
This commit is contained in:
Susant Sahani 2017-09-17 00:06:56 +05:30 committed by Zbigniew Jędrzejewski-Szmek
parent 4885626b56
commit 6cf0a20491
6 changed files with 194 additions and 9 deletions

View File

@ -370,8 +370,8 @@
Takes a boolean value. Unset by default, which means that the kernel default
will be used.</para>
<para>Note that if autonegotiation is enabled, speed and duplex settings are
read-only. If autonegotation is disabled, speed and duplex settings are writable
<para>Note that if autonegotiation is enabled, speed, duplex and advertise settings are
read-only. If autonegotation is disabled, speed, duplex and advertise settings are writable
if the driver supports multiple link modes.</para>
</listitem>
</varlistentry>
@ -478,6 +478,77 @@
</variablelist>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Advertise=</varname></term>
<listitem>
<para>This sets what speeds and duplex modes of operation are advertised for auto-negotiation.
The supported values are:
<table>
<title>Supported advertise values</title>
<tgroup cols='3'>
<colspec colname='Advertise' />
<colspec colname='Speed' />
<colspec colname='Duplex Mode' />
<thead><row>
<entry>Advertise</entry>
<entry>Speed (Mbps)</entry>
<entry>Duplex Mode</entry>
</row></thead>
<tbody>
<row><entry><literal>10baset-half</literal></entry>
<entry>10</entry><entry>half</entry></row>
<row><entry><literal>10baset-full</literal></entry>
<entry>10</entry><entry>full</entry></row>
<row><entry><literal>100baset-half</literal></entry>
<entry>100</entry><entry>half</entry></row>
<row><entry><literal>100baset-full</literal></entry>
<entry>100</entry><entry>full</entry></row>
<row><entry><literal>1000baset-half</literal></entry>
<entry>1000</entry><entry>half</entry></row>
<row><entry><literal>1000baset-full</literal></entry>
<entry>1000</entry><entry>full</entry></row>
<row><entry><literal>10000baset-full</literal></entry>
<entry>10000</entry><entry>full</entry></row>
<row><entry><literal>2500basex-full</literal></entry>
<entry>2500</entry><entry>full</entry></row>
<row><entry><literal>1000basekx-full</literal></entry>
<entry>1000</entry><entry>full</entry></row>
<row><entry><literal>10000basekx4-full</literal></entry>
<entry>10000</entry><entry>full</entry></row>
<row><entry><literal>10000basekr-full</literal></entry>
<entry>10000</entry><entry>full</entry></row>
<row><entry><literal>10000baser-fec</literal></entry>
<entry>10000</entry><entry>full</entry></row>
<row><entry><literal>20000basemld2-full</literal></entry>
<entry>20000</entry><entry>full</entry></row>
<row><entry><literal>20000basekr2-full</literal></entry>
<entry>20000</entry><entry>full</entry></row>
</tbody>
</tgroup>
</table>
By default this is unset, i.e. all possible modes will be advertised.
This option may be specified more than once, in which case all specified speeds and modes are advertised.
If the empty string is assigned to this option, the list is reset, and all prior assignments have no effect.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>TCPSegmentationOffload=</varname></term>
<listitem>

View File

@ -56,6 +56,25 @@ static const char* const netdev_feature_table[_NET_DEV_FEAT_MAX] = {
[NET_DEV_FEAT_TSO6] = "tx-tcp6-segmentation",
};
static const char* const advertise_table[_NET_DEV_ADVERTISE_MAX] = {
[NET_DEV_ADVERTISE_10BASET_HALF] = "10baset-half",
[NET_DEV_ADVERTISE_10BASET_FULL] = "10baset-full",
[NET_DEV_ADVERTISE_100BASET_HALF] = "100baset-half",
[NET_DEV_ADVERTISE_100BASET_FULL] = "100baset-full",
[NET_DEV_ADVERTISE_1000BASET_HALF] = "1000baset-half",
[NET_DEV_ADVERTISE_1000BASET_FULL] = "1000baset-full",
[NET_DEV_ADVERTISE_10000BASET_FULL] = "10000baset-full",
[NET_DEV_ADVERTISE_2500BASEX_FULL] = "2500basex-full",
[NET_DEV_ADVERTISE_1000BASEKX_FULL] = "1000basekx-full",
[NET_DEV_ADVERTISE_10000BASEKX4_FULL] = "10000basekx4-full",
[NET_DEV_ADVERTISE_10000BASEKR_FULL] = "10000basekr-full",
[NET_DEV_ADVERTISE_10000BASER_FEC] = "10000baser-fec",
[NET_DEV_ADVERTISE_20000BASEMLD2_Full] = "20000basemld2-full",
[NET_DEV_ADVERTISE_20000BASEKR2_Full] = "20000basekr2-full",
};
DEFINE_STRING_TABLE_LOOKUP(advertise, NetDevAdvertise);
int ethtool_connect(int *ret) {
int fd;
@ -501,6 +520,8 @@ static int set_sset(int fd, struct ifreq *ifr, const struct ethtool_link_usettin
ecmd.phy_address = u->base.phy_address;
ecmd.autoneg = u->base.autoneg;
ecmd.mdio_support = u->base.mdio_support;
ecmd.eth_tp_mdix = u->base.eth_tp_mdix;
ecmd.eth_tp_mdix_ctrl = u->base.eth_tp_mdix_ctrl;
ifr->ifr_data = (void *) &ecmd;
@ -517,7 +538,6 @@ static int set_sset(int fd, struct ifreq *ifr, const struct ethtool_link_usettin
* link mode; if the link is down, the speed is 0, %SPEED_UNKNOWN or the highest
* enabled speed and @duplex is %DUPLEX_UNKNOWN or the best enabled duplex mode.
*/
int ethtool_set_glinksettings(int *fd, const char *ifname, struct link_config *link) {
_cleanup_free_ struct ethtool_link_usettings *u = NULL;
struct ifreq ifr = {};
@ -554,6 +574,13 @@ int ethtool_set_glinksettings(int *fd, const char *ifname, struct link_config *l
u->base.autoneg = link->autonegotiation;
if (link->advertise) {
uint32_t advertise[ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32] = {};
advertise[0] = link->advertise;
memcpy(&u->link_modes.advertising, advertise, ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES);
}
if (u->base.cmd == ETHTOOL_GLINKSETTINGS)
r = set_slinksettings(*fd, &ifr, u);
else
@ -665,3 +692,56 @@ int ethtool_set_channels(int *fd, const char *ifname, netdev_channels *channels)
return 0;
}
int config_parse_advertise(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;
NetDevAdvertise mode, a = 0;
const char *p;
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
if (isempty(rvalue)) {
/* Empty string resets the value. */
config->advertise = 0;
return 0;
}
for (p = rvalue;;) {
_cleanup_free_ char *w = NULL;
r = extract_first_word(&p, &w, NULL, 0);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split advertise modes '%s', ignoring: %m", rvalue);
break;
}
if (r == 0)
break;
mode = advertise_from_string(w);
if (mode == _NET_DEV_ADVERTISE_INVALID) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse advertise mode, ignoring: %s", w);
continue;
}
a |= mode;
}
config->advertise |= a;
return 0;
}

View File

@ -53,7 +53,27 @@ typedef enum NetDevPort {
_NET_DEV_PORT_INVALID = -1
} NetDevPort;
typedef enum NetDevAdvertise {
NET_DEV_ADVERTISE_10BASET_HALF = 1 << ETHTOOL_LINK_MODE_10baseT_Half_BIT,
NET_DEV_ADVERTISE_10BASET_FULL = 1 << ETHTOOL_LINK_MODE_10baseT_Full_BIT,
NET_DEV_ADVERTISE_100BASET_HALF = 1 << ETHTOOL_LINK_MODE_100baseT_Half_BIT,
NET_DEV_ADVERTISE_100BASET_FULL = 1 << ETHTOOL_LINK_MODE_100baseT_Full_BIT,
NET_DEV_ADVERTISE_1000BASET_HALF = 1 << ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
NET_DEV_ADVERTISE_1000BASET_FULL = 1 << ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
NET_DEV_ADVERTISE_10000BASET_FULL = 1 << ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
NET_DEV_ADVERTISE_2500BASEX_FULL = 1 << ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
NET_DEV_ADVERTISE_1000BASEKX_FULL = 1 << ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
NET_DEV_ADVERTISE_10000BASEKX4_FULL = 1 << ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
NET_DEV_ADVERTISE_10000BASEKR_FULL = 1 << ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
NET_DEV_ADVERTISE_10000BASER_FEC = 1 << ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
NET_DEV_ADVERTISE_20000BASEMLD2_Full = 1 << ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT,
NET_DEV_ADVERTISE_20000BASEKR2_Full = 1 << ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
_NET_DEV_ADVERTISE_MAX,
_NET_DEV_ADVERTISE_INVALID = -1,
} NetDevAdvertise;
#define ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32 (SCHAR_MAX)
#define ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES (4 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32)
/* layout of the struct passed from/to userland */
struct ethtool_link_usettings {
@ -96,7 +116,11 @@ WakeOnLan wol_from_string(const char *wol) _pure_;
const char *port_to_string(NetDevPort port) _const_;
NetDevPort port_from_string(const char *port) _pure_;
const char *advertise_to_string(NetDevAdvertise advertise) _const_;
NetDevAdvertise advertise_from_string(const char *advertise) _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);
int config_parse_advertise(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);

View File

@ -51,3 +51,4 @@ Link.RxChannels, config_parse_channel, 0,
Link.TxChannels, config_parse_channel, 0, 0
Link.OtherChannels, config_parse_channel, 0, 0
Link.CombinedChannels, config_parse_channel, 0, 0
Link.Advertise, config_parse_advertise, 0, 0

View File

@ -376,13 +376,21 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
if (config->port != _NET_DEV_PORT_INVALID)
log_warning_errno(r, "Could not set port (%s) of %s: %m", port_to_string(config->port), old_name);
speed = DIV_ROUND_UP(config->speed, 1000000);
if (r == -EOPNOTSUPP)
r = ethtool_set_speed(&ctx->ethtool_fd, old_name, speed, config->duplex);
if (config->advertise)
log_warning_errno(r, "Could not set advertise mode to 0x%X: %m", config->advertise);
if (r < 0)
log_warning_errno(r, "Could not set speed or duplex of %s to %u Mbps (%s): %m",
old_name, speed, duplex_to_string(config->duplex));
if (config->speed) {
speed = DIV_ROUND_UP(config->speed, 1000000);
if (r == -EOPNOTSUPP) {
r = ethtool_set_speed(&ctx->ethtool_fd, old_name, speed, config->duplex);
if (r < 0)
log_warning_errno(r, "Could not set speed of %s to %u Mbps: %m", old_name, speed);
}
}
if (config->duplex !=_DUP_INVALID)
log_warning_errno(r, "Could not set duplex of %s to (%s): %m", old_name, duplex_to_string(config->duplex));
}
r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);

View File

@ -54,6 +54,7 @@ struct link_config {
size_t speed;
Duplex duplex;
int autonegotiation;
uint32_t advertise;
WakeOnLan wol;
NetDevPort port;
int features[_NET_DEV_FEAT_MAX];