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 | doc: | | 2706 | doc: | |
| 2707 | Notification for creation of an additional RSS context. | 2707 | Notification for creation of an additional RSS context. |
| 2708 | notify: rss-create-act | 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 | mcast-groups: | 2728 | mcast-groups: |
| 2711 | list: | 2729 | list: |
| @@ -241,6 +241,7 @@ Userspace to kernel: · 240 unmodified lines | |||
| 241 | ``ETHTOOL_MSG_TSCONFIG_SET`` set hw timestamping configuration | 241 | ``ETHTOOL_MSG_TSCONFIG_SET`` set hw timestamping configuration |
| 242 | ``ETHTOOL_MSG_RSS_SET`` set RSS settings | 242 | ``ETHTOOL_MSG_RSS_SET`` set RSS settings |
| 243 | ``ETHTOOL_MSG_RSS_CREATE_ACT`` create an additional RSS context | 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 | Kernel to userspace: | 247 | Kernel to userspace: |
| @@ -297,6 +298,7 @@ Kernel to userspace: · 50 unmodified lines | |||
| 297 | ``ETHTOOL_MSG_RSS_NTF`` RSS settings notification | 298 | ``ETHTOOL_MSG_RSS_NTF`` RSS settings notification |
| 298 | ``ETHTOOL_MSG_RSS_CREATE_ACT_REPLY`` create an additional RSS context | 299 | ``ETHTOOL_MSG_RSS_CREATE_ACT_REPLY`` create an additional RSS context |
| 299 | ``ETHTOOL_MSG_RSS_CREATE_NTF`` additional RSS context created | 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 | ``GET`` requests are sent by userspace applications to retrieve device | 304 | ``GET`` requests are sent by userspace applications to retrieve device |
| @@ -2041,6 +2043,18 @@ Kernel response contents: · 1738 unmodified lines | |||
| 2041 | Create an additional RSS context, if ``ETHTOOL_A_RSS_CONTEXT`` is not | 2043 | Create an additional RSS context, if ``ETHTOOL_A_RSS_CONTEXT`` is not |
| 2042 | specified kernel will allocate one automatically. | 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 | PLCA_GET_CFG | 2058 | PLCA_GET_CFG |
| 2045 | ============ | 2059 | ============ |
| 2046 | 2060 | ||
| @@ -842,6 +842,7 @@ enum { · 841 unmodified lines | |||
| 842 | ETHTOOL_MSG_TSCONFIG_SET, | 842 | ETHTOOL_MSG_TSCONFIG_SET, |
| 843 | ETHTOOL_MSG_RSS_SET, | 843 | ETHTOOL_MSG_RSS_SET, |
| 844 | ETHTOOL_MSG_RSS_CREATE_ACT, | 844 | ETHTOOL_MSG_RSS_CREATE_ACT, |
| 845 | ETHTOOL_MSG_RSS_DELETE_ACT, | ||
| 845 | 846 | ||
| 846 | __ETHTOOL_MSG_USER_CNT, | 847 | __ETHTOOL_MSG_USER_CNT, |
| 847 | ETHTOOL_MSG_USER_MAX = (__ETHTOOL_MSG_USER_CNT - 1) | 848 | ETHTOOL_MSG_USER_MAX = (__ETHTOOL_MSG_USER_CNT - 1) |
| @@ -901,6 +902,7 @@ enum { · 53 unmodified lines | |||
| 901 | ETHTOOL_MSG_RSS_NTF, | 902 | ETHTOOL_MSG_RSS_NTF, |
| 902 | ETHTOOL_MSG_RSS_CREATE_ACT_REPLY, | 903 | ETHTOOL_MSG_RSS_CREATE_ACT_REPLY, |
| 903 | ETHTOOL_MSG_RSS_CREATE_NTF, | 904 | ETHTOOL_MSG_RSS_CREATE_NTF, |
| 905 | ETHTOOL_MSG_RSS_DELETE_NTF, | ||
| 904 | 906 | ||
| 905 | __ETHTOOL_MSG_KERNEL_CNT, | 907 | __ETHTOOL_MSG_KERNEL_CNT, |
| 906 | ETHTOOL_MSG_KERNEL_MAX = (__ETHTOOL_MSG_KERNEL_CNT - 1) | 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 | netdev_err(dev, "device error, RSS context %d lost\n", context_id); | 1136 | netdev_err(dev, "device error, RSS context %d lost\n", context_id); |
| 1137 | ctx = xa_erase(&dev->ethtool->rss_ctx, context_id); | 1137 | ctx = xa_erase(&dev->ethtool->rss_ctx, context_id); |
| 1138 | kfree(ctx); | 1138 | kfree(ctx); |
| 1139 | ethtool_rss_notify(dev, ETHTOOL_MSG_RSS_DELETE_NTF, context_id); | ||
| 1139 | } | 1140 | } |
| 1140 | EXPORT_SYMBOL(ethtool_rxfh_context_lost); | 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 | !memchr_inv(ethtool_rxfh_context_key(ctx), 0, | 1647 | !memchr_inv(ethtool_rxfh_context_key(ctx), 0, |
| 1648 | ctx->key_size)); | 1648 | ctx->key_size)); |
| 1649 | } else if (rxfh_dev.rss_delete) { | 1649 | } else if (rxfh_dev.rss_delete) { |
| 1650 | ntf = ETHTOOL_MSG_RSS_DELETE_NTF; | ||
| 1650 | ret = ops->remove_rxfh_context(dev, ctx, rxfh.rss_context, | 1651 | ret = ops->remove_rxfh_context(dev, ctx, rxfh.rss_context, |
| 1651 | extack); | 1652 | extack); |
| 1652 | } else { | 1653 | } else { |
| @@ -1527,6 +1527,13 @@ static const struct genl_ops ethtool_genl_ops[] = { · 1526 unmodified lines | |||
| 1527 | .policy = ethnl_rss_create_policy, | 1527 | .policy = ethnl_rss_create_policy, |
| 1528 | .maxattr = ARRAY_SIZE(ethnl_rss_create_policy) - 1, | 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 | static const struct genl_multicast_group ethtool_nl_mcgrps[] = { | 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 | extern const struct nla_policy ethnl_rss_get_policy[ETHTOOL_A_RSS_START_CONTEXT + 1]; | 487 | extern const struct nla_policy ethnl_rss_get_policy[ETHTOOL_A_RSS_START_CONTEXT + 1]; |
| 488 | extern const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_FLOW_HASH + 1]; | 488 | extern const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_FLOW_HASH + 1]; |
| 489 | extern const struct nla_policy ethnl_rss_create_policy[ETHTOOL_A_RSS_INPUT_XFRM + 1]; | 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 | extern const struct nla_policy ethnl_plca_get_cfg_policy[ETHTOOL_A_PLCA_HEADER + 1]; | 491 | extern const struct nla_policy ethnl_plca_get_cfg_policy[ETHTOOL_A_PLCA_HEADER + 1]; |
| 491 | extern const struct nla_policy ethnl_plca_set_cfg_policy[ETHTOOL_A_PLCA_MAX + 1]; | 492 | extern const struct nla_policy ethnl_plca_set_cfg_policy[ETHTOOL_A_PLCA_MAX + 1]; |
| 492 | extern const struct nla_policy ethnl_plca_get_status_policy[ETHTOOL_A_PLCA_HEADER + 1]; | 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 | int ethnl_tsinfo_dumpit(struct sk_buff *skb, struct netlink_callback *cb); | 511 | int ethnl_tsinfo_dumpit(struct sk_buff *skb, struct netlink_callback *cb); |
| 511 | int ethnl_tsinfo_done(struct netlink_callback *cb); | 512 | int ethnl_tsinfo_done(struct netlink_callback *cb); |
| 512 | int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info); | 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 | extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN]; | 516 | extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN]; |
| 515 | extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN]; | 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 | /* RSS_NTF */ | 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 | void ethtool_rss_notify(struct net_device *dev, u32 type, u32 rss_context) | 522 | void ethtool_rss_notify(struct net_device *dev, u32 type, u32 rss_context) |
| 490 | { | 523 | { |
| 491 | struct rss_req_info req_info = { | 524 | struct rss_req_info req_info = { |
| 492 | .rss_context = rss_context, | 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 | /* RSS_SET */ | 534 | /* RSS_SET */ |
| @@ -1096,3 +1132,74 @@ err_unlock_free_ctx: · 597 unmodified lines | |||
| 1096 | kfree(ctx); | 1132 | kfree(ctx); |
| 1097 | goto exit_unlock; | 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 | } | ||