]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev: add {Receive,Transmit}ChecksumOffload= settings
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 27 Jan 2020 10:49:25 +0000 (19:49 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 3 Feb 2020 03:31:31 +0000 (12:31 +0900)
Closes #14661.

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

index 9104dd7f8f45289ca627d676c46ab89c0485a799..3574dd41a129511aad1d13a994b21e7611fa5e1b 100644 (file)
           </para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><varname>ReceiveChecksumOffload=</varname></term>
+        <listitem>
+          <para>Takes a boolean. If set to true, the hardware offload for checksumming of ingress
+          network packets is enabled. When unset, the kernel's default will be used.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>TransmitChecksumOffload=</varname></term>
+        <listitem>
+          <para>Takes a boolean. If set to true, the hardware offload for checksumming of egress
+          network packets is enabled. When unset, the kernel's default will be used.</para>
+        </listitem>
+      </varlistentry>
       <varlistentry>
         <term><varname>TCPSegmentationOffload=</varname></term>
         <listitem>
           When unset, the kernel's default will be used.</para>
         </listitem>
       </varlistentry>
-    <varlistentry>
+      <varlistentry>
         <term><varname>GenericReceiveOffload=</varname></term>
         <listitem>
           <para>Takes a boolean. If set to true, the Generic Receive Offload (GRO) is enabled.
index d9c1231fa8f670700424e8f6eeeb0c0fce18c530..00a71d64a638a6e718f44ec3340d7fa2e8b3b58b 100644 (file)
@@ -50,6 +50,8 @@ DEFINE_STRING_TABLE_LOOKUP(port, NetDevPort);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_port, port, NetDevPort, "Failed to parse Port setting");
 
 static const char* const netdev_feature_table[_NET_DEV_FEAT_MAX] = {
+        [NET_DEV_FEAT_RX]   = "rx-checksum",
+        [NET_DEV_FEAT_TX]   = "tx-checksum-", /* The suffix "-" means any feature beginning with "tx-checksum-" */
         [NET_DEV_FEAT_GSO]  = "tx-generic-segmentation",
         [NET_DEV_FEAT_GRO]  = "rx-gro",
         [NET_DEV_FEAT_LRO]  = "rx-lro",
@@ -498,22 +500,38 @@ static int get_stringset(int ethtool_fd, struct ifreq *ifr, int stringset_id, st
         return 0;
 }
 
-static int find_feature_index(struct ethtool_gstrings *strings, const char *feature) {
-        unsigned i;
+static int set_features_bit(
+                const struct ethtool_gstrings *strings,
+                const char *feature,
+                bool flag,
+                struct ethtool_sfeatures *sfeatures) {
+        bool found = false;
 
-        for (i = 0; i < strings->len; i++) {
-                if (streq((char *) &strings->data[i * ETH_GSTRING_LEN], feature))
-                        return i;
-        }
+        assert(strings);
+        assert(feature);
+        assert(sfeatures);
+
+        for (size_t i = 0; i < strings->len; i++)
+                if (streq((char *) &strings->data[i * ETH_GSTRING_LEN], feature) ||
+                    (endswith(feature, "-") && startswith((char *) &strings->data[i * ETH_GSTRING_LEN], feature))) {
+                        size_t block, bit;
 
-        return -ENODATA;
+                        block = i / 32;
+                        bit = i % 32;
+
+                        sfeatures->features[block].valid |= 1 << bit;
+                        SET_FLAG(sfeatures->features[block].requested, 1 << bit, flag);
+                        found = true;
+                }
+
+        return found ? 0 : -ENODATA;
 }
 
 int ethtool_set_features(int *ethtool_fd, const char *ifname, int *features) {
         _cleanup_free_ struct ethtool_gstrings *strings = NULL;
         struct ethtool_sfeatures *sfeatures;
-        int block, bit, i, r;
         struct ifreq ifr = {};
+        int i, r;
 
         if (*ethtool_fd < 0) {
                 r = ethtool_connect_or_warn(ethtool_fd, true);
@@ -531,27 +549,14 @@ int ethtool_set_features(int *ethtool_fd, const char *ifname, int *features) {
         sfeatures->cmd = ETHTOOL_SFEATURES;
         sfeatures->size = DIV_ROUND_UP(strings->len, 32U);
 
-        for (i = 0; i < _NET_DEV_FEAT_MAX; i++) {
-
+        for (i = 0; i < _NET_DEV_FEAT_MAX; i++)
                 if (features[i] != -1) {
-
-                        r = find_feature_index(strings, netdev_feature_table[i]);
+                        r = set_features_bit(strings, netdev_feature_table[i], features[i], sfeatures);
                         if (r < 0) {
-                                log_warning_errno(r, "ethtool: could not find feature: %s", netdev_feature_table[i]);
+                                log_warning_errno(r, "ethtool: could not find feature, ignoring: %s", netdev_feature_table[i]);
                                 continue;
                         }
-
-                        block = r / 32;
-                        bit = r % 32;
-
-                        sfeatures->features[block].valid |= 1 << bit;
-
-                        if (features[i])
-                                sfeatures->features[block].requested |= 1 << bit;
-                        else
-                                sfeatures->features[block].requested &= ~(1 << bit);
                 }
-        }
 
         ifr.ifr_data = (void *) sfeatures;
 
index 8d762876406bb4c6f948eda62fd6966949bc48bd..c1d5d7590ef9a2a777d8fa40d1922a0294a59922 100644 (file)
@@ -32,6 +32,8 @@ typedef enum WakeOnLan {
 } WakeOnLan;
 
 typedef enum NetDevFeature {
+        NET_DEV_FEAT_RX,
+        NET_DEV_FEAT_TX,
         NET_DEV_FEAT_GSO,
         NET_DEV_FEAT_GRO,
         NET_DEV_FEAT_LRO,
index 1e794efdcba97a3b33884fd9951943ac106987c1..43d1c59b9401c80f4be2c49ae94556e6c692b6ed 100644 (file)
@@ -45,6 +45,8 @@ Link.Duplex,                     config_parse_duplex,                   0,
 Link.AutoNegotiation,            config_parse_tristate,                 0,                             offsetof(link_config, autonegotiation)
 Link.WakeOnLan,                  config_parse_wol,                      0,                             offsetof(link_config, wol)
 Link.Port,                       config_parse_port,                     0,                             offsetof(link_config, port)
+Link.ReceiveChecksumOffload,     config_parse_tristate,                 0,                             offsetof(link_config, features[NET_DEV_FEAT_RX])
+Link.TransmitChecksumOffload,    config_parse_tristate,                 0,                             offsetof(link_config, features[NET_DEV_FEAT_TX])
 Link.GenericSegmentationOffload, config_parse_tristate,                 0,                             offsetof(link_config, features[NET_DEV_FEAT_GSO])
 Link.TCPSegmentationOffload,     config_parse_tristate,                 0,                             offsetof(link_config, features[NET_DEV_FEAT_TSO])
 Link.TCP6SegmentationOffload,    config_parse_tristate,                 0,                             offsetof(link_config, features[NET_DEV_FEAT_TSO6])
index ba8760f12bab808b87530ab8b4bfebaacc1d81ff..b304ad0ddb141923743e5ec30d01099e641652de 100644 (file)
@@ -26,6 +26,8 @@ Duplex=
 AutoNegotiation=
 WakeOnLan=
 Port=
+ReceiveChecksumOffload=
+TransmitChecksumOffload=
 GenericSegmentationOffload=
 TCPSegmentationOffload=
 TCP6SegmentationOffload=