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