Skip to content

Commit 2f70251

Browse files
committed
ethtool: rss: support setting flow hashing fields
Add support for ETHTOOL_SRXFH (setting hashing fields) in RSS_SET. The tricky part is dealing with symmetric hashing. In netlink user can change the hashing fields and symmetric hash in one request, in IOCTL the two used to be set via different uAPI requests. Since fields and hash function config are still separate driver callbacks - changes to the two are not atomic. Keep things simple and validate the settings against both pre- and post- change ones. Meaning that we will reject the config request if user tries to correct the flow fields and set input_xfrm in one request, or disables input_xfrm and makes flow fields non-symmetric. We can adjust it later if there's a real need. Starting simple feels right, and potentially partially applying the settings isn't nice, either. Reviewed-by: Gal Pressman <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent d3e2c7b commit 2f70251

File tree

4 files changed

+107
-10
lines changed

4 files changed

+107
-10
lines changed

Documentation/netlink/specs/ethtool.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2679,6 +2679,7 @@ operations:
26792679
- indir
26802680
- hkey
26812681
- input-xfrm
2682+
- flow-hash
26822683
-
26832684
name: rss-ntf
26842685
doc: |

Documentation/networking/ethtool-netlink.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2003,6 +2003,7 @@ Request contents:
20032003
``ETHTOOL_A_RSS_INDIR`` binary Indir table bytes
20042004
``ETHTOOL_A_RSS_HKEY`` binary Hash key bytes
20052005
``ETHTOOL_A_RSS_INPUT_XFRM`` u32 RSS input data transformation
2006+
``ETHTOOL_A_RSS_FLOW_HASH`` nested Header fields included in hash
20062007
===================================== ====== ==============================
20072008

20082009
``ETHTOOL_A_RSS_INDIR`` is the minimal RSS table the user expects. Kernel and
@@ -2464,7 +2465,7 @@ are netlink only.
24642465
``ETHTOOL_GPFLAGS`` ``ETHTOOL_MSG_PRIVFLAGS_GET``
24652466
``ETHTOOL_SPFLAGS`` ``ETHTOOL_MSG_PRIVFLAGS_SET``
24662467
``ETHTOOL_GRXFH`` ``ETHTOOL_MSG_RSS_GET``
2467-
``ETHTOOL_SRXFH`` n/a
2468+
``ETHTOOL_SRXFH`` ``ETHTOOL_MSG_RSS_SET``
24682469
``ETHTOOL_GGRO`` ``ETHTOOL_MSG_FEATURES_GET``
24692470
``ETHTOOL_SGRO`` ``ETHTOOL_MSG_FEATURES_SET``
24702471
``ETHTOOL_GRXRINGS`` n/a

net/ethtool/netlink.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ extern const struct nla_policy ethnl_module_set_policy[ETHTOOL_A_MODULE_POWER_MO
484484
extern const struct nla_policy ethnl_pse_get_policy[ETHTOOL_A_PSE_HEADER + 1];
485485
extern const struct nla_policy ethnl_pse_set_policy[ETHTOOL_A_PSE_MAX + 1];
486486
extern const struct nla_policy ethnl_rss_get_policy[ETHTOOL_A_RSS_START_CONTEXT + 1];
487-
extern const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_START_CONTEXT + 1];
487+
extern const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_FLOW_HASH + 1];
488488
extern const struct nla_policy ethnl_plca_get_cfg_policy[ETHTOOL_A_PLCA_HEADER + 1];
489489
extern const struct nla_policy ethnl_plca_set_cfg_policy[ETHTOOL_A_PLCA_MAX + 1];
490490
extern const struct nla_policy ethnl_plca_get_status_policy[ETHTOOL_A_PLCA_HEADER + 1];

net/ethtool/rss.c

Lines changed: 103 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -472,14 +472,49 @@ void ethtool_rss_notify(struct net_device *dev, u32 rss_context)
472472

473473
/* RSS_SET */
474474

475-
const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_START_CONTEXT + 1] = {
475+
#define RFH_MASK (RXH_L2DA | RXH_VLAN | RXH_IP_SRC | RXH_IP_DST | \
476+
RXH_L3_PROTO | RXH_L4_B_0_1 | RXH_L4_B_2_3 | \
477+
RXH_GTP_TEID | RXH_DISCARD)
478+
479+
static const struct nla_policy ethnl_rss_flows_policy[] = {
480+
[ETHTOOL_A_FLOW_ETHER] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
481+
[ETHTOOL_A_FLOW_IP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
482+
[ETHTOOL_A_FLOW_IP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
483+
[ETHTOOL_A_FLOW_TCP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
484+
[ETHTOOL_A_FLOW_UDP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
485+
[ETHTOOL_A_FLOW_SCTP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
486+
[ETHTOOL_A_FLOW_AH_ESP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
487+
[ETHTOOL_A_FLOW_TCP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
488+
[ETHTOOL_A_FLOW_UDP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
489+
[ETHTOOL_A_FLOW_SCTP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
490+
[ETHTOOL_A_FLOW_AH_ESP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
491+
[ETHTOOL_A_FLOW_AH4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
492+
[ETHTOOL_A_FLOW_ESP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
493+
[ETHTOOL_A_FLOW_AH6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
494+
[ETHTOOL_A_FLOW_ESP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
495+
[ETHTOOL_A_FLOW_GTPU4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
496+
[ETHTOOL_A_FLOW_GTPU6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
497+
[ETHTOOL_A_FLOW_GTPC4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
498+
[ETHTOOL_A_FLOW_GTPC6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
499+
[ETHTOOL_A_FLOW_GTPC_TEID4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
500+
[ETHTOOL_A_FLOW_GTPC_TEID6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
501+
[ETHTOOL_A_FLOW_GTPU_EH4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
502+
[ETHTOOL_A_FLOW_GTPU_EH6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
503+
[ETHTOOL_A_FLOW_GTPU_UL4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
504+
[ETHTOOL_A_FLOW_GTPU_UL6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
505+
[ETHTOOL_A_FLOW_GTPU_DL4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
506+
[ETHTOOL_A_FLOW_GTPU_DL6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
507+
};
508+
509+
const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_FLOW_HASH + 1] = {
476510
[ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
477511
[ETHTOOL_A_RSS_CONTEXT] = { .type = NLA_U32, },
478512
[ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_MIN(NLA_U32, 1),
479513
[ETHTOOL_A_RSS_INDIR] = { .type = NLA_BINARY, },
480514
[ETHTOOL_A_RSS_HKEY] = NLA_POLICY_MIN(NLA_BINARY, 1),
481515
[ETHTOOL_A_RSS_INPUT_XFRM] =
482516
NLA_POLICY_MAX(NLA_U32, RXH_XFRM_SYM_OR_XOR),
517+
[ETHTOOL_A_RSS_FLOW_HASH] = NLA_POLICY_NESTED(ethnl_rss_flows_policy),
483518
};
484519

485520
static int
@@ -504,6 +539,12 @@ ethnl_rss_set_validate(struct ethnl_req_info *req_info, struct genl_info *info)
504539
if (input_xfrm & ~ops->supported_input_xfrm)
505540
bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_INPUT_XFRM];
506541

542+
if (tb[ETHTOOL_A_RSS_FLOW_HASH] && !ops->set_rxfh_fields)
543+
bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_FLOW_HASH];
544+
if (request->rss_context &&
545+
tb[ETHTOOL_A_RSS_FLOW_HASH] && !ops->rxfh_per_ctx_fields)
546+
bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_FLOW_HASH];
547+
507548
if (bad_attr) {
508549
NL_SET_BAD_ATTR(info->extack, bad_attr);
509550
return -EOPNOTSUPP;
@@ -644,6 +685,59 @@ rss_check_rxfh_fields_sym(struct net_device *dev, struct genl_info *info,
644685
return 0;
645686
}
646687

688+
static int
689+
ethnl_set_rss_fields(struct net_device *dev, struct genl_info *info,
690+
u32 rss_context, struct rss_reply_data *data,
691+
bool xfrm_sym, bool *mod)
692+
{
693+
struct nlattr *flow_nest = info->attrs[ETHTOOL_A_RSS_FLOW_HASH];
694+
struct nlattr *flows[ETHTOOL_A_FLOW_MAX + 1];
695+
const struct ethtool_ops *ops;
696+
int i, ret;
697+
698+
ops = dev->ethtool_ops;
699+
700+
ret = rss_check_rxfh_fields_sym(dev, info, data, xfrm_sym);
701+
if (ret)
702+
return ret;
703+
704+
if (!flow_nest)
705+
return 0;
706+
707+
ret = nla_parse_nested(flows, ARRAY_SIZE(ethnl_rss_flows_policy) - 1,
708+
flow_nest, ethnl_rss_flows_policy, info->extack);
709+
if (ret < 0)
710+
return ret;
711+
712+
for (i = 1; i < __ETHTOOL_A_FLOW_CNT; i++) {
713+
struct ethtool_rxfh_fields fields = {
714+
.flow_type = ethtool_rxfh_ft_nl2ioctl[i],
715+
.rss_context = rss_context,
716+
};
717+
718+
if (!flows[i])
719+
continue;
720+
721+
fields.data = nla_get_u32(flows[i]);
722+
if (data->has_flow_hash && data->flow_hash[i] == fields.data)
723+
continue;
724+
725+
if (xfrm_sym && !ethtool_rxfh_config_is_sym(fields.data)) {
726+
NL_SET_ERR_MSG_ATTR(info->extack, flows[i],
727+
"conflict with xfrm-input");
728+
return -EINVAL;
729+
}
730+
731+
ret = ops->set_rxfh_fields(dev, &fields, info->extack);
732+
if (ret)
733+
return ret;
734+
735+
*mod = true;
736+
}
737+
738+
return 0;
739+
}
740+
647741
static void
648742
rss_set_ctx_update(struct ethtool_rxfh_context *ctx, struct nlattr **tb,
649743
struct rss_reply_data *data, struct ethtool_rxfh_param *rxfh)
@@ -673,11 +767,11 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
673767
struct rss_req_info *request = RSS_REQINFO(req_info);
674768
struct ethtool_rxfh_context *ctx = NULL;
675769
struct net_device *dev = req_info->dev;
770+
bool mod = false, fields_mod = false;
676771
struct ethtool_rxfh_param rxfh = {};
677772
struct nlattr **tb = info->attrs;
678773
struct rss_reply_data data = {};
679774
const struct ethtool_ops *ops;
680-
bool mod = false;
681775
int ret;
682776

683777
ops = dev->ethtool_ops;
@@ -710,14 +804,10 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
710804
* symmetric hashing is requested.
711805
*/
712806
if (!request->rss_context || ops->rxfh_per_ctx_key)
713-
xfrm_sym = !!rxfh.input_xfrm;
807+
xfrm_sym = rxfh.input_xfrm || data.input_xfrm;
714808
if (rxfh.input_xfrm == data.input_xfrm)
715809
rxfh.input_xfrm = RXH_XFRM_NO_CHANGE;
716810

717-
ret = rss_check_rxfh_fields_sym(dev, info, &data, xfrm_sym);
718-
if (ret)
719-
goto exit_clean_data;
720-
721811
mutex_lock(&dev->ethtool->rss_lock);
722812
if (request->rss_context) {
723813
ctx = xa_load(&dev->ethtool->rss_ctx, request->rss_context);
@@ -727,6 +817,11 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
727817
}
728818
}
729819

820+
ret = ethnl_set_rss_fields(dev, info, request->rss_context,
821+
&data, xfrm_sym, &fields_mod);
822+
if (ret)
823+
goto exit_unlock;
824+
730825
if (!mod)
731826
ret = 0; /* nothing to tell the driver */
732827
else if (!ops->set_rxfh)
@@ -753,7 +848,7 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
753848
exit_clean_data:
754849
rss_cleanup_data(&data.base);
755850

756-
return ret ?: mod;
851+
return ret ?: mod || fields_mod;
757852
}
758853

759854
const struct ethnl_request_ops ethnl_rss_request_ops = {

0 commit comments

Comments
 (0)