]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev/net: support to set MDI-X mode
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 4 Feb 2022 04:06:27 +0000 (13:06 +0900)
committerLuca Boccassi <luca.boccassi@gmail.com>
Tue, 8 Feb 2022 15:47:46 +0000 (15:47 +0000)
Closes #22386.

man/systemd.link.xml
src/shared/ethtool-util.c
src/shared/ethtool-util.h
src/udev/net/link-config-gperf.gperf
src/udev/net/link-config.c
src/udev/net/link-config.h
test/fuzz/fuzz-link-parser/directives.link

index 700defeda6b86045e9f4daf7a302d5c1a0c41f65..55ca597c97a2d35bd69d006a50669c0a1b632191 100644 (file)
         </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>
index 489a29fa2e846819145a6605763f44aae8f6449a..6c9aeb1c6c6483411473bc34706dcf46e2f7ce52 100644 (file)
@@ -74,6 +74,15 @@ static const char* const port_table[] = {
 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",
@@ -835,6 +844,8 @@ static int get_gset(int fd, struct ifreq *ifr, struct ethtool_link_usettings **r
                 .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,
@@ -914,7 +925,8 @@ int ethtool_set_glinksettings(
                 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 = {};
@@ -926,7 +938,7 @@ int ethtool_set_glinksettings(
         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
@@ -957,7 +969,7 @@ int ethtool_set_glinksettings(
         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)
@@ -984,6 +996,13 @@ int ethtool_set_glinksettings(
                         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;
 
@@ -1261,6 +1280,48 @@ int config_parse_advertise(
         }
 }
 
+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,
index 8ca221bc090d736f2f206a2018e042376c8fb4c7..d07cfaefb26b919a2685e39ccbe421ac6f6a23a6 100644 (file)
@@ -168,9 +168,15 @@ int ethtool_get_permanent_hw_addr(int *ethtool_fd, const char *ifname, struct hw
 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);
@@ -183,12 +189,15 @@ int wol_options_to_string_alloc(uint32_t opts, char **ret);
 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);
index 7dde4ed59f5287b8a4ffc34e8b6aaf3b8c8d58fb..fe33507694dd92aa8be42e01e2c2f19412644efa 100644 (file)
@@ -102,6 +102,7 @@ Link.RxMaxCoalescedHighFrames,             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)
index 7e2da6088c4196d4cb7a0d57f564ea13f20f4d77..29e960acc04adb44b3999a78be9f9c8e1d1f5e57 100644 (file)
@@ -250,6 +250,7 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
                 .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,
         };
 
@@ -475,7 +476,7 @@ static int link_apply_ethtool_settings(Link *link, int *ethtool_fd) {
 
         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",
@@ -495,6 +496,10 @@ static int link_apply_ethtool_settings(Link *link, int *ethtool_fd) {
                 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);
index 0d1d117f2e1a2ab5b590115de21278285d54d6cb..90cb438e4b62ae23da6fe31834cdf628ef2daff0 100644 (file)
@@ -76,6 +76,7 @@ struct LinkConfig {
         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;
index a5773826c583f320b59eebcece7c166e372d2ca6..bffdce0ec95af6ccb02d810624e1d0a3a8347594 100644 (file)
@@ -80,6 +80,7 @@ RxMaxCoalescedHighFrames=
 TxCoalesceHighSec=
 TxMaxCoalescedHighFrames=
 CoalescePacketRateSampleIntervalSec=
+MDI=
 SR-IOVVirtualFunctions=
 [SR-IOV]
 VirtualFunction=