1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <net/netdev_lock.h> 4 5 #include "../core/dev.h" 6 #include "common.h" 7 #include "netlink.h" 8 9 struct rss_req_info { 10 struct ethnl_req_info base; 11 u32 rss_context; 12 }; 13 14 struct rss_reply_data { 15 struct ethnl_reply_data base; 16 bool has_flow_hash; 17 bool no_key_fields; 18 u32 indir_size; 19 u32 hkey_size; 20 u32 hfunc; 21 u32 input_xfrm; 22 u32 *indir_table; 23 u8 *hkey; 24 int flow_hash[__ETHTOOL_A_FLOW_CNT]; 25 }; 26 27 static const u8 ethtool_rxfh_ft_nl2ioctl[] = { 28 [ETHTOOL_A_FLOW_ETHER] = ETHER_FLOW, 29 [ETHTOOL_A_FLOW_IP4] = IPV4_FLOW, 30 [ETHTOOL_A_FLOW_IP6] = IPV6_FLOW, 31 [ETHTOOL_A_FLOW_TCP4] = TCP_V4_FLOW, 32 [ETHTOOL_A_FLOW_UDP4] = UDP_V4_FLOW, 33 [ETHTOOL_A_FLOW_SCTP4] = SCTP_V4_FLOW, 34 [ETHTOOL_A_FLOW_AH_ESP4] = AH_ESP_V4_FLOW, 35 [ETHTOOL_A_FLOW_TCP6] = TCP_V6_FLOW, 36 [ETHTOOL_A_FLOW_UDP6] = UDP_V6_FLOW, 37 [ETHTOOL_A_FLOW_SCTP6] = SCTP_V6_FLOW, 38 [ETHTOOL_A_FLOW_AH_ESP6] = AH_ESP_V6_FLOW, 39 [ETHTOOL_A_FLOW_AH4] = AH_V4_FLOW, 40 [ETHTOOL_A_FLOW_ESP4] = ESP_V4_FLOW, 41 [ETHTOOL_A_FLOW_AH6] = AH_V6_FLOW, 42 [ETHTOOL_A_FLOW_ESP6] = ESP_V6_FLOW, 43 [ETHTOOL_A_FLOW_GTPU4] = GTPU_V4_FLOW, 44 [ETHTOOL_A_FLOW_GTPU6] = GTPU_V6_FLOW, 45 [ETHTOOL_A_FLOW_GTPC4] = GTPC_V4_FLOW, 46 [ETHTOOL_A_FLOW_GTPC6] = GTPC_V6_FLOW, 47 [ETHTOOL_A_FLOW_GTPC_TEID4] = GTPC_TEID_V4_FLOW, 48 [ETHTOOL_A_FLOW_GTPC_TEID6] = GTPC_TEID_V6_FLOW, 49 [ETHTOOL_A_FLOW_GTPU_EH4] = GTPU_EH_V4_FLOW, 50 [ETHTOOL_A_FLOW_GTPU_EH6] = GTPU_EH_V6_FLOW, 51 [ETHTOOL_A_FLOW_GTPU_UL4] = GTPU_UL_V4_FLOW, 52 [ETHTOOL_A_FLOW_GTPU_UL6] = GTPU_UL_V6_FLOW, 53 [ETHTOOL_A_FLOW_GTPU_DL4] = GTPU_DL_V4_FLOW, 54 [ETHTOOL_A_FLOW_GTPU_DL6] = GTPU_DL_V6_FLOW, 55 }; 56 57 #define RSS_REQINFO(__req_base) \ 58 container_of(__req_base, struct rss_req_info, base) 59 60 #define RSS_REPDATA(__reply_base) \ 61 container_of(__reply_base, struct rss_reply_data, base) 62 63 const struct nla_policy ethnl_rss_get_policy[] = { 64 [ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy), 65 [ETHTOOL_A_RSS_CONTEXT] = { .type = NLA_U32 }, 66 [ETHTOOL_A_RSS_START_CONTEXT] = { .type = NLA_U32 }, 67 }; 68 69 static int 70 rss_parse_request(struct ethnl_req_info *req_info, 71 const struct genl_info *info, 72 struct nlattr **tb, 73 struct netlink_ext_ack *extack) 74 { 75 struct rss_req_info *request = RSS_REQINFO(req_info); 76 77 if (tb[ETHTOOL_A_RSS_CONTEXT]) 78 request->rss_context = nla_get_u32(tb[ETHTOOL_A_RSS_CONTEXT]); 79 if (tb[ETHTOOL_A_RSS_START_CONTEXT]) { 80 NL_SET_BAD_ATTR(extack, tb[ETHTOOL_A_RSS_START_CONTEXT]); 81 return -EINVAL; 82 } 83 84 return 0; 85 } 86 87 static void 88 rss_prepare_flow_hash(const struct rss_req_info *req, struct net_device *dev, 89 struct rss_reply_data *data, const struct genl_info *info) 90 { 91 int i; 92 93 data->has_flow_hash = false; 94 95 if (!dev->ethtool_ops->get_rxfh_fields) 96 return; 97 if (req->rss_context && !dev->ethtool_ops->rxfh_per_ctx_fields) 98 return; 99 100 mutex_lock(&dev->ethtool->rss_lock); 101 for (i = 1; i < __ETHTOOL_A_FLOW_CNT; i++) { 102 struct ethtool_rxfh_fields fields = { 103 .flow_type = ethtool_rxfh_ft_nl2ioctl[i], 104 .rss_context = req->rss_context, 105 }; 106 107 if (dev->ethtool_ops->get_rxfh_fields(dev, &fields)) { 108 data->flow_hash[i] = -1; /* Unsupported */ 109 continue; 110 } 111 112 data->flow_hash[i] = fields.data; 113 data->has_flow_hash = true; 114 } 115 mutex_unlock(&dev->ethtool->rss_lock); 116 } 117 118 static int 119 rss_get_data_alloc(struct net_device *dev, struct rss_reply_data *data) 120 { 121 const struct ethtool_ops *ops = dev->ethtool_ops; 122 u32 total_size, indir_bytes; 123 u8 *rss_config; 124 125 data->indir_size = 0; 126 data->hkey_size = 0; 127 if (ops->get_rxfh_indir_size) 128 data->indir_size = ops->get_rxfh_indir_size(dev); 129 if (ops->get_rxfh_key_size) 130 data->hkey_size = ops->get_rxfh_key_size(dev); 131 132 indir_bytes = data->indir_size * sizeof(u32); 133 total_size = indir_bytes + data->hkey_size; 134 rss_config = kzalloc(total_size, GFP_KERNEL); 135 if (!rss_config) 136 return -ENOMEM; 137 138 data->indir_table = (u32 *)rss_config; 139 if (data->hkey_size) 140 data->hkey = rss_config + indir_bytes; 141 142 return 0; 143 } 144 145 static void rss_get_data_free(const struct rss_reply_data *data) 146 { 147 kfree(data->indir_table); 148 } 149 150 static int 151 rss_prepare_get(const struct rss_req_info *request, struct net_device *dev, 152 struct rss_reply_data *data, const struct genl_info *info) 153 { 154 const struct ethtool_ops *ops = dev->ethtool_ops; 155 struct ethtool_rxfh_param rxfh = {}; 156 int ret; 157 158 ret = ethnl_ops_begin(dev); 159 if (ret < 0) 160 return ret; 161 mutex_lock(&dev->ethtool->rss_lock); 162 163 ret = rss_get_data_alloc(dev, data); 164 if (ret) 165 goto out_unlock; 166 167 rxfh.indir_size = data->indir_size; 168 rxfh.indir = data->indir_table; 169 rxfh.key_size = data->hkey_size; 170 rxfh.key = data->hkey; 171 172 ret = ops->get_rxfh(dev, &rxfh); 173 if (ret) { 174 rss_get_data_free(data); 175 goto out_unlock; 176 } 177 178 data->hfunc = rxfh.hfunc; 179 data->input_xfrm = rxfh.input_xfrm; 180 out_unlock: 181 mutex_unlock(&dev->ethtool->rss_lock); 182 ethnl_ops_complete(dev); 183 return ret; 184 } 185 186 static void 187 __rss_prepare_ctx(struct net_device *dev, struct rss_reply_data *data, 188 struct ethtool_rxfh_context *ctx) 189 { 190 if (WARN_ON_ONCE(data->indir_size != ctx->indir_size || 191 data->hkey_size != ctx->key_size)) 192 return; 193 194 data->no_key_fields = !dev->ethtool_ops->rxfh_per_ctx_key; 195 196 data->hfunc = ctx->hfunc; 197 data->input_xfrm = ctx->input_xfrm; 198 memcpy(data->indir_table, ethtool_rxfh_context_indir(ctx), 199 data->indir_size * sizeof(u32)); 200 if (data->hkey_size) 201 memcpy(data->hkey, ethtool_rxfh_context_key(ctx), 202 data->hkey_size); 203 } 204 205 static int 206 rss_prepare_ctx(const struct rss_req_info *request, struct net_device *dev, 207 struct rss_reply_data *data, const struct genl_info *info) 208 { 209 struct ethtool_rxfh_context *ctx; 210 u32 total_size, indir_bytes; 211 u8 *rss_config; 212 int ret; 213 214 mutex_lock(&dev->ethtool->rss_lock); 215 ctx = xa_load(&dev->ethtool->rss_ctx, request->rss_context); 216 if (!ctx) { 217 ret = -ENOENT; 218 goto out_unlock; 219 } 220 221 data->indir_size = ctx->indir_size; 222 data->hkey_size = ctx->key_size; 223 224 indir_bytes = data->indir_size * sizeof(u32); 225 total_size = indir_bytes + data->hkey_size; 226 rss_config = kzalloc(total_size, GFP_KERNEL); 227 if (!rss_config) { 228 ret = -ENOMEM; 229 goto out_unlock; 230 } 231 232 data->indir_table = (u32 *)rss_config; 233 if (data->hkey_size) 234 data->hkey = rss_config + indir_bytes; 235 236 __rss_prepare_ctx(dev, data, ctx); 237 238 ret = 0; 239 out_unlock: 240 mutex_unlock(&dev->ethtool->rss_lock); 241 return ret; 242 } 243 244 static int 245 rss_prepare(const struct rss_req_info *request, struct net_device *dev, 246 struct rss_reply_data *data, const struct genl_info *info) 247 { 248 rss_prepare_flow_hash(request, dev, data, info); 249 250 /* Coming from RSS_SET, driver may only have flow_hash_fields ops */ 251 if (!dev->ethtool_ops->get_rxfh) 252 return 0; 253 254 if (request->rss_context) 255 return rss_prepare_ctx(request, dev, data, info); 256 return rss_prepare_get(request, dev, data, info); 257 } 258 259 static int 260 rss_prepare_data(const struct ethnl_req_info *req_base, 261 struct ethnl_reply_data *reply_base, 262 const struct genl_info *info) 263 { 264 struct rss_reply_data *data = RSS_REPDATA(reply_base); 265 struct rss_req_info *request = RSS_REQINFO(req_base); 266 struct net_device *dev = reply_base->dev; 267 const struct ethtool_ops *ops; 268 269 ops = dev->ethtool_ops; 270 if (!ops->get_rxfh) 271 return -EOPNOTSUPP; 272 273 /* Some drivers don't handle rss_context */ 274 if (request->rss_context && !ops->create_rxfh_context) 275 return -EOPNOTSUPP; 276 277 return rss_prepare(request, dev, data, info); 278 } 279 280 static int 281 rss_reply_size(const struct ethnl_req_info *req_base, 282 const struct ethnl_reply_data *reply_base) 283 { 284 const struct rss_reply_data *data = RSS_REPDATA(reply_base); 285 int len; 286 287 len = nla_total_size(sizeof(u32)) + /* _RSS_CONTEXT */ 288 nla_total_size(sizeof(u32)) + /* _RSS_HFUNC */ 289 nla_total_size(sizeof(u32)) + /* _RSS_INPUT_XFRM */ 290 nla_total_size(sizeof(u32) * data->indir_size) + /* _RSS_INDIR */ 291 nla_total_size(data->hkey_size) + /* _RSS_HKEY */ 292 nla_total_size(0) + /* _RSS_FLOW_HASH */ 293 nla_total_size(sizeof(u32)) * ETHTOOL_A_FLOW_MAX + 294 0; 295 296 return len; 297 } 298 299 static int 300 rss_fill_reply(struct sk_buff *skb, const struct ethnl_req_info *req_base, 301 const struct ethnl_reply_data *reply_base) 302 { 303 const struct rss_reply_data *data = RSS_REPDATA(reply_base); 304 struct rss_req_info *request = RSS_REQINFO(req_base); 305 306 if (request->rss_context && 307 nla_put_u32(skb, ETHTOOL_A_RSS_CONTEXT, request->rss_context)) 308 return -EMSGSIZE; 309 310 if ((data->indir_size && 311 nla_put(skb, ETHTOOL_A_RSS_INDIR, 312 sizeof(u32) * data->indir_size, data->indir_table))) 313 return -EMSGSIZE; 314 315 if (!data->no_key_fields && 316 ((data->hfunc && 317 nla_put_u32(skb, ETHTOOL_A_RSS_HFUNC, data->hfunc)) || 318 (data->input_xfrm && 319 nla_put_u32(skb, ETHTOOL_A_RSS_INPUT_XFRM, data->input_xfrm)) || 320 (data->hkey_size && 321 nla_put(skb, ETHTOOL_A_RSS_HKEY, data->hkey_size, data->hkey)))) 322 return -EMSGSIZE; 323 324 if (data->has_flow_hash) { 325 struct nlattr *nest; 326 int i; 327 328 nest = nla_nest_start(skb, ETHTOOL_A_RSS_FLOW_HASH); 329 if (!nest) 330 return -EMSGSIZE; 331 332 for (i = 1; i < __ETHTOOL_A_FLOW_CNT; i++) { 333 if (data->flow_hash[i] >= 0 && 334 nla_put_uint(skb, i, data->flow_hash[i])) { 335 nla_nest_cancel(skb, nest); 336 return -EMSGSIZE; 337 } 338 } 339 340 nla_nest_end(skb, nest); 341 } 342 343 return 0; 344 } 345 346 static void rss_cleanup_data(struct ethnl_reply_data *reply_base) 347 { 348 const struct rss_reply_data *data = RSS_REPDATA(reply_base); 349 350 rss_get_data_free(data); 351 } 352 353 struct rss_nl_dump_ctx { 354 unsigned long ifindex; 355 unsigned long ctx_idx; 356 357 /* User wants to only dump contexts from given ifindex */ 358 unsigned int match_ifindex; 359 unsigned int start_ctx; 360 }; 361 362 static struct rss_nl_dump_ctx *rss_dump_ctx(struct netlink_callback *cb) 363 { 364 NL_ASSERT_CTX_FITS(struct rss_nl_dump_ctx); 365 366 return (struct rss_nl_dump_ctx *)cb->ctx; 367 } 368 369 int ethnl_rss_dump_start(struct netlink_callback *cb) 370 { 371 const struct genl_info *info = genl_info_dump(cb); 372 struct rss_nl_dump_ctx *ctx = rss_dump_ctx(cb); 373 struct ethnl_req_info req_info = {}; 374 struct nlattr **tb = info->attrs; 375 int ret; 376 377 /* Filtering by context not supported */ 378 if (tb[ETHTOOL_A_RSS_CONTEXT]) { 379 NL_SET_BAD_ATTR(info->extack, tb[ETHTOOL_A_RSS_CONTEXT]); 380 return -EINVAL; 381 } 382 if (tb[ETHTOOL_A_RSS_START_CONTEXT]) { 383 ctx->start_ctx = nla_get_u32(tb[ETHTOOL_A_RSS_START_CONTEXT]); 384 ctx->ctx_idx = ctx->start_ctx; 385 } 386 387 ret = ethnl_parse_header_dev_get(&req_info, 388 tb[ETHTOOL_A_RSS_HEADER], 389 sock_net(cb->skb->sk), cb->extack, 390 false); 391 if (req_info.dev) { 392 ctx->match_ifindex = req_info.dev->ifindex; 393 ctx->ifindex = ctx->match_ifindex; 394 ethnl_parse_header_dev_put(&req_info); 395 req_info.dev = NULL; 396 } 397 398 return ret; 399 } 400 401 static int 402 rss_dump_one_ctx(struct sk_buff *skb, struct netlink_callback *cb, 403 struct net_device *dev, u32 rss_context) 404 { 405 const struct genl_info *info = genl_info_dump(cb); 406 struct rss_reply_data data = {}; 407 struct rss_req_info req = {}; 408 void *ehdr; 409 int ret; 410 411 req.rss_context = rss_context; 412 413 ehdr = ethnl_dump_put(skb, cb, ETHTOOL_MSG_RSS_GET_REPLY); 414 if (!ehdr) 415 return -EMSGSIZE; 416 417 ret = ethnl_fill_reply_header(skb, dev, ETHTOOL_A_RSS_HEADER); 418 if (ret < 0) 419 goto err_cancel; 420 421 ret = rss_prepare(&req, dev, &data, info); 422 if (ret) 423 goto err_cancel; 424 425 ret = rss_fill_reply(skb, &req.base, &data.base); 426 if (ret) 427 goto err_cleanup; 428 genlmsg_end(skb, ehdr); 429 430 rss_cleanup_data(&data.base); 431 return 0; 432 433 err_cleanup: 434 rss_cleanup_data(&data.base); 435 err_cancel: 436 genlmsg_cancel(skb, ehdr); 437 return ret; 438 } 439 440 static int 441 rss_dump_one_dev(struct sk_buff *skb, struct netlink_callback *cb, 442 struct net_device *dev) 443 { 444 struct rss_nl_dump_ctx *ctx = rss_dump_ctx(cb); 445 int ret; 446 447 if (!dev->ethtool_ops->get_rxfh) 448 return 0; 449 450 if (!ctx->ctx_idx) { 451 ret = rss_dump_one_ctx(skb, cb, dev, 0); 452 if (ret) 453 return ret; 454 ctx->ctx_idx++; 455 } 456 457 for (; xa_find(&dev->ethtool->rss_ctx, &ctx->ctx_idx, 458 ULONG_MAX, XA_PRESENT); ctx->ctx_idx++) { 459 ret = rss_dump_one_ctx(skb, cb, dev, ctx->ctx_idx); 460 if (ret) 461 return ret; 462 } 463 ctx->ctx_idx = ctx->start_ctx; 464 465 return 0; 466 } 467 468 int ethnl_rss_dumpit(struct sk_buff *skb, struct netlink_callback *cb) 469 { 470 struct rss_nl_dump_ctx *ctx = rss_dump_ctx(cb); 471 struct net *net = sock_net(skb->sk); 472 int ret = 0; 473 474 for_each_netdev_lock_ops_compat_scoped(net, dev, ctx->ifindex) { 475 if (ctx->match_ifindex && ctx->match_ifindex != ctx->ifindex) 476 break; 477 478 ret = rss_dump_one_dev(skb, cb, dev); 479 if (ret) 480 break; 481 } 482 483 return ret; 484 } 485 486 /* RSS_NTF */ 487 488 static void ethnl_rss_delete_notify(struct net_device *dev, u32 rss_context) 489 { 490 struct sk_buff *ntf; 491 size_t ntf_size; 492 void *hdr; 493 494 ntf_size = ethnl_reply_header_size() + 495 nla_total_size(sizeof(u32)); /* _RSS_CONTEXT */ 496 497 ntf = genlmsg_new(ntf_size, GFP_KERNEL); 498 if (!ntf) 499 goto out_warn; 500 501 hdr = ethnl_bcastmsg_put(ntf, ETHTOOL_MSG_RSS_DELETE_NTF); 502 if (!hdr) 503 goto out_free_ntf; 504 505 if (ethnl_fill_reply_header(ntf, dev, ETHTOOL_A_RSS_HEADER) || 506 nla_put_u32(ntf, ETHTOOL_A_RSS_CONTEXT, rss_context)) 507 goto out_free_ntf; 508 509 genlmsg_end(ntf, hdr); 510 if (ethnl_multicast(ntf, dev)) 511 goto out_warn; 512 513 return; 514 515 out_free_ntf: 516 nlmsg_free(ntf); 517 out_warn: 518 pr_warn_once("Failed to send a RSS delete notification"); 519 } 520 521 void ethtool_rss_notify(struct net_device *dev, u32 type, u32 rss_context) 522 { 523 struct rss_req_info req_info = { 524 .rss_context = rss_context, 525 }; 526 527 if (type == ETHTOOL_MSG_RSS_DELETE_NTF) 528 ethnl_rss_delete_notify(dev, rss_context); 529 else 530 ethnl_notify(dev, type, &req_info.base); 531 } 532 533 /* RSS_SET */ 534 535 #define RFH_MASK (RXH_L2DA | RXH_VLAN | RXH_IP_SRC | RXH_IP_DST | \ 536 RXH_L3_PROTO | RXH_L4_B_0_1 | RXH_L4_B_2_3 | \ 537 RXH_GTP_TEID | RXH_DISCARD) 538 #define RFH_MASKv6 (RFH_MASK | RXH_IP6_FL) 539 540 static const struct nla_policy ethnl_rss_flows_policy[] = { 541 [ETHTOOL_A_FLOW_ETHER] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), 542 [ETHTOOL_A_FLOW_IP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), 543 [ETHTOOL_A_FLOW_IP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), 544 [ETHTOOL_A_FLOW_TCP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), 545 [ETHTOOL_A_FLOW_UDP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), 546 [ETHTOOL_A_FLOW_SCTP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), 547 [ETHTOOL_A_FLOW_AH_ESP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), 548 [ETHTOOL_A_FLOW_TCP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), 549 [ETHTOOL_A_FLOW_UDP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), 550 [ETHTOOL_A_FLOW_SCTP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), 551 [ETHTOOL_A_FLOW_AH_ESP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), 552 [ETHTOOL_A_FLOW_AH4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), 553 [ETHTOOL_A_FLOW_ESP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), 554 [ETHTOOL_A_FLOW_AH6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), 555 [ETHTOOL_A_FLOW_ESP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), 556 [ETHTOOL_A_FLOW_GTPU4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), 557 [ETHTOOL_A_FLOW_GTPU6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), 558 [ETHTOOL_A_FLOW_GTPC4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), 559 [ETHTOOL_A_FLOW_GTPC6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), 560 [ETHTOOL_A_FLOW_GTPC_TEID4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), 561 [ETHTOOL_A_FLOW_GTPC_TEID6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), 562 [ETHTOOL_A_FLOW_GTPU_EH4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), 563 [ETHTOOL_A_FLOW_GTPU_EH6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), 564 [ETHTOOL_A_FLOW_GTPU_UL4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), 565 [ETHTOOL_A_FLOW_GTPU_UL6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), 566 [ETHTOOL_A_FLOW_GTPU_DL4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), 567 [ETHTOOL_A_FLOW_GTPU_DL6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), 568 }; 569 570 const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_FLOW_HASH + 1] = { 571 [ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy), 572 [ETHTOOL_A_RSS_CONTEXT] = { .type = NLA_U32, }, 573 [ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_MIN(NLA_U32, 1), 574 [ETHTOOL_A_RSS_INDIR] = { .type = NLA_BINARY, }, 575 [ETHTOOL_A_RSS_HKEY] = NLA_POLICY_MIN(NLA_BINARY, 1), 576 [ETHTOOL_A_RSS_INPUT_XFRM] = 577 NLA_POLICY_MAX(NLA_U32, RXH_XFRM_SYM_OR_XOR), 578 [ETHTOOL_A_RSS_FLOW_HASH] = NLA_POLICY_NESTED(ethnl_rss_flows_policy), 579 }; 580 581 static int 582 ethnl_rss_set_validate(struct ethnl_req_info *req_info, struct genl_info *info) 583 { 584 const struct ethtool_ops *ops = req_info->dev->ethtool_ops; 585 struct rss_req_info *request = RSS_REQINFO(req_info); 586 struct nlattr **tb = info->attrs; 587 struct nlattr *bad_attr = NULL; 588 u32 input_xfrm; 589 590 if (request->rss_context && !ops->create_rxfh_context) 591 bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_CONTEXT]; 592 593 if (request->rss_context && !ops->rxfh_per_ctx_key) { 594 bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_HFUNC]; 595 bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_HKEY]; 596 bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_INPUT_XFRM]; 597 } 598 599 input_xfrm = nla_get_u32_default(tb[ETHTOOL_A_RSS_INPUT_XFRM], 0); 600 if (input_xfrm & ~ops->supported_input_xfrm) 601 bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_INPUT_XFRM]; 602 603 if (tb[ETHTOOL_A_RSS_FLOW_HASH] && !ops->set_rxfh_fields) 604 bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_FLOW_HASH]; 605 if (request->rss_context && 606 tb[ETHTOOL_A_RSS_FLOW_HASH] && !ops->rxfh_per_ctx_fields) 607 bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_FLOW_HASH]; 608 609 if (bad_attr) { 610 NL_SET_BAD_ATTR(info->extack, bad_attr); 611 return -EOPNOTSUPP; 612 } 613 614 return 1; 615 } 616 617 static int 618 rss_set_prep_indir(struct net_device *dev, struct genl_info *info, 619 struct rss_reply_data *data, struct ethtool_rxfh_param *rxfh, 620 bool *reset, bool *mod) 621 { 622 struct netlink_ext_ack *extack = info->extack; 623 struct nlattr **tb = info->attrs; 624 size_t alloc_size; 625 int num_rx_rings; 626 u32 user_size; 627 int i, err; 628 629 if (!tb[ETHTOOL_A_RSS_INDIR]) 630 return 0; 631 if (!data->indir_size) 632 return -EOPNOTSUPP; 633 634 err = ethtool_get_rx_ring_count(dev); 635 if (err < 0) 636 return err; 637 num_rx_rings = err; 638 639 if (nla_len(tb[ETHTOOL_A_RSS_INDIR]) % 4) { 640 NL_SET_BAD_ATTR(info->extack, tb[ETHTOOL_A_RSS_INDIR]); 641 return -EINVAL; 642 } 643 user_size = nla_len(tb[ETHTOOL_A_RSS_INDIR]) / 4; 644 if (!user_size) { 645 if (rxfh->rss_context) { 646 NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_RSS_INDIR], 647 "can't reset table for a context"); 648 return -EINVAL; 649 } 650 *reset = true; 651 } else if (data->indir_size % user_size) { 652 NL_SET_ERR_MSG_ATTR_FMT(extack, tb[ETHTOOL_A_RSS_INDIR], 653 "size (%d) mismatch with device indir table (%d)", 654 user_size, data->indir_size); 655 return -EINVAL; 656 } 657 658 rxfh->indir_size = data->indir_size; 659 alloc_size = array_size(data->indir_size, sizeof(rxfh->indir[0])); 660 rxfh->indir = kzalloc(alloc_size, GFP_KERNEL); 661 if (!rxfh->indir) 662 return -ENOMEM; 663 664 nla_memcpy(rxfh->indir, tb[ETHTOOL_A_RSS_INDIR], alloc_size); 665 for (i = 0; i < user_size; i++) { 666 if (rxfh->indir[i] < num_rx_rings) 667 continue; 668 669 NL_SET_ERR_MSG_ATTR_FMT(extack, tb[ETHTOOL_A_RSS_INDIR], 670 "entry %d: queue out of range (%d)", 671 i, rxfh->indir[i]); 672 err = -EINVAL; 673 goto err_free; 674 } 675 676 if (user_size) { 677 /* Replicate the user-provided table to fill the device table */ 678 for (i = user_size; i < data->indir_size; i++) 679 rxfh->indir[i] = rxfh->indir[i % user_size]; 680 } else { 681 for (i = 0; i < data->indir_size; i++) 682 rxfh->indir[i] = 683 ethtool_rxfh_indir_default(i, num_rx_rings); 684 } 685 686 *mod |= memcmp(rxfh->indir, data->indir_table, alloc_size); 687 688 return user_size; 689 690 err_free: 691 kfree(rxfh->indir); 692 rxfh->indir = NULL; 693 return err; 694 } 695 696 static int 697 rss_set_prep_hkey(struct net_device *dev, struct genl_info *info, 698 struct rss_reply_data *data, struct ethtool_rxfh_param *rxfh, 699 bool *mod) 700 { 701 struct nlattr **tb = info->attrs; 702 703 if (!tb[ETHTOOL_A_RSS_HKEY]) 704 return 0; 705 706 if (nla_len(tb[ETHTOOL_A_RSS_HKEY]) != data->hkey_size) { 707 NL_SET_BAD_ATTR(info->extack, tb[ETHTOOL_A_RSS_HKEY]); 708 return -EINVAL; 709 } 710 711 rxfh->key_size = data->hkey_size; 712 rxfh->key = kmemdup(data->hkey, data->hkey_size, GFP_KERNEL); 713 if (!rxfh->key) 714 return -ENOMEM; 715 716 ethnl_update_binary(rxfh->key, rxfh->key_size, tb[ETHTOOL_A_RSS_HKEY], 717 mod); 718 return 0; 719 } 720 721 static int 722 rss_check_rxfh_fields_sym(struct net_device *dev, struct genl_info *info, 723 struct rss_reply_data *data, bool xfrm_sym) 724 { 725 struct nlattr **tb = info->attrs; 726 int i; 727 728 if (!xfrm_sym) 729 return 0; 730 if (!data->has_flow_hash) { 731 NL_SET_ERR_MSG_ATTR(info->extack, tb[ETHTOOL_A_RSS_INPUT_XFRM], 732 "hash field config not reported"); 733 return -EINVAL; 734 } 735 736 for (i = 1; i < __ETHTOOL_A_FLOW_CNT; i++) 737 if (data->flow_hash[i] >= 0 && 738 !ethtool_rxfh_config_is_sym(data->flow_hash[i])) { 739 NL_SET_ERR_MSG_ATTR(info->extack, 740 tb[ETHTOOL_A_RSS_INPUT_XFRM], 741 "hash field config is not symmetric"); 742 return -EINVAL; 743 } 744 745 return 0; 746 } 747 748 static int 749 ethnl_set_rss_fields(struct net_device *dev, struct genl_info *info, 750 u32 rss_context, struct rss_reply_data *data, 751 bool xfrm_sym, bool *mod) 752 { 753 struct nlattr *flow_nest = info->attrs[ETHTOOL_A_RSS_FLOW_HASH]; 754 struct nlattr *flows[ETHTOOL_A_FLOW_MAX + 1]; 755 const struct ethtool_ops *ops; 756 int i, ret; 757 758 ops = dev->ethtool_ops; 759 760 ret = rss_check_rxfh_fields_sym(dev, info, data, xfrm_sym); 761 if (ret) 762 return ret; 763 764 if (!flow_nest) 765 return 0; 766 767 ret = nla_parse_nested(flows, ARRAY_SIZE(ethnl_rss_flows_policy) - 1, 768 flow_nest, ethnl_rss_flows_policy, info->extack); 769 if (ret < 0) 770 return ret; 771 772 for (i = 1; i < __ETHTOOL_A_FLOW_CNT; i++) { 773 struct ethtool_rxfh_fields fields = { 774 .flow_type = ethtool_rxfh_ft_nl2ioctl[i], 775 .rss_context = rss_context, 776 }; 777 778 if (!flows[i]) 779 continue; 780 781 fields.data = nla_get_u32(flows[i]); 782 if (data->has_flow_hash && data->flow_hash[i] == fields.data) 783 continue; 784 785 if (xfrm_sym && !ethtool_rxfh_config_is_sym(fields.data)) { 786 NL_SET_ERR_MSG_ATTR(info->extack, flows[i], 787 "conflict with xfrm-input"); 788 return -EINVAL; 789 } 790 791 ret = ops->set_rxfh_fields(dev, &fields, info->extack); 792 if (ret) 793 return ret; 794 795 *mod = true; 796 } 797 798 return 0; 799 } 800 801 static void 802 rss_set_ctx_update(struct ethtool_rxfh_context *ctx, struct nlattr **tb, 803 struct rss_reply_data *data, struct ethtool_rxfh_param *rxfh) 804 { 805 int i; 806 807 if (rxfh->indir) { 808 for (i = 0; i < data->indir_size; i++) 809 ethtool_rxfh_context_indir(ctx)[i] = rxfh->indir[i]; 810 ctx->indir_configured = !!nla_len(tb[ETHTOOL_A_RSS_INDIR]); 811 } 812 if (rxfh->key) { 813 memcpy(ethtool_rxfh_context_key(ctx), rxfh->key, 814 data->hkey_size); 815 ctx->key_configured = !!rxfh->key_size; 816 } 817 if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE) 818 ctx->hfunc = rxfh->hfunc; 819 if (rxfh->input_xfrm != RXH_XFRM_NO_CHANGE) 820 ctx->input_xfrm = rxfh->input_xfrm; 821 } 822 823 static int 824 ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info) 825 { 826 struct rss_req_info *request = RSS_REQINFO(req_info); 827 bool indir_reset = false, indir_mod, xfrm_sym; 828 struct ethtool_rxfh_context *ctx = NULL; 829 struct net_device *dev = req_info->dev; 830 bool mod = false, fields_mod = false; 831 struct ethtool_rxfh_param rxfh = {}; 832 struct nlattr **tb = info->attrs; 833 struct rss_reply_data data = {}; 834 const struct ethtool_ops *ops; 835 u32 indir_user_size; 836 int ret; 837 838 ops = dev->ethtool_ops; 839 data.base.dev = dev; 840 841 ret = rss_prepare(request, dev, &data, info); 842 if (ret) 843 return ret; 844 845 rxfh.rss_context = request->rss_context; 846 847 ret = rss_set_prep_indir(dev, info, &data, &rxfh, &indir_reset, &mod); 848 if (ret < 0) 849 goto exit_clean_data; 850 indir_user_size = ret; 851 indir_mod = !!tb[ETHTOOL_A_RSS_INDIR]; 852 853 rxfh.hfunc = data.hfunc; 854 ethnl_update_u8(&rxfh.hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod); 855 if (rxfh.hfunc == data.hfunc) 856 rxfh.hfunc = ETH_RSS_HASH_NO_CHANGE; 857 858 ret = rss_set_prep_hkey(dev, info, &data, &rxfh, &mod); 859 if (ret) 860 goto exit_free_indir; 861 862 rxfh.input_xfrm = data.input_xfrm; 863 ethnl_update_u8(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM], &mod); 864 xfrm_sym = rxfh.input_xfrm || data.input_xfrm; 865 if (rxfh.input_xfrm == data.input_xfrm) 866 rxfh.input_xfrm = RXH_XFRM_NO_CHANGE; 867 868 mutex_lock(&dev->ethtool->rss_lock); 869 if (request->rss_context) { 870 ctx = xa_load(&dev->ethtool->rss_ctx, request->rss_context); 871 if (!ctx) { 872 ret = -ENOENT; 873 goto exit_unlock; 874 } 875 } 876 877 ret = ethnl_set_rss_fields(dev, info, request->rss_context, 878 &data, xfrm_sym, &fields_mod); 879 if (ret) 880 goto exit_unlock; 881 882 if (!mod) 883 ret = 0; /* nothing to tell the driver */ 884 else if (!ops->set_rxfh) 885 ret = -EOPNOTSUPP; 886 else if (!rxfh.rss_context) 887 ret = ops->set_rxfh(dev, &rxfh, info->extack); 888 else 889 ret = ops->modify_rxfh_context(dev, ctx, &rxfh, info->extack); 890 if (ret) 891 goto exit_unlock; 892 893 if (ctx) { 894 rss_set_ctx_update(ctx, tb, &data, &rxfh); 895 if (indir_user_size) 896 ctx->indir_user_size = indir_user_size; 897 } else if (indir_reset) { 898 dev->ethtool->rss_indir_user_size = 0; 899 } else if (indir_mod) { 900 dev->ethtool->rss_indir_user_size = indir_user_size; 901 } 902 903 exit_unlock: 904 mutex_unlock(&dev->ethtool->rss_lock); 905 kfree(rxfh.key); 906 exit_free_indir: 907 kfree(rxfh.indir); 908 exit_clean_data: 909 rss_cleanup_data(&data.base); 910 911 return ret ?: mod || fields_mod; 912 } 913 914 const struct ethnl_request_ops ethnl_rss_request_ops = { 915 .request_cmd = ETHTOOL_MSG_RSS_GET, 916 .reply_cmd = ETHTOOL_MSG_RSS_GET_REPLY, 917 .hdr_attr = ETHTOOL_A_RSS_HEADER, 918 .req_info_size = sizeof(struct rss_req_info), 919 .reply_data_size = sizeof(struct rss_reply_data), 920 921 .parse_request = rss_parse_request, 922 .prepare_data = rss_prepare_data, 923 .reply_size = rss_reply_size, 924 .fill_reply = rss_fill_reply, 925 .cleanup_data = rss_cleanup_data, 926 927 .set_validate = ethnl_rss_set_validate, 928 .set = ethnl_rss_set, 929 .set_ntf_cmd = ETHTOOL_MSG_RSS_NTF, 930 }; 931 932 /* RSS_CREATE */ 933 934 const struct nla_policy ethnl_rss_create_policy[ETHTOOL_A_RSS_INPUT_XFRM + 1] = { 935 [ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy), 936 [ETHTOOL_A_RSS_CONTEXT] = NLA_POLICY_MIN(NLA_U32, 1), 937 [ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_MIN(NLA_U32, 1), 938 [ETHTOOL_A_RSS_INDIR] = NLA_POLICY_MIN(NLA_BINARY, 1), 939 [ETHTOOL_A_RSS_HKEY] = NLA_POLICY_MIN(NLA_BINARY, 1), 940 [ETHTOOL_A_RSS_INPUT_XFRM] = 941 NLA_POLICY_MAX(NLA_U32, RXH_XFRM_SYM_OR_XOR), 942 }; 943 944 static int 945 ethnl_rss_create_validate(struct net_device *dev, struct genl_info *info) 946 { 947 const struct ethtool_ops *ops = dev->ethtool_ops; 948 struct nlattr **tb = info->attrs; 949 struct nlattr *bad_attr = NULL; 950 u32 rss_context, input_xfrm; 951 952 if (!ops->create_rxfh_context) 953 return -EOPNOTSUPP; 954 955 rss_context = nla_get_u32_default(tb[ETHTOOL_A_RSS_CONTEXT], 0); 956 if (ops->rxfh_max_num_contexts && 957 ops->rxfh_max_num_contexts <= rss_context) { 958 NL_SET_BAD_ATTR(info->extack, tb[ETHTOOL_A_RSS_CONTEXT]); 959 return -ERANGE; 960 } 961 962 if (!ops->rxfh_per_ctx_key) { 963 bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_HFUNC]; 964 bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_HKEY]; 965 bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_INPUT_XFRM]; 966 } 967 968 input_xfrm = nla_get_u32_default(tb[ETHTOOL_A_RSS_INPUT_XFRM], 0); 969 if (input_xfrm & ~ops->supported_input_xfrm) 970 bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_INPUT_XFRM]; 971 972 if (bad_attr) { 973 NL_SET_BAD_ATTR(info->extack, bad_attr); 974 return -EOPNOTSUPP; 975 } 976 977 return 0; 978 } 979 980 static void 981 ethnl_rss_create_send_ntf(const struct sk_buff *rsp, struct net_device *dev) 982 { 983 struct genlmsghdr *genl_hdr; 984 struct nlmsghdr *nlh; 985 struct sk_buff *ntf; 986 987 ntf = skb_copy_expand(rsp, 0, 0, GFP_KERNEL); 988 if (!ntf) 989 return; 990 991 nlh = nlmsg_hdr(ntf); 992 /* Convert the reply into a notification */ 993 nlh->nlmsg_pid = 0; 994 995 genl_hdr = nlmsg_data(nlh); 996 genl_hdr->cmd = ETHTOOL_MSG_RSS_CREATE_NTF; 997 998 ethnl_multicast(ntf, dev); 999 } 1000 1001 int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info) 1002 { 1003 bool indir_dflt = false, mod = false, ntf_fail = false; 1004 struct ethtool_rxfh_param rxfh = {}; 1005 struct ethtool_rxfh_context *ctx; 1006 struct nlattr **tb = info->attrs; 1007 struct rss_reply_data data = {}; 1008 const struct ethtool_ops *ops; 1009 struct rss_req_info req = {}; 1010 struct net_device *dev; 1011 u32 indir_user_size; 1012 struct sk_buff *rsp; 1013 void *hdr; 1014 u32 limit; 1015 int ret; 1016 1017 rsp = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 1018 if (!rsp) 1019 return -ENOMEM; 1020 1021 ret = ethnl_parse_header_dev_get(&req.base, tb[ETHTOOL_A_RSS_HEADER], 1022 genl_info_net(info), info->extack, 1023 true); 1024 if (ret < 0) 1025 goto exit_free_rsp; 1026 1027 dev = req.base.dev; 1028 ops = dev->ethtool_ops; 1029 1030 req.rss_context = nla_get_u32_default(tb[ETHTOOL_A_RSS_CONTEXT], 0); 1031 1032 ret = ethnl_rss_create_validate(dev, info); 1033 if (ret) 1034 goto exit_free_dev; 1035 1036 netdev_lock_ops_compat(dev); 1037 1038 ret = ethnl_ops_begin(dev); 1039 if (ret < 0) 1040 goto exit_dev_unlock; 1041 1042 ret = rss_get_data_alloc(dev, &data); 1043 if (ret) 1044 goto exit_ops; 1045 1046 ret = rss_set_prep_indir(dev, info, &data, &rxfh, &indir_dflt, &mod); 1047 if (ret < 0) 1048 goto exit_clean_data; 1049 indir_user_size = ret; 1050 1051 ethnl_update_u8(&rxfh.hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod); 1052 1053 ret = rss_set_prep_hkey(dev, info, &data, &rxfh, &mod); 1054 if (ret) 1055 goto exit_free_indir; 1056 1057 rxfh.input_xfrm = RXH_XFRM_NO_CHANGE; 1058 ethnl_update_u8(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM], &mod); 1059 1060 ctx = ethtool_rxfh_ctx_alloc(ops, data.indir_size, data.hkey_size); 1061 if (!ctx) { 1062 ret = -ENOMEM; 1063 goto exit_free_hkey; 1064 } 1065 1066 mutex_lock(&dev->ethtool->rss_lock); 1067 if (!req.rss_context) { 1068 limit = ops->rxfh_max_num_contexts ?: U32_MAX; 1069 ret = xa_alloc(&dev->ethtool->rss_ctx, &req.rss_context, ctx, 1070 XA_LIMIT(1, limit - 1), GFP_KERNEL_ACCOUNT); 1071 } else { 1072 ret = xa_insert(&dev->ethtool->rss_ctx, 1073 req.rss_context, ctx, GFP_KERNEL_ACCOUNT); 1074 } 1075 if (ret < 0) { 1076 NL_SET_ERR_MSG_ATTR(info->extack, tb[ETHTOOL_A_RSS_CONTEXT], 1077 "error allocating context ID"); 1078 goto err_unlock_free_ctx; 1079 } 1080 rxfh.rss_context = req.rss_context; 1081 1082 ret = ops->create_rxfh_context(dev, ctx, &rxfh, info->extack); 1083 if (ret) 1084 goto err_ctx_id_free; 1085 1086 /* Make sure driver populates defaults */ 1087 WARN_ON_ONCE(!rxfh.key && ops->rxfh_per_ctx_key && 1088 !memchr_inv(ethtool_rxfh_context_key(ctx), 0, 1089 ctx->key_size)); 1090 1091 /* Store the config from rxfh to Xarray.. */ 1092 rss_set_ctx_update(ctx, tb, &data, &rxfh); 1093 ctx->indir_user_size = indir_user_size; 1094 /* .. copy from Xarray to data. */ 1095 __rss_prepare_ctx(dev, &data, ctx); 1096 1097 hdr = ethnl_unicast_put(rsp, info->snd_portid, info->snd_seq, 1098 ETHTOOL_MSG_RSS_CREATE_ACT_REPLY); 1099 ntf_fail = ethnl_fill_reply_header(rsp, dev, ETHTOOL_A_RSS_HEADER); 1100 ntf_fail |= rss_fill_reply(rsp, &req.base, &data.base); 1101 if (WARN_ON(!hdr || ntf_fail)) { 1102 ret = -EMSGSIZE; 1103 goto err_remove_ctx; 1104 } 1105 1106 genlmsg_end(rsp, hdr); 1107 1108 ethnl_rss_create_send_ntf(rsp, dev); 1109 ret = genlmsg_reply(rsp, info); 1110 rsp = NULL; 1111 1112 exit_unlock: 1113 mutex_unlock(&dev->ethtool->rss_lock); 1114 exit_free_hkey: 1115 kfree(rxfh.key); 1116 exit_free_indir: 1117 kfree(rxfh.indir); 1118 exit_clean_data: 1119 rss_get_data_free(&data); 1120 exit_ops: 1121 ethnl_ops_complete(dev); 1122 exit_dev_unlock: 1123 netdev_unlock_ops_compat(dev); 1124 exit_free_dev: 1125 ethnl_parse_header_dev_put(&req.base); 1126 exit_free_rsp: 1127 nlmsg_free(rsp); 1128 return ret; 1129 1130 err_remove_ctx: 1131 if (ops->remove_rxfh_context(dev, ctx, req.rss_context, NULL)) 1132 /* leave the context on failure, like ethnl_rss_delete_doit() */ 1133 goto exit_unlock; 1134 err_ctx_id_free: 1135 xa_erase(&dev->ethtool->rss_ctx, req.rss_context); 1136 err_unlock_free_ctx: 1137 kfree(ctx); 1138 goto exit_unlock; 1139 } 1140 1141 /* RSS_DELETE */ 1142 1143 const struct nla_policy ethnl_rss_delete_policy[ETHTOOL_A_RSS_CONTEXT + 1] = { 1144 [ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy), 1145 [ETHTOOL_A_RSS_CONTEXT] = NLA_POLICY_MIN(NLA_U32, 1), 1146 }; 1147 1148 int ethnl_rss_delete_doit(struct sk_buff *skb, struct genl_info *info) 1149 { 1150 struct ethtool_rxfh_context *ctx; 1151 struct nlattr **tb = info->attrs; 1152 struct ethnl_req_info req = {}; 1153 const struct ethtool_ops *ops; 1154 struct net_device *dev; 1155 u32 rss_context; 1156 int ret; 1157 1158 if (GENL_REQ_ATTR_CHECK(info, ETHTOOL_A_RSS_CONTEXT)) 1159 return -EINVAL; 1160 rss_context = nla_get_u32(tb[ETHTOOL_A_RSS_CONTEXT]); 1161 1162 ret = ethnl_parse_header_dev_get(&req, tb[ETHTOOL_A_RSS_HEADER], 1163 genl_info_net(info), info->extack, 1164 true); 1165 if (ret < 0) 1166 return ret; 1167 1168 dev = req.dev; 1169 ops = dev->ethtool_ops; 1170 1171 if (!ops->create_rxfh_context) { 1172 ret = -EOPNOTSUPP; 1173 goto exit_free_dev; 1174 } 1175 1176 netdev_lock_ops_compat(dev); 1177 1178 ret = ethnl_ops_begin(dev); 1179 if (ret < 0) 1180 goto exit_dev_unlock; 1181 1182 mutex_lock(&dev->ethtool->rss_lock); 1183 ret = ethtool_check_rss_ctx_busy(dev, rss_context); 1184 if (ret) 1185 goto exit_unlock; 1186 1187 ctx = xa_load(&dev->ethtool->rss_ctx, rss_context); 1188 if (!ctx) { 1189 ret = -ENOENT; 1190 goto exit_unlock; 1191 } 1192 1193 ret = ops->remove_rxfh_context(dev, ctx, rss_context, info->extack); 1194 if (ret) 1195 goto exit_unlock; 1196 1197 WARN_ON(xa_erase(&dev->ethtool->rss_ctx, rss_context) != ctx); 1198 kfree(ctx); 1199 1200 ethnl_rss_delete_notify(dev, rss_context); 1201 1202 exit_unlock: 1203 mutex_unlock(&dev->ethtool->rss_lock); 1204 ethnl_ops_complete(dev); 1205 exit_dev_unlock: 1206 netdev_unlock_ops_compat(dev); 1207 exit_free_dev: 1208 ethnl_parse_header_dev_put(&req); 1209 return ret; 1210 } 1211