mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-11 05:17:44 +03:00
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:
parent
4885626b56
commit
6cf0a20491
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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];
|
||||
|
Loading…
Reference in New Issue
Block a user