]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ethtool: rss: support setting input-xfrm via Netlink
authorJakub Kicinski <kuba@kernel.org>
Wed, 16 Jul 2025 00:03:29 +0000 (17:03 -0700)
committerJakub Kicinski <kuba@kernel.org>
Thu, 17 Jul 2025 23:13:59 +0000 (16:13 -0700)
Support configuring symmetric hashing via Netlink.
We have the flow field config prepared as part of SET handling,
so scan it for conflicts instead of querying the driver again.

Reviewed-by: Gal Pressman <gal@nvidia.com>
Link: https://patch.msgid.link/20250716000331.1378807-10-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Documentation/netlink/specs/ethtool.yaml
Documentation/networking/ethtool-netlink.rst
net/ethtool/common.c
net/ethtool/common.h
net/ethtool/ioctl.c
net/ethtool/rss.c

index d0a9c4120a1941c9334456d62b10c85f24b6af82..41f26d58f2f9408255b6b28d46eac0a8df6db7a9 100644 (file)
@@ -2678,6 +2678,7 @@ operations:
             - hfunc
             - indir
             - hkey
+            - input-xfrm
     -
       name: rss-ntf
       doc: |
index 1830354495aee6e3e6596903ed433a87efab09f2..2214d2ce346ab1bcae36bdb9b8b95e0a82d58a72 100644 (file)
@@ -2002,6 +2002,7 @@ Request contents:
   ``ETHTOOL_A_RSS_HFUNC``              u32     RSS hash func
   ``ETHTOOL_A_RSS_INDIR``              binary  Indir table bytes
   ``ETHTOOL_A_RSS_HKEY``               binary  Hash key bytes
+  ``ETHTOOL_A_RSS_INPUT_XFRM``         u32     RSS input data transformation
 =====================================  ======  ==============================
 
 ``ETHTOOL_A_RSS_INDIR`` is the minimal RSS table the user expects. Kernel and
@@ -2012,9 +2013,6 @@ device needs at least 8 entries - the real table in use will end up being
 of 2, so tables which size is not a power of 2 will likely be rejected.
 Using table of size 0 will reset the indirection table to the default.
 
-Note that, at present, only a subset of RSS configuration can be accomplished
-over Netlink.
-
 PLCA_GET_CFG
 ============
 
index 459cf25e763eb12af695aff43fb55d7dbc355b68..4dcb4194f3ce19eadae24f2cf3756d9a262da6ba 100644 (file)
@@ -806,6 +806,21 @@ out_free:
        return rc;
 }
 
+/* Check if fields configured for flow hash are symmetric - if src is included
+ * so is dst and vice versa.
+ */
+int ethtool_rxfh_config_is_sym(u64 rxfh)
+{
+       bool sym;
+
+       sym = rxfh == (rxfh & (RXH_IP_SRC | RXH_IP_DST |
+                              RXH_L4_B_0_1 | RXH_L4_B_2_3));
+       sym &= !!(rxfh & RXH_IP_SRC)   == !!(rxfh & RXH_IP_DST);
+       sym &= !!(rxfh & RXH_L4_B_0_1) == !!(rxfh & RXH_L4_B_2_3);
+
+       return sym;
+}
+
 int ethtool_check_ops(const struct ethtool_ops *ops)
 {
        if (WARN_ON(ops->set_coalesce && !ops->supported_coalesce_params))
index c41db1595621e135a3025b564c96afcdb49f5bd8..b2718afe38b56deb65cce6734287c6e0526e7683 100644 (file)
@@ -44,6 +44,7 @@ int ethtool_check_max_channel(struct net_device *dev,
                              struct ethtool_channels channels,
                              struct genl_info *info);
 int ethtool_check_rss_ctx_busy(struct net_device *dev, u32 rss_context);
+int ethtool_rxfh_config_is_sym(u64 rxfh);
 
 void ethtool_ringparam_get_cfg(struct net_device *dev,
                               struct ethtool_ringparam *param,
index 830623678cb3bdb54536c07b0a3b13dcb628192d..2dfeaaa099fb3a6981bd6480e7dab3a2718092af 100644 (file)
@@ -1027,9 +1027,7 @@ static int ethtool_check_xfrm_rxfh(u32 input_xfrm, u64 rxfh)
         */
        if ((input_xfrm != RXH_XFRM_NO_CHANGE &&
             input_xfrm & (RXH_XFRM_SYM_XOR | RXH_XFRM_SYM_OR_XOR)) &&
-           ((rxfh & ~(RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3)) ||
-            (!!(rxfh & RXH_IP_SRC) ^ !!(rxfh & RXH_IP_DST)) ||
-            (!!(rxfh & RXH_L4_B_0_1) ^ !!(rxfh & RXH_L4_B_2_3))))
+           !ethtool_rxfh_config_is_sym(rxfh))
                return -EINVAL;
 
        return 0;
index 55260830639f97dffd413b6aede923244d366e3d..79de013da28804c55c22ad6f2a2f1d22b4530578 100644 (file)
@@ -478,6 +478,8 @@ const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_START_CONTEXT + 1] =
        [ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_MIN(NLA_U32, 1),
        [ETHTOOL_A_RSS_INDIR] = { .type = NLA_BINARY, },
        [ETHTOOL_A_RSS_HKEY] = NLA_POLICY_MIN(NLA_BINARY, 1),
+       [ETHTOOL_A_RSS_INPUT_XFRM] =
+               NLA_POLICY_MAX(NLA_U32, RXH_XFRM_SYM_OR_XOR),
 };
 
 static int
@@ -487,6 +489,7 @@ ethnl_rss_set_validate(struct ethnl_req_info *req_info, struct genl_info *info)
        struct rss_req_info *request = RSS_REQINFO(req_info);
        struct nlattr **tb = info->attrs;
        struct nlattr *bad_attr = NULL;
+       u32 input_xfrm;
 
        if (request->rss_context && !ops->create_rxfh_context)
                bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_CONTEXT];
@@ -494,8 +497,13 @@ ethnl_rss_set_validate(struct ethnl_req_info *req_info, struct genl_info *info)
        if (request->rss_context && !ops->rxfh_per_ctx_key) {
                bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_HFUNC];
                bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_HKEY];
+               bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_INPUT_XFRM];
        }
 
+       input_xfrm = nla_get_u32_default(tb[ETHTOOL_A_RSS_INPUT_XFRM], 0);
+       if (input_xfrm & ~ops->supported_input_xfrm)
+               bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_INPUT_XFRM];
+
        if (bad_attr) {
                NL_SET_BAD_ATTR(info->extack, bad_attr);
                return -EOPNOTSUPP;
@@ -609,6 +617,33 @@ rss_set_prep_hkey(struct net_device *dev, struct genl_info *info,
        return 0;
 }
 
+static int
+rss_check_rxfh_fields_sym(struct net_device *dev, struct genl_info *info,
+                         struct rss_reply_data *data, bool xfrm_sym)
+{
+       struct nlattr **tb = info->attrs;
+       int i;
+
+       if (!xfrm_sym)
+               return 0;
+       if (!data->has_flow_hash) {
+               NL_SET_ERR_MSG_ATTR(info->extack, tb[ETHTOOL_A_RSS_INPUT_XFRM],
+                                   "hash field config not reported");
+               return -EINVAL;
+       }
+
+       for (i = 1; i < __ETHTOOL_A_FLOW_CNT; i++)
+               if (data->flow_hash[i] >= 0 &&
+                   !ethtool_rxfh_config_is_sym(data->flow_hash[i])) {
+                       NL_SET_ERR_MSG_ATTR(info->extack,
+                                           tb[ETHTOOL_A_RSS_INPUT_XFRM],
+                                           "hash field config is not symmetric");
+                       return -EINVAL;
+               }
+
+       return 0;
+}
+
 static void
 rss_set_ctx_update(struct ethtool_rxfh_context *ctx, struct nlattr **tb,
                   struct rss_reply_data *data, struct ethtool_rxfh_param *rxfh)
@@ -627,16 +662,18 @@ rss_set_ctx_update(struct ethtool_rxfh_context *ctx, struct nlattr **tb,
        }
        if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE)
                ctx->hfunc = rxfh->hfunc;
+       if (rxfh->input_xfrm != RXH_XFRM_NO_CHANGE)
+               ctx->input_xfrm = rxfh->input_xfrm;
 }
 
 static int
 ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
 {
+       bool indir_reset = false, indir_mod, xfrm_sym = false;
        struct rss_req_info *request = RSS_REQINFO(req_info);
        struct ethtool_rxfh_context *ctx = NULL;
        struct net_device *dev = req_info->dev;
        struct ethtool_rxfh_param rxfh = {};
-       bool indir_reset = false, indir_mod;
        struct nlattr **tb = info->attrs;
        struct rss_reply_data data = {};
        const struct ethtool_ops *ops;
@@ -666,7 +703,20 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
        if (ret)
                goto exit_free_indir;
 
-       rxfh.input_xfrm = RXH_XFRM_NO_CHANGE;
+       rxfh.input_xfrm = data.input_xfrm;
+       ethnl_update_u8(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM], &mod);
+       /* For drivers which don't support input_xfrm it will be set to 0xff
+        * in the RSS context info. In all other case input_xfrm != 0 means
+        * symmetric hashing is requested.
+        */
+       if (!request->rss_context || ops->rxfh_per_ctx_key)
+               xfrm_sym = !!rxfh.input_xfrm;
+       if (rxfh.input_xfrm == data.input_xfrm)
+               rxfh.input_xfrm = RXH_XFRM_NO_CHANGE;
+
+       ret = rss_check_rxfh_fields_sym(dev, info, &data, xfrm_sym);
+       if (ret)
+               goto exit_clean_data;
 
        mutex_lock(&dev->ethtool->rss_lock);
        if (request->rss_context) {