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