Closes #22386.
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>MDI=</varname></term>
+ <listitem>
+ <para>Specifies the medium dependent interface (MDI) mode for the interface. A MDI describes
+ the interface from a physical layer implementation to the physical medium used to carry the
+ transmission. Takes one of the following words: <literal>straight</literal> (or equivalently:
+ <literal>mdi</literal>), <literal>crossover</literal> (or equivalently:
+ <literal>mdi-x</literal>, <literal>mdix</literal>), and <literal>auto</literal>. When
+ <literal>straight</literal>, the MDI straight through mode will be used. When
+ <literal>crossover</literal>, the MDI crossover (MDI-X) mode will be used. When
+ <literal>auto</literal>, the MDI status is automatically detected. Defaults to unset, and the
+ kernel's default will be used.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>SR-IOVVirtualFunctions=</varname></term>
<listitem>
DEFINE_STRING_TABLE_LOOKUP(port, NetDevPort);
DEFINE_CONFIG_PARSE_ENUM(config_parse_port, port, NetDevPort, "Failed to parse Port setting");
+static const char* const mdi_table[] = {
+ [ETH_TP_MDI_INVALID] = "unknown",
+ [ETH_TP_MDI] = "mdi",
+ [ETH_TP_MDI_X] = "mdi-x",
+ [ETH_TP_MDI_AUTO] = "auto",
+};
+
+DEFINE_STRING_TABLE_LOOKUP_TO_STRING(mdi, int);
+
static const char* const netdev_feature_table[_NET_DEV_FEAT_MAX] = {
[NET_DEV_FEAT_SG] = "tx-scatter-gather",
[NET_DEV_FEAT_IP_CSUM] = "tx-checksum-ipv4",
.base.phy_address = ecmd.phy_address,
.base.autoneg = ecmd.autoneg,
.base.mdio_support = ecmd.mdio_support,
+ .base.eth_tp_mdix = ecmd.eth_tp_mdix,
+ .base.eth_tp_mdix_ctrl = ecmd.eth_tp_mdix_ctrl,
.link_modes.supported[0] = ecmd.supported,
.link_modes.advertising[0] = ecmd.advertising,
const uint32_t advertise[static N_ADVERTISE],
uint64_t speed,
Duplex duplex,
- NetDevPort port) {
+ NetDevPort port,
+ uint8_t mdi) {
_cleanup_free_ struct ethtool_link_usettings *u = NULL;
struct ifreq ifr = {};
assert(advertise);
if (autonegotiation < 0 && memeqzero(advertise, sizeof(uint32_t) * N_ADVERTISE) &&
- speed == 0 && duplex < 0 && port < 0)
+ speed == 0 && duplex < 0 && port < 0 && mdi == ETH_TP_MDI_INVALID)
return 0;
/* If autonegotiation is disabled, the speed and duplex represent the fixed link mode and are
if (r < 0) {
r = get_gset(*fd, &ifr, &u);
if (r < 0)
- return log_debug_errno(r, "ethtool: Cannot get device settings for %s : %m", ifname);
+ return log_debug_errno(r, "ethtool: Cannot get device settings for %s: %m", ifname);
}
if (speed > 0)
ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES - sizeof(uint32_t) * N_ADVERTISE);
}
+ if (mdi != ETH_TP_MDI_INVALID) {
+ if (u->base.eth_tp_mdix_ctrl == ETH_TP_MDI_INVALID)
+ log_debug("ethtool: setting MDI not supported for %s, ignoring.", ifname);
+ else
+ UPDATE(u->base.eth_tp_mdix_ctrl, mdi, changed);
+ }
+
if (!changed)
return 0;
}
}
+int config_parse_mdi(
+ 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) {
+
+ uint8_t *mdi = ASSERT_PTR(data);
+
+ assert(filename);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ *mdi = ETH_TP_MDI_INVALID;
+ return 0;
+ }
+
+ if (STR_IN_SET(rvalue, "mdi", "straight")) {
+ *mdi = ETH_TP_MDI;
+ return 0;
+ }
+
+ if (STR_IN_SET(rvalue, "mdi-x", "mdix", "crossover")) {
+ *mdi = ETH_TP_MDI_X;
+ return 0;
+ }
+
+ if (streq(rvalue, "auto")) {
+ *mdi = ETH_TP_MDI_AUTO;
+ return 0;
+ }
+
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Failed to parse %s= setting, ignoring assignment: %s", lvalue, rvalue);
+ return 0;
+}
+
int config_parse_ring_buffer_or_channel(
const char *unit,
const char *filename,
int ethtool_set_wol(int *ethtool_fd, const char *ifname, uint32_t wolopts, const uint8_t password[SOPASS_MAX]);
int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netdev_ring_param *ring);
int ethtool_set_features(int *ethtool_fd, const char *ifname, const int features[static _NET_DEV_FEAT_MAX]);
-int ethtool_set_glinksettings(int *ethtool_fd, const char *ifname,
- int autonegotiation, const uint32_t advertise[static N_ADVERTISE],
- uint64_t speed, Duplex duplex, NetDevPort port);
+int ethtool_set_glinksettings(
+ int *fd,
+ const char *ifname,
+ int autonegotiation,
+ const uint32_t advertise[static N_ADVERTISE],
+ uint64_t speed,
+ Duplex duplex,
+ NetDevPort port,
+ uint8_t mdi);
int ethtool_set_channels(int *ethtool_fd, const char *ifname, const netdev_channels *channels);
int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int autoneg);
int ethtool_set_nic_coalesce_settings(int *ethtool_fd, const char *ifname, const netdev_coalesce_param *coalesce);
const char *port_to_string(NetDevPort port) _const_;
NetDevPort port_from_string(const char *port) _pure_;
+const char *mdi_to_string(int mdi) _const_;
+
const char *ethtool_link_mode_bit_to_string(enum ethtool_link_mode_bit_indices val) _const_;
enum ethtool_link_mode_bit_indices ethtool_link_mode_bit_from_string(const char *str) _pure_;
CONFIG_PARSER_PROTOTYPE(config_parse_duplex);
CONFIG_PARSER_PROTOTYPE(config_parse_wol);
CONFIG_PARSER_PROTOTYPE(config_parse_port);
+CONFIG_PARSER_PROTOTYPE(config_parse_mdi);
CONFIG_PARSER_PROTOTYPE(config_parse_advertise);
CONFIG_PARSER_PROTOTYPE(config_parse_ring_buffer_or_channel);
CONFIG_PARSER_PROTOTYPE(config_parse_coalesce_u32);
Link.TxCoalesceHighSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.tx_coalesce_usecs_high)
Link.TxMaxCoalescedHighFrames, config_parse_coalesce_u32, 0, offsetof(LinkConfig, coalesce.tx_max_coalesced_frames_high)
Link.CoalescePacketRateSampleIntervalSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.rate_sample_interval)
+Link.MDI, config_parse_mdi, 0, offsetof(LinkConfig, mdi)
Link.SR-IOVVirtualFunctions, config_parse_sr_iov_num_vfs, 0, offsetof(LinkConfig, sr_iov_num_vfs)
SR-IOV.VirtualFunction, config_parse_sr_iov_uint32, 0, offsetof(LinkConfig, sr_iov_by_section)
SR-IOV.VLANId, config_parse_sr_iov_uint32, 0, offsetof(LinkConfig, sr_iov_by_section)
.txqueuelen = UINT32_MAX,
.coalesce.use_adaptive_rx_coalesce = -1,
.coalesce.use_adaptive_tx_coalesce = -1,
+ .mdi = ETH_TP_MDI_INVALID,
.sr_iov_num_vfs = UINT32_MAX,
};
r = ethtool_set_glinksettings(ethtool_fd, name,
config->autonegotiation, config->advertise,
- config->speed, config->duplex, config->port);
+ config->speed, config->duplex, config->port, config->mdi);
if (r < 0) {
if (config->autonegotiation >= 0)
log_link_warning_errno(link, r, "Could not %s auto negotiation, ignoring: %m",
if (config->port >= 0)
log_link_warning_errno(link, r, "Could not set port to '%s', ignoring: %m",
port_to_string(config->port));
+
+ if (config->mdi != ETH_TP_MDI_INVALID)
+ log_link_warning_errno(link, r, "Could not set MDI-X to '%s', ignoring: %m",
+ mdi_to_string(config->mdi));
}
r = ethtool_set_wol(ethtool_fd, name, config->wol, config->wol_password);
int tx_flow_control;
int autoneg_flow_control;
netdev_coalesce_param coalesce;
+ uint8_t mdi;
uint32_t sr_iov_num_vfs;
OrderedHashmap *sr_iov_by_section;
TxCoalesceHighSec=
TxMaxCoalescedHighFrames=
CoalescePacketRateSampleIntervalSec=
+MDI=
SR-IOVVirtualFunctions=
[SR-IOV]
VirtualFunction=