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).
Unified · Split
| @@ -2706,6 +2706,24 @@ operations: · 2705 unmodified lines | ||
| 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: |
| @@ -241,6 +241,7 @@ Userspace to kernel: · 240 unmodified lines | ||
| 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: |
| @@ -297,6 +298,7 @@ Kernel to userspace: · 50 unmodified lines | ||
| 297 | 298 | ``ETHTOOL_MSG_RSS_NTF`` RSS settings notification |
| 298 | 299 | ``ETHTOOL_MSG_RSS_CREATE_ACT_REPLY`` create an additional RSS context |
| 299 | 300 | ``ETHTOOL_MSG_RSS_CREATE_NTF`` additional RSS context created |
| 301 | + ``ETHTOOL_MSG_RSS_DELETE_NTF`` additional RSS context deleted | |
| 300 | 302 | ======================================== ================================= |
| 301 | 303 | |
| 302 | 304 | ``GET`` requests are sent by userspace applications to retrieve device |
| @@ -2041,6 +2043,18 @@ Kernel response contents: · 1738 unmodified lines | ||
| 2041 | 2043 | Create an additional RSS context, if ``ETHTOOL_A_RSS_CONTEXT`` is not |
| 2042 | 2044 | specified kernel will allocate one automatically. |
| 2043 | 2045 | |
| 2046 | +RSS_DELETE_ACT | |
| 2047 | +============== | |
| 2048 | + | |
| 2049 | +Request contents: | |
| 2050 | + | |
| 2051 | +===================================== ====== ============================== | |
| 2052 | + ``ETHTOOL_A_RSS_HEADER`` nested request header | |
| 2053 | + ``ETHTOOL_A_RSS_CONTEXT`` u32 context number | |
| 2054 | +===================================== ====== ============================== | |
| 2055 | + | |
| 2056 | +Delete an additional RSS context. | |
| 2057 | + | |
| 2044 | 2058 | PLCA_GET_CFG |
| 2045 | 2059 | ============ |
| 2046 | 2060 | |
| @@ -842,6 +842,7 @@ enum { · 841 unmodified lines | ||
| 842 | 842 | ETHTOOL_MSG_TSCONFIG_SET, |
| 843 | 843 | ETHTOOL_MSG_RSS_SET, |
| 844 | 844 | ETHTOOL_MSG_RSS_CREATE_ACT, |
| 845 | + ETHTOOL_MSG_RSS_DELETE_ACT, | |
| 845 | 846 | |
| 846 | 847 | __ETHTOOL_MSG_USER_CNT, |
| 847 | 848 | ETHTOOL_MSG_USER_MAX = (__ETHTOOL_MSG_USER_CNT - 1) |
| @@ -901,6 +902,7 @@ enum { · 53 unmodified lines | ||
| 901 | 902 | ETHTOOL_MSG_RSS_NTF, |
| 902 | 903 | ETHTOOL_MSG_RSS_CREATE_ACT_REPLY, |
| 903 | 904 | ETHTOOL_MSG_RSS_CREATE_NTF, |
| 905 | + ETHTOOL_MSG_RSS_DELETE_NTF, | |
| 904 | 906 | |
| 905 | 907 | __ETHTOOL_MSG_KERNEL_CNT, |
| 906 | 908 | ETHTOOL_MSG_KERNEL_MAX = (__ETHTOOL_MSG_KERNEL_CNT - 1) |
| @@ -1136,5 +1136,6 @@ void ethtool_rxfh_context_lost(struct net_device *dev, u32 context_id) · 1135 unmodified lines | ||
| 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); |
| @@ -1647,6 +1647,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, · 1646 unmodified lines | ||
| 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 { |
| @@ -1527,6 +1527,13 @@ static const struct genl_ops ethtool_genl_ops[] = { · 1526 unmodified lines | ||
| 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[] = { |
| @@ -487,6 +487,7 @@ extern const struct nla_policy ethnl_pse_set_policy[ETHTOOL_A_PSE_MAX + 1]; · 486 unmodified lines | ||
| 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]; |
| @@ -510,6 +511,7 @@ int ethnl_tsinfo_start(struct netlink_callback *cb); · 17 unmodified lines | ||
| 510 | 511 | int ethnl_tsinfo_dumpit(struct sk_buff *skb, struct netlink_callback *cb); |
| 511 | 512 | int ethnl_tsinfo_done(struct netlink_callback *cb); |
| 512 | 513 | int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info); |
| 514 | +int ethnl_rss_delete_doit(struct sk_buff *skb, struct genl_info *info); | |
| 513 | 515 | |
| 514 | 516 | extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN]; |
| 515 | 517 | extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN]; |
| @@ -486,13 +486,49 @@ int ethnl_rss_dumpit(struct sk_buff *skb, struct netlink_callback *cb) · 485 unmodified lines | ||
| 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 */ |
| @@ -1096,3 +1132,74 @@ err_unlock_free_ctx: · 597 unmodified lines | ||
| 1096 | 1132 | kfree(ctx); |
| 1097 | 1133 | goto exit_unlock; |
| 1098 | 1134 | } |
| 1135 | + | |
| 1136 | +/* RSS_DELETE */ | |
| 1137 | + | |
| 1138 | +const struct nla_policy ethnl_rss_delete_policy[ETHTOOL_A_RSS_CONTEXT + 1] = { | |
| 1139 | + [ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy), | |
| 1140 | + [ETHTOOL_A_RSS_CONTEXT] = NLA_POLICY_MIN(NLA_U32, 1), | |
| 1141 | +}; | |
| 1142 | + | |
| 1143 | +int ethnl_rss_delete_doit(struct sk_buff *skb, struct genl_info *info) | |
| 1144 | +{ | |
| 1145 | + struct ethtool_rxfh_context *ctx; | |
| 1146 | + struct nlattr **tb = info->attrs; | |
| 1147 | + struct ethnl_req_info req = {}; | |
| 1148 | + const struct ethtool_ops *ops; | |
| 1149 | + struct net_device *dev; | |
| 1150 | + u32 rss_context; | |
| 1151 | + int ret; | |
| 1152 | + | |
| 1153 | + if (GENL_REQ_ATTR_CHECK(info, ETHTOOL_A_RSS_CONTEXT)) | |
| 1154 | + return -EINVAL; | |
| 1155 | + rss_context = nla_get_u32(tb[ETHTOOL_A_RSS_CONTEXT]); | |
| 1156 | + | |
| 1157 | + ret = ethnl_parse_header_dev_get(&req, tb[ETHTOOL_A_RSS_HEADER], | |
| 1158 | + genl_info_net(info), info->extack, | |
| 1159 | + true); | |
| 1160 | + if (ret < 0) | |
| 1161 | + return ret; | |
| 1162 | + | |
| 1163 | + dev = req.dev; | |
| 1164 | + ops = dev->ethtool_ops; | |
| 1165 | + | |
| 1166 | + if (!ops->create_rxfh_context) | |
| 1167 | + goto exit_free_dev; | |
| 1168 | + | |
| 1169 | + rtnl_lock(); | |
| 1170 | + netdev_lock_ops(dev); | |
| 1171 | + | |
| 1172 | + ret = ethnl_ops_begin(dev); | |
| 1173 | + if (ret < 0) | |
| 1174 | + goto exit_dev_unlock; | |
| 1175 | + | |
| 1176 | + mutex_lock(&dev->ethtool->rss_lock); | |
| 1177 | + ret = ethtool_check_rss_ctx_busy(dev, rss_context); | |
| 1178 | + if (ret) | |
| 1179 | + goto exit_unlock; | |
| 1180 | + | |
| 1181 | + ctx = xa_load(&dev->ethtool->rss_ctx, rss_context); | |
| 1182 | + if (!ctx) { | |
| 1183 | + ret = -ENOENT; | |
| 1184 | + goto exit_unlock; | |
| 1185 | + } | |
| 1186 | + | |
| 1187 | + ret = ops->remove_rxfh_context(dev, ctx, rss_context, info->extack); | |
| 1188 | + if (ret) | |
| 1189 | + goto exit_unlock; | |
| 1190 | + | |
| 1191 | + WARN_ON(xa_erase(&dev->ethtool->rss_ctx, rss_context) != ctx); | |
| 1192 | + kfree(ctx); | |
| 1193 | + | |
| 1194 | + ethnl_rss_delete_notify(dev, rss_context); | |
| 1195 | + | |
| 1196 | +exit_unlock: | |
| 1197 | + mutex_unlock(&dev->ethtool->rss_lock); | |
| 1198 | + ethnl_ops_complete(dev); | |
| 1199 | +exit_dev_unlock: | |
| 1200 | + netdev_unlock_ops(dev); | |
| 1201 | + rtnl_unlock(); | |
| 1202 | +exit_free_dev: | |
| 1203 | + ethnl_parse_header_dev_put(&req); | |
| 1204 | + return ret; | |
| 1205 | +} | |