]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev/net: support to configure Energy Efficient Ethernet settings 36302/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 7 Feb 2025 04:47:36 +0000 (13:47 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 7 Feb 2025 04:47:41 +0000 (13:47 +0900)
Closes #36278.

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

index 9ddcaf7c09d08389da3c4eaf9ab19635fed1d66a..42ad2c27eae3cb59dcf3dece410e9049b14c9717 100644 (file)
     </variablelist>
   </refsect1>
 
+  <refsect1>
+    <title>[EnergyEfficientEthernet] Section Options</title>
+    <para>The [EnergyEfficientEthernet] section controls the Energy Efficient Ethernet (EEE) feature of the
+    interface, and accepts the following keys.</para>
+
+    <variablelist class='network-directives'>
+      <varlistentry>
+        <term><varname>Enabled=</varname></term>
+        <listitem>
+          <para>Takes a boolean argument. When true, the Energy Efficient Ethernet (EEE) feature will be
+          enabled on the interface. Defaults to unset, and the enablement of EEE will be unchanged.</para>
+
+          <xi:include href="version-info.xml" xpointer="v258"/>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>TxLowPowerIdle=</varname></term>
+        <listitem>
+          <para>Takes a boolean argument. When true, the transmit Low Power Idle (Tx-LPI) mode of the Energy
+          Efficient Ethernet feature will be enabled on the interface. Defaults to unset, and the enablement
+          of the mode will be unchanged.</para>
+
+          <xi:include href="version-info.xml" xpointer="v258"/>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>TxLowPowerIdleSec=</varname></term>
+        <listitem>
+          <para>Takes a timespan. This configures how long the interface should not enter the Low Power Idle
+          mode after transmission. If it is too short, may decrease performance. If it is too long, may not
+          gain energy saving. Defaults to unset, and the timespan will be unchanged.</para>
+
+          <xi:include href="version-info.xml" xpointer="v258"/>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>LinkMode=</varname></term>
+        <listitem>
+          <para>Takes a list of link modes, e.g. <literal>1000baset-full</literal>. See the table for
+          <varname>Advertise=</varname> setting in [Link] section in the above for possible values. This
+          configures the Energy Efficient Ethernet capable connection modes to be advertised. Defaults to
+          unset, and the advertised modes will be unchanged.</para>
+
+          <xi:include href="version-info.xml" xpointer="v258"/>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
   <refsect1>
     <title>Specifiers</title>
 
index aeed917a6a599df003aa3b252da788dae2cbb535..b29d2641ef2af1f1390d06a9623489b78e5d47fb 100644 (file)
@@ -1123,6 +1123,62 @@ int ethtool_set_nic_coalesce_settings(int *ethtool_fd, const char *ifname, const
         return RET_NERRNO(ioctl(*ethtool_fd, SIOCETHTOOL, &ifr));
 }
 
+int ethtool_set_eee_settings(
+                int *ethtool_fd,
+                const char *ifname,
+                int enabled,
+                int tx_lpi_enabled,
+                usec_t tx_lpi_timer_usec,
+                uint32_t advertise) {
+
+        int r;
+
+        assert(ethtool_fd);
+        assert(ifname);
+
+        if (enabled < 0 &&
+            tx_lpi_enabled < 0 &&
+            tx_lpi_timer_usec == USEC_INFINITY &&
+            advertise == 0)
+                return 0; /* Nothing requested. */
+
+        r = ethtool_connect(ethtool_fd);
+        if (r < 0)
+                return r;
+
+        struct ethtool_eee ecmd = {
+                .cmd = ETHTOOL_GEEE,
+        };
+        struct ifreq ifr = {
+                .ifr_data = (void*) &ecmd,
+        };
+
+        strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname);
+
+        if (ioctl(*ethtool_fd, SIOCETHTOOL, &ifr) < 0)
+                return -errno;
+
+        if (ecmd.supported == 0)
+                return 0; /* Unsupported. */
+
+        bool need_update = false;
+
+        if (enabled >= 0)
+                UPDATE(ecmd.eee_enabled, (uint32_t) enabled, need_update);
+        if (tx_lpi_enabled >= 0)
+                UPDATE(ecmd.tx_lpi_enabled, (uint32_t) tx_lpi_enabled, need_update);
+        if (tx_lpi_timer_usec != USEC_INFINITY)
+                UPDATE(ecmd.tx_lpi_timer, (uint32_t) MIN(DIV_ROUND_UP(tx_lpi_timer_usec, USEC_PER_MSEC), (usec_t) UINT32_MAX), need_update);
+        if (advertise != 0)
+                UPDATE(ecmd.advertised, advertise & ecmd.supported, need_update);
+
+        if (!need_update)
+                return 0; /* Nothing changed. */
+
+        ecmd.cmd = ETHTOOL_SEEE;
+        return RET_NERRNO(ioctl(*ethtool_fd, SIOCETHTOOL, &ifr));
+}
+
 int config_parse_advertise(
                 const char *unit,
                 const char *filename,
index d431b4452ce01f3db7aeff89ea7a971f6dcb509f..9aa36da227a838a65c533443f8b5f325798f3d3f 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "conf-parser.h"
 #include "ether-addr-util.h"
+#include "time-util.h"
 
 #define N_ADVERTISE 4
 
@@ -180,6 +181,13 @@ int ethtool_set_glinksettings(
 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);
+int ethtool_set_eee_settings(
+                int *ethtool_fd,
+                const char *ifname,
+                int enabled,
+                int tx_lpi_enabled,
+                usec_t tx_lpi_timer_usec,
+                uint32_t advertise);
 
 const char* duplex_to_string(Duplex d) _const_;
 Duplex duplex_from_string(const char *d) _pure_;
index 8535562998ee3db0eb4f3cbd155fc3e49c2728a7..4f4a016a4258f46b83b8fda804c84c3acdeeb6b6 100644 (file)
@@ -135,3 +135,8 @@ SR-IOV.QueryReceiveSideScaling,            config_parse_sr_iov_boolean,
 SR-IOV.Trust,                              config_parse_sr_iov_boolean,           0,                             offsetof(LinkConfig, sr_iov_by_section)
 SR-IOV.LinkState,                          config_parse_sr_iov_link_state,        0,                             offsetof(LinkConfig, sr_iov_by_section)
 SR-IOV.MACAddress,                         config_parse_sr_iov_mac,               0,                             offsetof(LinkConfig, sr_iov_by_section)
+/* ethtool EEE settings */
+EnergyEfficientEthernet.Enable,            config_parse_tristate,                 0,                             offsetof(LinkConfig, eee_enabled)
+EnergyEfficientEthernet.TxLowPowerIdle,    config_parse_tristate,                 0,                             offsetof(LinkConfig, eee_tx_lpi_enabled)
+EnergyEfficientEthernet.TxLowPowerIdleSec, config_parse_sec,                      0,                             offsetof(LinkConfig, eee_tx_lpi_timer_usec)
+EnergyEfficientEthernet.LinkMode,          config_parse_advertise,                0,                             offsetof(LinkConfig, eee_advertise)
index 5a4b7261bbd9ecd51f928101e4c010a2680d1c23..3400286566fbb9bf29f31113a274476c05f27c14 100644 (file)
@@ -263,6 +263,9 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
                 .coalesce.use_adaptive_tx_coalesce = -1,
                 .mdi = ETH_TP_MDI_INVALID,
                 .sr_iov_num_vfs = UINT32_MAX,
+                .eee_enabled = -1,
+                .eee_tx_lpi_enabled = -1,
+                .eee_tx_lpi_timer_usec = USEC_INFINITY,
         };
 
         FOREACH_ELEMENT(feature, config->features)
@@ -548,6 +551,10 @@ static int link_apply_ethtool_settings(Link *link, int *ethtool_fd) {
         if (r < 0)
                 log_link_warning_errno(link, r, "Could not set coalesce settings, ignoring: %m");
 
+        r = ethtool_set_eee_settings(ethtool_fd, name, config->eee_enabled, config->eee_tx_lpi_enabled, config->eee_tx_lpi_timer_usec, config->eee_advertise[0]);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Could not set energy efficient ethernet settings, ignoring: %m");
+
         return 0;
 }
 
index 6f4a1b1a63dc08c5e4500352d5fd184602a4ae2b..dcbc61359c57221d54344517cf0b997440ba999f 100644 (file)
@@ -107,6 +107,12 @@ struct LinkConfig {
         /* ethtool coalesce settings */
         netdev_coalesce_param coalesce;
 
+        /* ethtool energy efficient ethernet settings */
+        int eee_enabled;
+        int eee_tx_lpi_enabled;
+        usec_t eee_tx_lpi_timer_usec;
+        uint32_t eee_advertise[N_ADVERTISE];
+
         /* Rx RPS CPU mask */
         CPUSet *rps_cpu_mask;