1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <net/netdev_lock.h> 4 5 #include "netlink.h" 6 #include "common.h" 7 8 struct rss_req_info { 9 struct ethnl_req_info base; 10 u32 rss_context; 11 }; 12 13 struct rss_reply_data { 14 struct ethnl_reply_data base; 15 bool has_flow_hash; 16 bool no_key_fields; 17 u32 indir_size; 18 u32 hkey_size; 19 u32 hfunc; 20 u32 input_xfrm; 21 u32 *indir_table; 22 u8 *hkey; 23 int flow_hash[__ETHTOOL_A_FLOW_CNT]; 24 }; 25 26 static const u8 ethtool_rxfh_ft_nl2ioctl[] = { 27 [ETHTOOL_A_FLOW_ETHER] = ETHER_FLOW, 28 [ETHTOOL_A_FLOW_IP4] = IPV4_FLOW, 29 [ETHTOOL_A_FLOW_IP6] = IPV6_FLOW, 30 [ETHTOOL_A_FLOW_TCP4] = TCP_V4_FLOW, 31 [ETHTOOL_A_FLOW_UDP4] = UDP_V4_FLOW, 32 [ETHTOOL_A_FLOW_SCTP4] = SCTP_V4_FLOW, 33 [ETHTOOL_A_FLOW_AH_ESP4] = AH_ESP_V4_FLOW, 34 [ETHTOOL_A_FLOW_TCP6] = TCP_V6_FLOW, 35 [ETHTOOL_A_FLOW_UDP6] = UDP_V6_FLOW, 36 [ETHTOOL_A_FLOW_SCTP6] = SCTP_V6_FLOW, 37 [ETHTOOL_A_FLOW_AH_ESP6] = AH_ESP_V6_FLOW, 38 [ETHTOOL_A_FLOW_AH4] = AH_V4_FLOW, 39 [ETHTOOL_A_FLOW_ESP4] = ESP_V4_FLOW, 40 [ETHTOOL_A_FLOW_AH6] = AH_V6_FLOW, 41 [ETHTOOL_A_FLOW_ESP6] = ESP_V6_FLOW, 42 [ETHTOOL_A_FLOW_GTPU4] = GTPU_V4_FLOW, 43 [ETHTOOL_A_FLOW_GTPU6] = GTPU_V6_FLOW, 44 [ETHTOOL_A_FLOW_GTPC4] = GTPC_V4_FLOW, 45 [ETHTOOL_A_FLOW_GTPC6] = GTPC_V6_FLOW, 46 [ETHTOOL_A_FLOW_GTPC_TEID4] = GTPC_TEID_V4_FLOW, 47 [ETHTOOL_A_FLOW_GTPC_TEID6] = GTPC_TEID_V6_FLOW, 48 [ETHTOOL_A_FLOW_GTPU_EH4] = GTPU_EH_V4_FLOW, 49 [ETHTOOL_A_FLOW_GTPU_EH6] = GTPU_EH_V6_FLOW, 50 [ETHTOOL_A_FLOW_GTPU_UL4] = GTPU_UL_V4_FLOW, 51 [ETHTOOL_A_FLOW_GTPU_UL6] = GTPU_UL_V6_FLOW, 52 [ETHTOOL_A_FLOW_GTPU_DL4] = GTPU_DL_V4_FLOW, 53 [ETHTOOL_A_FLOW_GTPU_DL6] = GTPU_DL_V6_FLOW, 54 }; 55 56 #define RSS_REQINFO(__req_base) \ 57 container_of(__req_base, struct rss_req_info, base) 58 59 #define RSS_REPDATA(__reply_base) \ 60 container_of(__reply_base, struct rss_reply_data, base) 61 62 const struct nla_policy ethnl_rss_get_policy[] = { 63 [ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy), 64 [ETHTOOL_A_RSS_CONTEXT] = { .type = NLA_U32 }, 65 [ETHTOOL_A_RSS_START_CONTEXT] = { .type = NLA_U32 }, 66 }; 67 68 static int 69 rss_parse_request(struct ethnl_req_info *req_info, struct nlattr **tb, 70 struct netlink_ext_ack *extack) 71 { 72 struct rss_req_info *request = RSS_REQINFO(req_info); 73 74 if (tb[ETHTOOL_A_RSS_CONTEXT]) 75 request->rss_context = nla_get_u32(tb[ETHTOOL_A_RSS_CONTEXT]); 76 if (tb[ETHTOOL_A_RSS_START_CONTEXT]) { 77 NL_SET_BAD_ATTR(extack, tb[ETHTOOL_A_RSS_START_CONTEXT]); 78 return -EINVAL; 79 } 80 81 return 0; 82 } 83 84 static void 85 rss_prepare_flow_hash(const struct rss_req_info *req, struct net_device *dev, 86 struct rss_reply_data *data, const struct genl_info *info) 87 { 88 int i; 89 90 data->has_flow_hash = false; 91 92 if (!dev->ethtool_ops->get_rxfh_fields) 93 return; 94 if (req->rss_context && !dev->ethtool_ops->rxfh_per_ctx_fields) 95 return; 96 97 mutex_lock(&dev->ethtool->rss_lock); 98 for (i = 1; i < __ETHTOOL_A_FLOW_CNT; i++) { 99 struct ethtool_rxfh_fields fields = { 100 .flow_type = ethtool_rxfh_ft_nl2ioctl[i], 101 .rss_context = req->rss_context, 102 }; 103 104 if (dev->ethtool_ops->get_rxfh_fields(dev, &fields)) { 105 data->flow_hash[i] = -1; /* Unsupported */ 106 continue; 107 } 108 109 data->flow_hash[i] = fields.data; 110 data->has_flow_hash = true; 111 } 112 mutex_unlock(&dev->ethtool->rss_lock); 113 } 114 115 static int 116 rss_prepare_get(const struct rss_req_info *request, struct net_device *dev, 117 struct rss_reply_data *data, const struct genl_info *info) 118 { 119 struct ethtool_rxfh_param rxfh = {}; 120 const struct ethtool_ops *ops; 121 u32 total_size, indir_bytes; 122 u8 *rss_config; 123 int ret; 124 125 ops = dev->ethtool_ops; 126 127 ret = ethnl_ops_begin(dev); 128 if (ret < 0) 129 return ret; 130 mutex_lock(&dev->ethtool->rss_lock); 131 132 data->indir_size = 0; 133 data->hkey_size = 0; 134 if (ops->get_rxfh_indir_size) 135 data->indir_size = ops->get_rxfh_indir_size(dev); 136 if (ops->get_rxfh_key_size) 137 data->hkey_size = ops->get_rxfh_key_size(dev); 138 139 indir_bytes = data->indir_size * sizeof(u32); 140 total_size = indir_bytes + data->hkey_size; 141 rss_config = kzalloc(total_size, GFP_KERNEL); 142 if (!rss_config) { 143 ret = -ENOMEM; 144 goto out_unlock; 145 } 146 147 if (data->indir_size) 148 data->indir_table = (u32 *)rss_config; 149 if (data->hkey_size) 150 data->hkey = rss_config + indir_bytes; 151 152 rxfh.indir_size = data->indir_size; 153 rxfh.indir = data->indir_table; 154 rxfh.key_size = data->hkey_size; 155 rxfh.key = data->hkey; 156 157 ret = ops->get_rxfh(dev, &rxfh); 158 if (ret) 159 goto out_unlock; 160 161 data->hfunc = rxfh.hfunc; 162 data->input_xfrm = rxfh.input_xfrm; 163 out_unlock: 164 mutex_unlock(&dev->ethtool->rss_lock); 165 ethnl_ops_complete(dev); 166 return ret; 167 } 168 169 static int 170 rss_prepare_ctx(const struct rss_req_info *request, struct net_device *dev, 171 struct rss_reply_data *data, const struct genl_info *info) 172 { 173 struct ethtool_rxfh_context *ctx; 174 u32 total_size, indir_bytes; 175 u8 *rss_config; 176 int ret; 177 178 data->no_key_fields = !dev->ethtool_ops->rxfh_per_ctx_key; 179 180 mutex_lock(&dev->ethtool->rss_lock); 181 ctx = xa_load(&dev->ethtool->rss_ctx, request->rss_context); 182 if (!ctx) { 183 ret = -ENOENT; 184 goto out_unlock; 185 } 186 187 data->indir_size = ctx->indir_size; 188 data->hkey_size = ctx->key_size; 189 data->hfunc = ctx->hfunc; 190 data->input_xfrm = ctx->input_xfrm; 191 192 indir_bytes = data->indir_size * sizeof(u32); 193 total_size = indir_bytes + data->hkey_size; 194 rss_config = kzalloc(total_size, GFP_KERNEL); 195 if (!rss_config) { 196 ret = -ENOMEM; 197 goto out_unlock; 198 } 199 200 data->indir_table = (u32 *)rss_config; 201 memcpy(data->indir_table, ethtool_rxfh_context_indir(ctx), indir_bytes); 202 203 if (data->hkey_size) { 204 data->hkey = rss_config + indir_bytes; 205 memcpy(data->hkey, ethtool_rxfh_context_key(ctx), 206 data->hkey_size); 207 } 208 209 ret = 0; 210 out_unlock: 211 mutex_unlock(&dev->ethtool->rss_lock); 212 return ret; 213 } 214 215 static int 216 rss_prepare(const struct rss_req_info *request, struct net_device *dev, 217 struct rss_reply_data *data, const struct genl_info *info) 218 { 219 rss_prepare_flow_hash(request, dev, data, info); 220 221 /* Coming from RSS_SET, driver may only have flow_hash_fields ops */ 222 if (!dev->ethtool_ops->get_rxfh) 223 return 0; 224 225 if (request->rss_context) 226 return rss_prepare_ctx(request, dev, data, info); 227 return rss_prepare_get(request, dev, data, info); 228 } 229 230 static int 231 rss_prepare_data(const struct ethnl_req_info *req_base, 232 struct ethnl_reply_data *reply_base, 233 const struct genl_info *info) 234 { 235 struct rss_reply_data *data = RSS_REPDATA(reply_base); 236 struct rss_req_info *request = RSS_REQINFO(req_base); 237 struct net_device *dev = reply_base->dev; 238 const struct ethtool_ops *ops; 239 240 ops = dev->ethtool_ops; 241 if (!ops->get_rxfh) 242 return -EOPNOTSUPP; 243 244 /* Some drivers don't handle rss_context */ 245 if (request->rss_context && !ops->create_rxfh_context) 246 return -EOPNOTSUPP; 247 248 return rss_prepare(request, dev, data, info); 249 } 250 251 static int 252 rss_reply_size(const struct ethnl_req_info *req_base, 253 const struct ethnl_reply_data *reply_base) 254 { 255 const struct rss_reply_data *data = RSS_REPDATA(reply_base); 256 int len; 257 258 len = nla_total_size(sizeof(u32)) + /* _RSS_CONTEXT */ 259 nla_total_size(sizeof(u32)) + /* _RSS_HFUNC */ 260 nla_total_size(sizeof(u32)) + /* _RSS_INPUT_XFRM */ 261 nla_total_size(sizeof(u32) * data->indir_size) + /* _RSS_INDIR */ 262 nla_total_size(data->hkey_size) + /* _RSS_HKEY */ 263 nla_total_size(0) + /* _RSS_FLOW_HASH */ 264 nla_total_size(sizeof(u32)) * ETHTOOL_A_FLOW_MAX + 265 0; 266 267 return len; 268 } 269 270 static int 271 rss_fill_reply(struct sk_buff *skb, const struct ethnl_req_info *req_base, 272 const struct ethnl_reply_data *reply_base) 273 { 274 const struct rss_reply_data *data = RSS_REPDATA(reply_base); 275 struct rss_req_info *request = RSS_REQINFO(req_base); 276 277 if (request->rss_context && 278 nla_put_u32(skb, ETHTOOL_A_RSS_CONTEXT, request->rss_context)) 279 return -EMSGSIZE; 280 281 if ((data->indir_size && 282 nla_put(skb, ETHTOOL_A_RSS_INDIR, 283 sizeof(u32) * data->indir_size, data->indir_table))) 284 return -EMSGSIZE; 285 286 if (!data->no_key_fields && 287 ((data->hfunc && 288 nla_put_u32(skb, ETHTOOL_A_RSS_HFUNC, data->hfunc)) || 289 (data->input_xfrm && 290 nla_put_u32(skb, ETHTOOL_A_RSS_INPUT_XFRM, data->input_xfrm)) || 291 (data->hkey_size && 292 nla_put(skb, ETHTOOL_A_RSS_HKEY, data->hkey_size, data->hkey)))) 293 return -EMSGSIZE; 294 295 if (data->has_flow_hash) { 296 struct nlattr *nest; 297 int i; 298 299 nest = nla_nest_start(skb, ETHTOOL_A_RSS_FLOW_HASH); 300 if (!nest) 301 return -EMSGSIZE; 302 303 for (i = 1; i < __ETHTOOL_A_FLOW_CNT; i++) { 304 if (data->flow_hash[i] >= 0 && 305 nla_put_uint(skb, i, data->flow_hash[i])) { 306 nla_nest_cancel(skb, nest); 307 return -EMSGSIZE; 308 } 309 } 310 311 nla_nest_end(skb, nest); 312 } 313 314 return 0; 315 } 316 317 static void rss_cleanup_data(struct ethnl_reply_data *reply_base) 318 { 319 const struct rss_reply_data *data = RSS_REPDATA(reply_base); 320 321 kfree(data->indir_table); 322 } 323 324 struct rss_nl_dump_ctx { 325 unsigned long ifindex; 326 unsigned long ctx_idx; 327 328 /* User wants to only dump contexts from given ifindex */ 329 unsigned int match_ifindex; 330 unsigned int start_ctx; 331 }; 332 333 static struct rss_nl_dump_ctx *rss_dump_ctx(struct netlink_callback *cb) 334 { 335 NL_ASSERT_CTX_FITS(struct rss_nl_dump_ctx); 336 337 return (struct rss_nl_dump_ctx *)cb->ctx; 338 } 339 340 int ethnl_rss_dump_start(struct netlink_callback *cb) 341 { 342 const struct genl_info *info = genl_info_dump(cb); 343 struct rss_nl_dump_ctx *ctx = rss_dump_ctx(cb); 344 struct ethnl_req_info req_info = {}; 345 struct nlattr **tb = info->attrs; 346 int ret; 347 348 /* Filtering by context not supported */ 349 if (tb[ETHTOOL_A_RSS_CONTEXT]) { 350 NL_SET_BAD_ATTR(info->extack, tb[ETHTOOL_A_RSS_CONTEXT]); 351 return -EINVAL; 352 } 353 if (tb[ETHTOOL_A_RSS_START_CONTEXT]) { 354 ctx->start_ctx = nla_get_u32(tb[ETHTOOL_A_RSS_START_CONTEXT]); 355 ctx->ctx_idx = ctx->start_ctx; 356 } 357 358 ret = ethnl_parse_header_dev_get(&req_info, 359 tb[ETHTOOL_A_RSS_HEADER], 360 sock_net(cb->skb->sk), cb->extack, 361 false); 362 if (req_info.dev) { 363 ctx->match_ifindex = req_info.dev->ifindex; 364 ctx->ifindex = ctx->match_ifindex; 365 ethnl_parse_header_dev_put(&req_info); 366 req_info.dev = NULL; 367 } 368 369 return ret; 370 } 371 372 static int 373 rss_dump_one_ctx(struct sk_buff *skb, struct netlink_callback *cb, 374 struct net_device *dev, u32 rss_context) 375 { 376 const struct genl_info *info = genl_info_dump(cb); 377 struct rss_reply_data data = {}; 378 struct rss_req_info req = {}; 379 void *ehdr; 380 int ret; 381 382 req.rss_context = rss_context; 383 384 ehdr = ethnl_dump_put(skb, cb, ETHTOOL_MSG_RSS_GET_REPLY); 385 if (!ehdr) 386 return -EMSGSIZE; 387 388 ret = ethnl_fill_reply_header(skb, dev, ETHTOOL_A_RSS_HEADER); 389 if (ret < 0) 390 goto err_cancel; 391 392 ret = rss_prepare(&req, dev, &data, info); 393 if (ret) 394 goto err_cancel; 395 396 ret = rss_fill_reply(skb, &req.base, &data.base); 397 if (ret) 398 goto err_cleanup; 399 genlmsg_end(skb, ehdr); 400 401 rss_cleanup_data(&data.base); 402 return 0; 403 404 err_cleanup: 405 rss_cleanup_data(&data.base); 406 err_cancel: 407 genlmsg_cancel(skb, ehdr); 408 return ret; 409 } 410 411 static int 412 rss_dump_one_dev(struct sk_buff *skb, struct netlink_callback *cb, 413 struct net_device *dev) 414 { 415 struct rss_nl_dump_ctx *ctx = rss_dump_ctx(cb); 416 int ret; 417 418 if (!dev->ethtool_ops->get_rxfh) 419 return 0; 420 421 if (!ctx->ctx_idx) { 422 ret = rss_dump_one_ctx(skb, cb, dev, 0); 423 if (ret) 424 return ret; 425 ctx->ctx_idx++; 426 } 427 428 for (; xa_find(&dev->ethtool->rss_ctx, &ctx->ctx_idx, 429 ULONG_MAX, XA_PRESENT); ctx->ctx_idx++) { 430 ret = rss_dump_one_ctx(skb, cb, dev, ctx->ctx_idx); 431 if (ret) 432 return ret; 433 } 434 ctx->ctx_idx = ctx->start_ctx; 435 436 return 0; 437 } 438 439 int ethnl_rss_dumpit(struct sk_buff *skb, struct netlink_callback *cb) 440 { 441 struct rss_nl_dump_ctx *ctx = rss_dump_ctx(cb); 442 struct net *net = sock_net(skb->sk); 443 struct net_device *dev; 444 int ret = 0; 445 446 rtnl_lock(); 447 for_each_netdev_dump(net, dev, ctx->ifindex) { 448 if (ctx->match_ifindex && ctx->match_ifindex != ctx->ifindex) 449 break; 450 451 netdev_lock_ops(dev); 452 ret = rss_dump_one_dev(skb, cb, dev); 453 netdev_unlock_ops(dev); 454 if (ret) 455 break; 456 } 457 rtnl_unlock(); 458 459 return ret; 460 } 461 462 /* RSS_NTF */ 463 464 void ethtool_rss_notify(struct net_device *dev, u32 rss_context) 465 { 466 struct rss_req_info req_info = { 467 .rss_context = rss_context, 468 }; 469 470 ethnl_notify(dev, ETHTOOL_MSG_RSS_NTF, &req_info.base); 471 } 472 473 /* RSS_SET */ 474 475 const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_START_CONTEXT + 1] = { 476 [ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy), 477 [ETHTOOL_A_RSS_CONTEXT] = { .type = NLA_U32, }, 478 [ETHTOOL_A_RSS_INDIR] = { .type = NLA_BINARY, }, 479 }; 480 481 static int 482 ethnl_rss_set_validate(struct ethnl_req_info *req_info, struct genl_info *info) 483 { 484 const struct ethtool_ops *ops = req_info->dev->ethtool_ops; 485 struct rss_req_info *request = RSS_REQINFO(req_info); 486 struct nlattr **tb = info->attrs; 487 struct nlattr *bad_attr = NULL; 488 489 if (request->rss_context && !ops->create_rxfh_context) 490 bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_CONTEXT]; 491 492 if (bad_attr) { 493 NL_SET_BAD_ATTR(info->extack, bad_attr); 494 return -EOPNOTSUPP; 495 } 496 497 return 1; 498 } 499 500 static int 501 rss_set_prep_indir(struct net_device *dev, struct genl_info *info, 502 struct rss_reply_data *data, struct ethtool_rxfh_param *rxfh, 503 bool *reset, bool *mod) 504 { 505 const struct ethtool_ops *ops = dev->ethtool_ops; 506 struct netlink_ext_ack *extack = info->extack; 507 struct nlattr **tb = info->attrs; 508 struct ethtool_rxnfc rx_rings; 509 size_t alloc_size; 510 u32 user_size; 511 int i, err; 512 513 if (!tb[ETHTOOL_A_RSS_INDIR]) 514 return 0; 515 if (!data->indir_size || !ops->get_rxnfc) 516 return -EOPNOTSUPP; 517 518 rx_rings.cmd = ETHTOOL_GRXRINGS; 519 err = ops->get_rxnfc(dev, &rx_rings, NULL); 520 if (err) 521 return err; 522 523 if (nla_len(tb[ETHTOOL_A_RSS_INDIR]) % 4) { 524 NL_SET_BAD_ATTR(info->extack, tb[ETHTOOL_A_RSS_INDIR]); 525 return -EINVAL; 526 } 527 user_size = nla_len(tb[ETHTOOL_A_RSS_INDIR]) / 4; 528 if (!user_size) { 529 if (rxfh->rss_context) { 530 NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_RSS_INDIR], 531 "can't reset table for a context"); 532 return -EINVAL; 533 } 534 *reset = true; 535 } else if (data->indir_size % user_size) { 536 NL_SET_ERR_MSG_ATTR_FMT(extack, tb[ETHTOOL_A_RSS_INDIR], 537 "size (%d) mismatch with device indir table (%d)", 538 user_size, data->indir_size); 539 return -EINVAL; 540 } 541 542 rxfh->indir_size = data->indir_size; 543 alloc_size = array_size(data->indir_size, sizeof(rxfh->indir[0])); 544 rxfh->indir = kzalloc(alloc_size, GFP_KERNEL); 545 if (!rxfh->indir) 546 return -ENOMEM; 547 548 nla_memcpy(rxfh->indir, tb[ETHTOOL_A_RSS_INDIR], alloc_size); 549 for (i = 0; i < user_size; i++) { 550 if (rxfh->indir[i] < rx_rings.data) 551 continue; 552 553 NL_SET_ERR_MSG_ATTR_FMT(extack, tb[ETHTOOL_A_RSS_INDIR], 554 "entry %d: queue out of range (%d)", 555 i, rxfh->indir[i]); 556 err = -EINVAL; 557 goto err_free; 558 } 559 560 if (user_size) { 561 /* Replicate the user-provided table to fill the device table */ 562 for (i = user_size; i < data->indir_size; i++) 563 rxfh->indir[i] = rxfh->indir[i % user_size]; 564 } else { 565 for (i = 0; i < data->indir_size; i++) 566 rxfh->indir[i] = 567 ethtool_rxfh_indir_default(i, rx_rings.data); 568 } 569 570 *mod |= memcmp(rxfh->indir, data->indir_table, data->indir_size); 571 572 return 0; 573 574 err_free: 575 kfree(rxfh->indir); 576 rxfh->indir = NULL; 577 return err; 578 } 579 580 static void 581 rss_set_ctx_update(struct ethtool_rxfh_context *ctx, struct nlattr **tb, 582 struct rss_reply_data *data, struct ethtool_rxfh_param *rxfh) 583 { 584 int i; 585 586 if (rxfh->indir) { 587 for (i = 0; i < data->indir_size; i++) 588 ethtool_rxfh_context_indir(ctx)[i] = rxfh->indir[i]; 589 ctx->indir_configured = !!nla_len(tb[ETHTOOL_A_RSS_INDIR]); 590 } 591 } 592 593 static int 594 ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info) 595 { 596 struct rss_req_info *request = RSS_REQINFO(req_info); 597 struct ethtool_rxfh_context *ctx = NULL; 598 struct net_device *dev = req_info->dev; 599 struct ethtool_rxfh_param rxfh = {}; 600 bool indir_reset = false, indir_mod; 601 struct nlattr **tb = info->attrs; 602 struct rss_reply_data data = {}; 603 const struct ethtool_ops *ops; 604 bool mod = false; 605 int ret; 606 607 ops = dev->ethtool_ops; 608 data.base.dev = dev; 609 610 ret = rss_prepare(request, dev, &data, info); 611 if (ret) 612 return ret; 613 614 rxfh.rss_context = request->rss_context; 615 616 ret = rss_set_prep_indir(dev, info, &data, &rxfh, &indir_reset, &mod); 617 if (ret) 618 goto exit_clean_data; 619 indir_mod = !!tb[ETHTOOL_A_RSS_INDIR]; 620 621 rxfh.hfunc = ETH_RSS_HASH_NO_CHANGE; 622 rxfh.input_xfrm = RXH_XFRM_NO_CHANGE; 623 624 mutex_lock(&dev->ethtool->rss_lock); 625 if (request->rss_context) { 626 ctx = xa_load(&dev->ethtool->rss_ctx, request->rss_context); 627 if (!ctx) { 628 ret = -ENOENT; 629 goto exit_unlock; 630 } 631 } 632 633 if (!mod) 634 ret = 0; /* nothing to tell the driver */ 635 else if (!ops->set_rxfh) 636 ret = -EOPNOTSUPP; 637 else if (!rxfh.rss_context) 638 ret = ops->set_rxfh(dev, &rxfh, info->extack); 639 else 640 ret = ops->modify_rxfh_context(dev, ctx, &rxfh, info->extack); 641 if (ret) 642 goto exit_unlock; 643 644 if (ctx) 645 rss_set_ctx_update(ctx, tb, &data, &rxfh); 646 else if (indir_reset) 647 dev->priv_flags &= ~IFF_RXFH_CONFIGURED; 648 else if (indir_mod) 649 dev->priv_flags |= IFF_RXFH_CONFIGURED; 650 651 exit_unlock: 652 mutex_unlock(&dev->ethtool->rss_lock); 653 kfree(rxfh.indir); 654 exit_clean_data: 655 rss_cleanup_data(&data.base); 656 657 return ret ?: mod; 658 } 659 660 const struct ethnl_request_ops ethnl_rss_request_ops = { 661 .request_cmd = ETHTOOL_MSG_RSS_GET, 662 .reply_cmd = ETHTOOL_MSG_RSS_GET_REPLY, 663 .hdr_attr = ETHTOOL_A_RSS_HEADER, 664 .req_info_size = sizeof(struct rss_req_info), 665 .reply_data_size = sizeof(struct rss_reply_data), 666 667 .parse_request = rss_parse_request, 668 .prepare_data = rss_prepare_data, 669 .reply_size = rss_reply_size, 670 .fill_reply = rss_fill_reply, 671 .cleanup_data = rss_cleanup_data, 672 673 .set_validate = ethnl_rss_set_validate, 674 .set = ethnl_rss_set, 675 .set_ntf_cmd = ETHTOOL_MSG_RSS_NTF, 676 }; 677