This work adds support for the equivalent of "ethtool advertise" to .link files?
http://lists.freedesktop.org/archives/systemd-devel/2015-April/030112.html
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>
</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>
<para>The TCP Segmentation Offload (TSO) when true enables
[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;
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;
* 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 = {};
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
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;
+}
_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 {
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);
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
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);
size_t speed;
Duplex duplex;
int autonegotiation;
+ uint32_t advertise;
WakeOnLan wol;
NetDevPort port;
int features[_NET_DEV_FEAT_MAX];