Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ethtool: rss: support removing contexts via Netlink

Implement removing additional RSS contexts via Netlink.
Technically it'd be possible to shoehorn the delete operation
into ethnl_request_ops-compatible handler. The code ends
up longer than open coded version, and I think we'll need
a custom way of sending notifications at some stage (if we
allow tying the context lifetime to the netlink socket, in
the future).

Link: https://patch.msgid.link/20250717234343.2328602-8-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+153 -1
+18
Documentation/netlink/specs/ethtool.yaml
··· 2706 2706 doc: | 2707 2707 Notification for creation of an additional RSS context. 2708 2708 notify: rss-create-act 2709 + - 2710 + name: rss-delete-act 2711 + doc: Delete an RSS context. 2712 + attribute-set: rss 2713 + do: 2714 + request: 2715 + attributes: 2716 + - header 2717 + - context 2718 + - 2719 + name: rss-delete-ntf 2720 + doc: | 2721 + Notification for deletion of an additional RSS context. 2722 + attribute-set: rss 2723 + event: 2724 + attributes: 2725 + - header 2726 + - context 2709 2727 2710 2728 mcast-groups: 2711 2729 list:
+14
Documentation/networking/ethtool-netlink.rst
··· 241 241 ``ETHTOOL_MSG_TSCONFIG_SET`` set hw timestamping configuration 242 242 ``ETHTOOL_MSG_RSS_SET`` set RSS settings 243 243 ``ETHTOOL_MSG_RSS_CREATE_ACT`` create an additional RSS context 244 + ``ETHTOOL_MSG_RSS_DELETE_ACT`` delete an additional RSS context 244 245 ===================================== ================================= 245 246 246 247 Kernel to userspace: ··· 298 297 ``ETHTOOL_MSG_RSS_NTF`` RSS settings notification 299 298 ``ETHTOOL_MSG_RSS_CREATE_ACT_REPLY`` create an additional RSS context 300 299 ``ETHTOOL_MSG_RSS_CREATE_NTF`` additional RSS context created 300 + ``ETHTOOL_MSG_RSS_DELETE_NTF`` additional RSS context deleted 301 301 ======================================== ================================= 302 302 303 303 ``GET`` requests are sent by userspace applications to retrieve device ··· 2042 2040 2043 2041 Create an additional RSS context, if ``ETHTOOL_A_RSS_CONTEXT`` is not 2044 2042 specified kernel will allocate one automatically. 2043 + 2044 + RSS_DELETE_ACT 2045 + ============== 2046 + 2047 + Request contents: 2048 + 2049 + ===================================== ====== ============================== 2050 + ``ETHTOOL_A_RSS_HEADER`` nested request header 2051 + ``ETHTOOL_A_RSS_CONTEXT`` u32 context number 2052 + ===================================== ====== ============================== 2053 + 2054 + Delete an additional RSS context. 2045 2055 2046 2056 PLCA_GET_CFG 2047 2057 ============
+1
net/ethtool/common.c
··· 1136 1136 netdev_err(dev, "device error, RSS context %d lost\n", context_id); 1137 1137 ctx = xa_erase(&dev->ethtool->rss_ctx, context_id); 1138 1138 kfree(ctx); 1139 + ethtool_rss_notify(dev, ETHTOOL_MSG_RSS_DELETE_NTF, context_id); 1139 1140 } 1140 1141 EXPORT_SYMBOL(ethtool_rxfh_context_lost);
+1
net/ethtool/ioctl.c
··· 1647 1647 !memchr_inv(ethtool_rxfh_context_key(ctx), 0, 1648 1648 ctx->key_size)); 1649 1649 } else if (rxfh_dev.rss_delete) { 1650 + ntf = ETHTOOL_MSG_RSS_DELETE_NTF; 1650 1651 ret = ops->remove_rxfh_context(dev, ctx, rxfh.rss_context, 1651 1652 extack); 1652 1653 } else {
+7
net/ethtool/netlink.c
··· 1527 1527 .policy = ethnl_rss_create_policy, 1528 1528 .maxattr = ARRAY_SIZE(ethnl_rss_create_policy) - 1, 1529 1529 }, 1530 + { 1531 + .cmd = ETHTOOL_MSG_RSS_DELETE_ACT, 1532 + .flags = GENL_UNS_ADMIN_PERM, 1533 + .doit = ethnl_rss_delete_doit, 1534 + .policy = ethnl_rss_delete_policy, 1535 + .maxattr = ARRAY_SIZE(ethnl_rss_delete_policy) - 1, 1536 + }, 1530 1537 }; 1531 1538 1532 1539 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
+2
net/ethtool/netlink.h
··· 487 487 extern const struct nla_policy ethnl_rss_get_policy[ETHTOOL_A_RSS_START_CONTEXT + 1]; 488 488 extern const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_FLOW_HASH + 1]; 489 489 extern const struct nla_policy ethnl_rss_create_policy[ETHTOOL_A_RSS_INPUT_XFRM + 1]; 490 + extern const struct nla_policy ethnl_rss_delete_policy[ETHTOOL_A_RSS_CONTEXT + 1]; 490 491 extern const struct nla_policy ethnl_plca_get_cfg_policy[ETHTOOL_A_PLCA_HEADER + 1]; 491 492 extern const struct nla_policy ethnl_plca_set_cfg_policy[ETHTOOL_A_PLCA_MAX + 1]; 492 493 extern const struct nla_policy ethnl_plca_get_status_policy[ETHTOOL_A_PLCA_HEADER + 1]; ··· 511 510 int ethnl_tsinfo_dumpit(struct sk_buff *skb, struct netlink_callback *cb); 512 511 int ethnl_tsinfo_done(struct netlink_callback *cb); 513 512 int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info); 513 + int ethnl_rss_delete_doit(struct sk_buff *skb, struct genl_info *info); 514 514 515 515 extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN]; 516 516 extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN];
+108 -1
net/ethtool/rss.c
··· 486 486 487 487 /* RSS_NTF */ 488 488 489 + static void ethnl_rss_delete_notify(struct net_device *dev, u32 rss_context) 490 + { 491 + struct sk_buff *ntf; 492 + size_t ntf_size; 493 + void *hdr; 494 + 495 + ntf_size = ethnl_reply_header_size() + 496 + nla_total_size(sizeof(u32)); /* _RSS_CONTEXT */ 497 + 498 + ntf = genlmsg_new(ntf_size, GFP_KERNEL); 499 + if (!ntf) 500 + goto out_warn; 501 + 502 + hdr = ethnl_bcastmsg_put(ntf, ETHTOOL_MSG_RSS_DELETE_NTF); 503 + if (!hdr) 504 + goto out_free_ntf; 505 + 506 + if (ethnl_fill_reply_header(ntf, dev, ETHTOOL_A_RSS_HEADER) || 507 + nla_put_u32(ntf, ETHTOOL_A_RSS_CONTEXT, rss_context)) 508 + goto out_free_ntf; 509 + 510 + genlmsg_end(ntf, hdr); 511 + if (ethnl_multicast(ntf, dev)) 512 + goto out_warn; 513 + 514 + return; 515 + 516 + out_free_ntf: 517 + nlmsg_free(ntf); 518 + out_warn: 519 + pr_warn_once("Failed to send a RSS delete notification"); 520 + } 521 + 489 522 void ethtool_rss_notify(struct net_device *dev, u32 type, u32 rss_context) 490 523 { 491 524 struct rss_req_info req_info = { 492 525 .rss_context = rss_context, 493 526 }; 494 527 495 - ethnl_notify(dev, type, &req_info.base); 528 + if (type == ETHTOOL_MSG_RSS_DELETE_NTF) 529 + ethnl_rss_delete_notify(dev, rss_context); 530 + else 531 + ethnl_notify(dev, type, &req_info.base); 496 532 } 497 533 498 534 /* RSS_SET */ ··· 1131 1095 err_unlock_free_ctx: 1132 1096 kfree(ctx); 1133 1097 goto exit_unlock; 1098 + } 1099 + 1100 + /* RSS_DELETE */ 1101 + 1102 + const struct nla_policy ethnl_rss_delete_policy[ETHTOOL_A_RSS_CONTEXT + 1] = { 1103 + [ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy), 1104 + [ETHTOOL_A_RSS_CONTEXT] = NLA_POLICY_MIN(NLA_U32, 1), 1105 + }; 1106 + 1107 + int ethnl_rss_delete_doit(struct sk_buff *skb, struct genl_info *info) 1108 + { 1109 + struct ethtool_rxfh_context *ctx; 1110 + struct nlattr **tb = info->attrs; 1111 + struct ethnl_req_info req = {}; 1112 + const struct ethtool_ops *ops; 1113 + struct net_device *dev; 1114 + u32 rss_context; 1115 + int ret; 1116 + 1117 + if (GENL_REQ_ATTR_CHECK(info, ETHTOOL_A_RSS_CONTEXT)) 1118 + return -EINVAL; 1119 + rss_context = nla_get_u32(tb[ETHTOOL_A_RSS_CONTEXT]); 1120 + 1121 + ret = ethnl_parse_header_dev_get(&req, tb[ETHTOOL_A_RSS_HEADER], 1122 + genl_info_net(info), info->extack, 1123 + true); 1124 + if (ret < 0) 1125 + return ret; 1126 + 1127 + dev = req.dev; 1128 + ops = dev->ethtool_ops; 1129 + 1130 + if (!ops->create_rxfh_context) 1131 + goto exit_free_dev; 1132 + 1133 + rtnl_lock(); 1134 + netdev_lock_ops(dev); 1135 + 1136 + ret = ethnl_ops_begin(dev); 1137 + if (ret < 0) 1138 + goto exit_dev_unlock; 1139 + 1140 + mutex_lock(&dev->ethtool->rss_lock); 1141 + ret = ethtool_check_rss_ctx_busy(dev, rss_context); 1142 + if (ret) 1143 + goto exit_unlock; 1144 + 1145 + ctx = xa_load(&dev->ethtool->rss_ctx, rss_context); 1146 + if (!ctx) { 1147 + ret = -ENOENT; 1148 + goto exit_unlock; 1149 + } 1150 + 1151 + ret = ops->remove_rxfh_context(dev, ctx, rss_context, info->extack); 1152 + if (ret) 1153 + goto exit_unlock; 1154 + 1155 + WARN_ON(xa_erase(&dev->ethtool->rss_ctx, rss_context) != ctx); 1156 + kfree(ctx); 1157 + 1158 + ethnl_rss_delete_notify(dev, rss_context); 1159 + 1160 + exit_unlock: 1161 + mutex_unlock(&dev->ethtool->rss_lock); 1162 + ethnl_ops_complete(dev); 1163 + exit_dev_unlock: 1164 + netdev_unlock_ops(dev); 1165 + rtnl_unlock(); 1166 + exit_free_dev: 1167 + ethnl_parse_header_dev_put(&req); 1168 + return ret; 1134 1169 }