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
rss_parse_request(struct ethnl_req_info * req_info,const struct genl_info * info,struct nlattr ** tb,struct netlink_ext_ack * extack)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
rss_prepare_flow_hash(const struct rss_req_info * req,struct net_device * dev,struct rss_reply_data * data,const struct genl_info * info)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
rss_get_data_alloc(struct net_device * dev,struct rss_reply_data * data)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
rss_get_data_free(const struct rss_reply_data * data)145 static void rss_get_data_free(const struct rss_reply_data *data)
146 {
147 kfree(data->indir_table);
148 }
149
150 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)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
__rss_prepare_ctx(struct net_device * dev,struct rss_reply_data * data,struct ethtool_rxfh_context * ctx)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
rss_prepare_ctx(const struct rss_req_info * request,struct net_device * dev,struct rss_reply_data * data,const struct genl_info * info)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
rss_prepare(const struct rss_req_info * request,struct net_device * dev,struct rss_reply_data * data,const struct genl_info * info)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
rss_prepare_data(const struct ethnl_req_info * req_base,struct ethnl_reply_data * reply_base,const struct genl_info * info)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
rss_reply_size(const struct ethnl_req_info * req_base,const struct ethnl_reply_data * reply_base)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
rss_fill_reply(struct sk_buff * skb,const struct ethnl_req_info * req_base,const struct ethnl_reply_data * reply_base)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
rss_cleanup_data(struct ethnl_reply_data * reply_base)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
rss_dump_ctx(struct netlink_callback * cb)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
ethnl_rss_dump_start(struct netlink_callback * cb)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
rss_dump_one_ctx(struct sk_buff * skb,struct netlink_callback * cb,struct net_device * dev,u32 rss_context)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
rss_dump_one_dev(struct sk_buff * skb,struct netlink_callback * cb,struct net_device * dev)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
ethnl_rss_dumpit(struct sk_buff * skb,struct netlink_callback * cb)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
ethnl_rss_delete_notify(struct net_device * dev,u32 rss_context)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
ethtool_rss_notify(struct net_device * dev,u32 type,u32 rss_context)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_RANGE(NLA_U32, 1, U8_MAX),
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
ethnl_rss_set_validate(struct ethnl_req_info * req_info,struct genl_info * info)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
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)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
rss_set_prep_hkey(struct net_device * dev,struct genl_info * info,struct rss_reply_data * data,struct ethtool_rxfh_param * rxfh,bool * mod)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
rss_check_rxfh_fields_sym(struct net_device * dev,struct genl_info * info,struct rss_reply_data * data,bool xfrm_sym)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
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)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
rss_set_ctx_update(struct ethtool_rxfh_context * ctx,struct nlattr ** tb,struct rss_reply_data * data,struct ethtool_rxfh_param * rxfh)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
ethnl_rss_set(struct ethnl_req_info * req_info,struct genl_info * info)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_u32(&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_u32(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM],
864 &mod);
865 xfrm_sym = rxfh.input_xfrm || data.input_xfrm;
866 if (rxfh.input_xfrm == data.input_xfrm)
867 rxfh.input_xfrm = RXH_XFRM_NO_CHANGE;
868
869 mutex_lock(&dev->ethtool->rss_lock);
870 if (request->rss_context) {
871 ctx = xa_load(&dev->ethtool->rss_ctx, request->rss_context);
872 if (!ctx) {
873 ret = -ENOENT;
874 goto exit_unlock;
875 }
876 }
877
878 ret = ethnl_set_rss_fields(dev, info, request->rss_context,
879 &data, xfrm_sym, &fields_mod);
880 if (ret)
881 goto exit_unlock;
882
883 if (!mod)
884 ret = 0; /* nothing to tell the driver */
885 else if (!ops->set_rxfh)
886 ret = -EOPNOTSUPP;
887 else if (!rxfh.rss_context)
888 ret = ops->set_rxfh(dev, &rxfh, info->extack);
889 else
890 ret = ops->modify_rxfh_context(dev, ctx, &rxfh, info->extack);
891 if (ret)
892 goto exit_unlock;
893
894 if (ctx) {
895 rss_set_ctx_update(ctx, tb, &data, &rxfh);
896 if (indir_user_size)
897 ctx->indir_user_size = indir_user_size;
898 } else if (indir_reset) {
899 dev->ethtool->rss_indir_user_size = 0;
900 } else if (indir_mod) {
901 dev->ethtool->rss_indir_user_size = indir_user_size;
902 }
903
904 exit_unlock:
905 mutex_unlock(&dev->ethtool->rss_lock);
906 kfree(rxfh.key);
907 exit_free_indir:
908 kfree(rxfh.indir);
909 exit_clean_data:
910 rss_cleanup_data(&data.base);
911
912 return ret ?: mod || fields_mod;
913 }
914
915 const struct ethnl_request_ops ethnl_rss_request_ops = {
916 .request_cmd = ETHTOOL_MSG_RSS_GET,
917 .reply_cmd = ETHTOOL_MSG_RSS_GET_REPLY,
918 .hdr_attr = ETHTOOL_A_RSS_HEADER,
919 .req_info_size = sizeof(struct rss_req_info),
920 .reply_data_size = sizeof(struct rss_reply_data),
921
922 .parse_request = rss_parse_request,
923 .prepare_data = rss_prepare_data,
924 .reply_size = rss_reply_size,
925 .fill_reply = rss_fill_reply,
926 .cleanup_data = rss_cleanup_data,
927
928 .set_validate = ethnl_rss_set_validate,
929 .set = ethnl_rss_set,
930 .set_ntf_cmd = ETHTOOL_MSG_RSS_NTF,
931 };
932
933 /* RSS_CREATE */
934
935 const struct nla_policy ethnl_rss_create_policy[ETHTOOL_A_RSS_INPUT_XFRM + 1] = {
936 [ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
937 [ETHTOOL_A_RSS_CONTEXT] = NLA_POLICY_MIN(NLA_U32, 1),
938 [ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_RANGE(NLA_U32, 1, U8_MAX),
939 [ETHTOOL_A_RSS_INDIR] = NLA_POLICY_MIN(NLA_BINARY, 1),
940 [ETHTOOL_A_RSS_HKEY] = NLA_POLICY_MIN(NLA_BINARY, 1),
941 [ETHTOOL_A_RSS_INPUT_XFRM] =
942 NLA_POLICY_MAX(NLA_U32, RXH_XFRM_SYM_OR_XOR),
943 };
944
945 static int
ethnl_rss_create_validate(struct net_device * dev,struct genl_info * info)946 ethnl_rss_create_validate(struct net_device *dev, struct genl_info *info)
947 {
948 const struct ethtool_ops *ops = dev->ethtool_ops;
949 struct nlattr **tb = info->attrs;
950 struct nlattr *bad_attr = NULL;
951 u32 rss_context, input_xfrm;
952
953 if (!ops->create_rxfh_context)
954 return -EOPNOTSUPP;
955
956 rss_context = nla_get_u32_default(tb[ETHTOOL_A_RSS_CONTEXT], 0);
957 if (ops->rxfh_max_num_contexts &&
958 ops->rxfh_max_num_contexts <= rss_context) {
959 NL_SET_BAD_ATTR(info->extack, tb[ETHTOOL_A_RSS_CONTEXT]);
960 return -ERANGE;
961 }
962
963 if (!ops->rxfh_per_ctx_key) {
964 bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_HFUNC];
965 bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_HKEY];
966 bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_INPUT_XFRM];
967 }
968
969 input_xfrm = nla_get_u32_default(tb[ETHTOOL_A_RSS_INPUT_XFRM], 0);
970 if (input_xfrm & ~ops->supported_input_xfrm)
971 bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_INPUT_XFRM];
972
973 if (bad_attr) {
974 NL_SET_BAD_ATTR(info->extack, bad_attr);
975 return -EOPNOTSUPP;
976 }
977
978 return 0;
979 }
980
981 static void
ethnl_rss_create_send_ntf(const struct sk_buff * rsp,struct net_device * dev)982 ethnl_rss_create_send_ntf(const struct sk_buff *rsp, struct net_device *dev)
983 {
984 struct genlmsghdr *genl_hdr;
985 struct nlmsghdr *nlh;
986 struct sk_buff *ntf;
987
988 ntf = skb_copy_expand(rsp, 0, 0, GFP_KERNEL);
989 if (!ntf)
990 return;
991
992 nlh = nlmsg_hdr(ntf);
993 /* Convert the reply into a notification */
994 nlh->nlmsg_pid = 0;
995
996 genl_hdr = nlmsg_data(nlh);
997 genl_hdr->cmd = ETHTOOL_MSG_RSS_CREATE_NTF;
998
999 ethnl_multicast(ntf, dev);
1000 }
1001
ethnl_rss_create_doit(struct sk_buff * skb,struct genl_info * info)1002 int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info)
1003 {
1004 bool indir_dflt = false, mod = false, ntf_fail = false;
1005 struct ethtool_rxfh_param rxfh = {};
1006 struct ethtool_rxfh_context *ctx;
1007 struct nlattr **tb = info->attrs;
1008 struct rss_reply_data data = {};
1009 const struct ethtool_ops *ops;
1010 struct rss_req_info req = {};
1011 struct net_device *dev;
1012 u32 indir_user_size;
1013 struct sk_buff *rsp;
1014 void *hdr;
1015 u32 limit;
1016 int ret;
1017
1018 rsp = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1019 if (!rsp)
1020 return -ENOMEM;
1021
1022 ret = ethnl_parse_header_dev_get(&req.base, tb[ETHTOOL_A_RSS_HEADER],
1023 genl_info_net(info), info->extack,
1024 true);
1025 if (ret < 0)
1026 goto exit_free_rsp;
1027
1028 dev = req.base.dev;
1029 ops = dev->ethtool_ops;
1030
1031 req.rss_context = nla_get_u32_default(tb[ETHTOOL_A_RSS_CONTEXT], 0);
1032
1033 ret = ethnl_rss_create_validate(dev, info);
1034 if (ret)
1035 goto exit_free_dev;
1036
1037 netdev_lock_ops_compat(dev);
1038
1039 ret = ethnl_ops_begin(dev);
1040 if (ret < 0)
1041 goto exit_dev_unlock;
1042
1043 ret = rss_get_data_alloc(dev, &data);
1044 if (ret)
1045 goto exit_ops;
1046
1047 ret = rss_set_prep_indir(dev, info, &data, &rxfh, &indir_dflt, &mod);
1048 if (ret < 0)
1049 goto exit_clean_data;
1050 indir_user_size = ret;
1051
1052 ethnl_update_u8_u32(&rxfh.hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod);
1053
1054 ret = rss_set_prep_hkey(dev, info, &data, &rxfh, &mod);
1055 if (ret)
1056 goto exit_free_indir;
1057
1058 rxfh.input_xfrm = RXH_XFRM_NO_CHANGE;
1059 ethnl_update_u8_u32(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM],
1060 &mod);
1061
1062 ctx = ethtool_rxfh_ctx_alloc(ops, data.indir_size, data.hkey_size);
1063 if (!ctx) {
1064 ret = -ENOMEM;
1065 goto exit_free_hkey;
1066 }
1067
1068 mutex_lock(&dev->ethtool->rss_lock);
1069 if (!req.rss_context) {
1070 limit = ops->rxfh_max_num_contexts ?: U32_MAX;
1071 ret = xa_alloc(&dev->ethtool->rss_ctx, &req.rss_context, ctx,
1072 XA_LIMIT(1, limit - 1), GFP_KERNEL_ACCOUNT);
1073 } else {
1074 ret = xa_insert(&dev->ethtool->rss_ctx,
1075 req.rss_context, ctx, GFP_KERNEL_ACCOUNT);
1076 }
1077 if (ret < 0) {
1078 NL_SET_ERR_MSG_ATTR(info->extack, tb[ETHTOOL_A_RSS_CONTEXT],
1079 "error allocating context ID");
1080 goto err_unlock_free_ctx;
1081 }
1082 rxfh.rss_context = req.rss_context;
1083
1084 ret = ops->create_rxfh_context(dev, ctx, &rxfh, info->extack);
1085 if (ret)
1086 goto err_ctx_id_free;
1087
1088 /* Make sure driver populates defaults */
1089 WARN_ON_ONCE(!rxfh.key && ops->rxfh_per_ctx_key &&
1090 !memchr_inv(ethtool_rxfh_context_key(ctx), 0,
1091 ctx->key_size));
1092
1093 /* Store the config from rxfh to Xarray.. */
1094 rss_set_ctx_update(ctx, tb, &data, &rxfh);
1095 ctx->indir_user_size = indir_user_size;
1096 /* .. copy from Xarray to data. */
1097 __rss_prepare_ctx(dev, &data, ctx);
1098
1099 hdr = ethnl_unicast_put(rsp, info->snd_portid, info->snd_seq,
1100 ETHTOOL_MSG_RSS_CREATE_ACT_REPLY);
1101 ntf_fail = ethnl_fill_reply_header(rsp, dev, ETHTOOL_A_RSS_HEADER);
1102 ntf_fail |= rss_fill_reply(rsp, &req.base, &data.base);
1103 if (WARN_ON(!hdr || ntf_fail)) {
1104 ret = -EMSGSIZE;
1105 goto err_remove_ctx;
1106 }
1107
1108 genlmsg_end(rsp, hdr);
1109
1110 ethnl_rss_create_send_ntf(rsp, dev);
1111 ret = genlmsg_reply(rsp, info);
1112 rsp = NULL;
1113
1114 exit_unlock:
1115 mutex_unlock(&dev->ethtool->rss_lock);
1116 exit_free_hkey:
1117 kfree(rxfh.key);
1118 exit_free_indir:
1119 kfree(rxfh.indir);
1120 exit_clean_data:
1121 rss_get_data_free(&data);
1122 exit_ops:
1123 ethnl_ops_complete(dev);
1124 exit_dev_unlock:
1125 netdev_unlock_ops_compat(dev);
1126 exit_free_dev:
1127 ethnl_parse_header_dev_put(&req.base);
1128 exit_free_rsp:
1129 nlmsg_free(rsp);
1130 return ret;
1131
1132 err_remove_ctx:
1133 if (ops->remove_rxfh_context(dev, ctx, req.rss_context, NULL))
1134 /* leave the context on failure, like ethnl_rss_delete_doit() */
1135 goto exit_unlock;
1136 err_ctx_id_free:
1137 xa_erase(&dev->ethtool->rss_ctx, req.rss_context);
1138 err_unlock_free_ctx:
1139 kfree(ctx);
1140 goto exit_unlock;
1141 }
1142
1143 /* RSS_DELETE */
1144
1145 const struct nla_policy ethnl_rss_delete_policy[ETHTOOL_A_RSS_CONTEXT + 1] = {
1146 [ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
1147 [ETHTOOL_A_RSS_CONTEXT] = NLA_POLICY_MIN(NLA_U32, 1),
1148 };
1149
ethnl_rss_delete_doit(struct sk_buff * skb,struct genl_info * info)1150 int ethnl_rss_delete_doit(struct sk_buff *skb, struct genl_info *info)
1151 {
1152 struct ethtool_rxfh_context *ctx;
1153 struct nlattr **tb = info->attrs;
1154 struct ethnl_req_info req = {};
1155 const struct ethtool_ops *ops;
1156 struct net_device *dev;
1157 u32 rss_context;
1158 int ret;
1159
1160 if (GENL_REQ_ATTR_CHECK(info, ETHTOOL_A_RSS_CONTEXT))
1161 return -EINVAL;
1162 rss_context = nla_get_u32(tb[ETHTOOL_A_RSS_CONTEXT]);
1163
1164 ret = ethnl_parse_header_dev_get(&req, tb[ETHTOOL_A_RSS_HEADER],
1165 genl_info_net(info), info->extack,
1166 true);
1167 if (ret < 0)
1168 return ret;
1169
1170 dev = req.dev;
1171 ops = dev->ethtool_ops;
1172
1173 if (!ops->create_rxfh_context) {
1174 ret = -EOPNOTSUPP;
1175 goto exit_free_dev;
1176 }
1177
1178 netdev_lock_ops_compat(dev);
1179
1180 ret = ethnl_ops_begin(dev);
1181 if (ret < 0)
1182 goto exit_dev_unlock;
1183
1184 mutex_lock(&dev->ethtool->rss_lock);
1185 ret = ethtool_check_rss_ctx_busy(dev, rss_context);
1186 if (ret)
1187 goto exit_unlock;
1188
1189 ctx = xa_load(&dev->ethtool->rss_ctx, rss_context);
1190 if (!ctx) {
1191 ret = -ENOENT;
1192 goto exit_unlock;
1193 }
1194
1195 ret = ops->remove_rxfh_context(dev, ctx, rss_context, info->extack);
1196 if (ret)
1197 goto exit_unlock;
1198
1199 WARN_ON(xa_erase(&dev->ethtool->rss_ctx, rss_context) != ctx);
1200 kfree(ctx);
1201
1202 ethnl_rss_delete_notify(dev, rss_context);
1203
1204 exit_unlock:
1205 mutex_unlock(&dev->ethtool->rss_lock);
1206 ethnl_ops_complete(dev);
1207 exit_dev_unlock:
1208 netdev_unlock_ops_compat(dev);
1209 exit_free_dev:
1210 ethnl_parse_header_dev_put(&req);
1211 return ret;
1212 }
1213