xref: /linux/net/devlink/dpipe.c (revision fcc79e1714e8c2b8e216dc3149812edd37884eef)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4  * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
5  */
6 
7 #include "devl_internal.h"
8 
9 static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = {
10 	{
11 		.name = "destination mac",
12 		.id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
13 		.bitwidth = 48,
14 	},
15 };
16 
17 struct devlink_dpipe_header devlink_dpipe_header_ethernet = {
18 	.name = "ethernet",
19 	.id = DEVLINK_DPIPE_HEADER_ETHERNET,
20 	.fields = devlink_dpipe_fields_ethernet,
21 	.fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet),
22 	.global = true,
23 };
24 EXPORT_SYMBOL_GPL(devlink_dpipe_header_ethernet);
25 
26 static struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = {
27 	{
28 		.name = "destination ip",
29 		.id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
30 		.bitwidth = 32,
31 	},
32 };
33 
34 struct devlink_dpipe_header devlink_dpipe_header_ipv4 = {
35 	.name = "ipv4",
36 	.id = DEVLINK_DPIPE_HEADER_IPV4,
37 	.fields = devlink_dpipe_fields_ipv4,
38 	.fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4),
39 	.global = true,
40 };
41 EXPORT_SYMBOL_GPL(devlink_dpipe_header_ipv4);
42 
43 static struct devlink_dpipe_field devlink_dpipe_fields_ipv6[] = {
44 	{
45 		.name = "destination ip",
46 		.id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
47 		.bitwidth = 128,
48 	},
49 };
50 
51 struct devlink_dpipe_header devlink_dpipe_header_ipv6 = {
52 	.name = "ipv6",
53 	.id = DEVLINK_DPIPE_HEADER_IPV6,
54 	.fields = devlink_dpipe_fields_ipv6,
55 	.fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv6),
56 	.global = true,
57 };
58 EXPORT_SYMBOL_GPL(devlink_dpipe_header_ipv6);
59 
60 int devlink_dpipe_match_put(struct sk_buff *skb,
61 			    struct devlink_dpipe_match *match)
62 {
63 	struct devlink_dpipe_header *header = match->header;
64 	struct devlink_dpipe_field *field = &header->fields[match->field_id];
65 	struct nlattr *match_attr;
66 
67 	match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH);
68 	if (!match_attr)
69 		return -EMSGSIZE;
70 
71 	if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
72 	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
73 	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
74 	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
75 	    nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
76 		goto nla_put_failure;
77 
78 	nla_nest_end(skb, match_attr);
79 	return 0;
80 
81 nla_put_failure:
82 	nla_nest_cancel(skb, match_attr);
83 	return -EMSGSIZE;
84 }
85 EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
86 
87 static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
88 				     struct sk_buff *skb)
89 {
90 	struct nlattr *matches_attr;
91 
92 	matches_attr = nla_nest_start_noflag(skb,
93 					     DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
94 	if (!matches_attr)
95 		return -EMSGSIZE;
96 
97 	if (table->table_ops->matches_dump(table->priv, skb))
98 		goto nla_put_failure;
99 
100 	nla_nest_end(skb, matches_attr);
101 	return 0;
102 
103 nla_put_failure:
104 	nla_nest_cancel(skb, matches_attr);
105 	return -EMSGSIZE;
106 }
107 
108 int devlink_dpipe_action_put(struct sk_buff *skb,
109 			     struct devlink_dpipe_action *action)
110 {
111 	struct devlink_dpipe_header *header = action->header;
112 	struct devlink_dpipe_field *field = &header->fields[action->field_id];
113 	struct nlattr *action_attr;
114 
115 	action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION);
116 	if (!action_attr)
117 		return -EMSGSIZE;
118 
119 	if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
120 	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
121 	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
122 	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
123 	    nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
124 		goto nla_put_failure;
125 
126 	nla_nest_end(skb, action_attr);
127 	return 0;
128 
129 nla_put_failure:
130 	nla_nest_cancel(skb, action_attr);
131 	return -EMSGSIZE;
132 }
133 EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
134 
135 static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
136 				     struct sk_buff *skb)
137 {
138 	struct nlattr *actions_attr;
139 
140 	actions_attr = nla_nest_start_noflag(skb,
141 					     DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
142 	if (!actions_attr)
143 		return -EMSGSIZE;
144 
145 	if (table->table_ops->actions_dump(table->priv, skb))
146 		goto nla_put_failure;
147 
148 	nla_nest_end(skb, actions_attr);
149 	return 0;
150 
151 nla_put_failure:
152 	nla_nest_cancel(skb, actions_attr);
153 	return -EMSGSIZE;
154 }
155 
156 static int devlink_dpipe_table_put(struct sk_buff *skb,
157 				   struct devlink_dpipe_table *table)
158 {
159 	struct nlattr *table_attr;
160 	u64 table_size;
161 
162 	table_size = table->table_ops->size_get(table->priv);
163 	table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE);
164 	if (!table_attr)
165 		return -EMSGSIZE;
166 
167 	if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
168 	    devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size))
169 		goto nla_put_failure;
170 	if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
171 		       table->counters_enabled))
172 		goto nla_put_failure;
173 
174 	if (table->resource_valid) {
175 		if (devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
176 				       table->resource_id) ||
177 		    devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
178 				       table->resource_units))
179 			goto nla_put_failure;
180 	}
181 	if (devlink_dpipe_matches_put(table, skb))
182 		goto nla_put_failure;
183 
184 	if (devlink_dpipe_actions_put(table, skb))
185 		goto nla_put_failure;
186 
187 	nla_nest_end(skb, table_attr);
188 	return 0;
189 
190 nla_put_failure:
191 	nla_nest_cancel(skb, table_attr);
192 	return -EMSGSIZE;
193 }
194 
195 static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
196 					    struct genl_info *info)
197 {
198 	int err;
199 
200 	if (*pskb) {
201 		err = genlmsg_reply(*pskb, info);
202 		if (err)
203 			return err;
204 	}
205 	*pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
206 	if (!*pskb)
207 		return -ENOMEM;
208 	return 0;
209 }
210 
211 static int devlink_dpipe_tables_fill(struct genl_info *info,
212 				     enum devlink_command cmd, int flags,
213 				     struct list_head *dpipe_tables,
214 				     const char *table_name)
215 {
216 	struct devlink *devlink = info->user_ptr[0];
217 	struct devlink_dpipe_table *table;
218 	struct nlattr *tables_attr;
219 	struct sk_buff *skb = NULL;
220 	struct nlmsghdr *nlh;
221 	bool incomplete;
222 	void *hdr;
223 	int i;
224 	int err;
225 
226 	table = list_first_entry(dpipe_tables,
227 				 struct devlink_dpipe_table, list);
228 start_again:
229 	err = devlink_dpipe_send_and_alloc_skb(&skb, info);
230 	if (err)
231 		return err;
232 
233 	hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
234 			  &devlink_nl_family, NLM_F_MULTI, cmd);
235 	if (!hdr) {
236 		nlmsg_free(skb);
237 		return -EMSGSIZE;
238 	}
239 
240 	if (devlink_nl_put_handle(skb, devlink))
241 		goto nla_put_failure;
242 	tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES);
243 	if (!tables_attr)
244 		goto nla_put_failure;
245 
246 	i = 0;
247 	incomplete = false;
248 	list_for_each_entry_from(table, dpipe_tables, list) {
249 		if (!table_name) {
250 			err = devlink_dpipe_table_put(skb, table);
251 			if (err) {
252 				if (!i)
253 					goto err_table_put;
254 				incomplete = true;
255 				break;
256 			}
257 		} else {
258 			if (!strcmp(table->name, table_name)) {
259 				err = devlink_dpipe_table_put(skb, table);
260 				if (err)
261 					break;
262 			}
263 		}
264 		i++;
265 	}
266 
267 	nla_nest_end(skb, tables_attr);
268 	genlmsg_end(skb, hdr);
269 	if (incomplete)
270 		goto start_again;
271 
272 send_done:
273 	nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
274 			NLMSG_DONE, 0, flags | NLM_F_MULTI);
275 	if (!nlh) {
276 		err = devlink_dpipe_send_and_alloc_skb(&skb, info);
277 		if (err)
278 			return err;
279 		goto send_done;
280 	}
281 
282 	return genlmsg_reply(skb, info);
283 
284 nla_put_failure:
285 	err = -EMSGSIZE;
286 err_table_put:
287 	nlmsg_free(skb);
288 	return err;
289 }
290 
291 int devlink_nl_dpipe_table_get_doit(struct sk_buff *skb, struct genl_info *info)
292 {
293 	struct devlink *devlink = info->user_ptr[0];
294 	const char *table_name =  NULL;
295 
296 	if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
297 		table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
298 
299 	return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
300 					 &devlink->dpipe_table_list,
301 					 table_name);
302 }
303 
304 static int devlink_dpipe_value_put(struct sk_buff *skb,
305 				   struct devlink_dpipe_value *value)
306 {
307 	if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
308 		    value->value_size, value->value))
309 		return -EMSGSIZE;
310 	if (value->mask)
311 		if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
312 			    value->value_size, value->mask))
313 			return -EMSGSIZE;
314 	if (value->mapping_valid)
315 		if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
316 				value->mapping_value))
317 			return -EMSGSIZE;
318 	return 0;
319 }
320 
321 static int devlink_dpipe_action_value_put(struct sk_buff *skb,
322 					  struct devlink_dpipe_value *value)
323 {
324 	if (!value->action)
325 		return -EINVAL;
326 	if (devlink_dpipe_action_put(skb, value->action))
327 		return -EMSGSIZE;
328 	if (devlink_dpipe_value_put(skb, value))
329 		return -EMSGSIZE;
330 	return 0;
331 }
332 
333 static int devlink_dpipe_action_values_put(struct sk_buff *skb,
334 					   struct devlink_dpipe_value *values,
335 					   unsigned int values_count)
336 {
337 	struct nlattr *action_attr;
338 	int i;
339 	int err;
340 
341 	for (i = 0; i < values_count; i++) {
342 		action_attr = nla_nest_start_noflag(skb,
343 						    DEVLINK_ATTR_DPIPE_ACTION_VALUE);
344 		if (!action_attr)
345 			return -EMSGSIZE;
346 		err = devlink_dpipe_action_value_put(skb, &values[i]);
347 		if (err)
348 			goto err_action_value_put;
349 		nla_nest_end(skb, action_attr);
350 	}
351 	return 0;
352 
353 err_action_value_put:
354 	nla_nest_cancel(skb, action_attr);
355 	return err;
356 }
357 
358 static int devlink_dpipe_match_value_put(struct sk_buff *skb,
359 					 struct devlink_dpipe_value *value)
360 {
361 	if (!value->match)
362 		return -EINVAL;
363 	if (devlink_dpipe_match_put(skb, value->match))
364 		return -EMSGSIZE;
365 	if (devlink_dpipe_value_put(skb, value))
366 		return -EMSGSIZE;
367 	return 0;
368 }
369 
370 static int devlink_dpipe_match_values_put(struct sk_buff *skb,
371 					  struct devlink_dpipe_value *values,
372 					  unsigned int values_count)
373 {
374 	struct nlattr *match_attr;
375 	int i;
376 	int err;
377 
378 	for (i = 0; i < values_count; i++) {
379 		match_attr = nla_nest_start_noflag(skb,
380 						   DEVLINK_ATTR_DPIPE_MATCH_VALUE);
381 		if (!match_attr)
382 			return -EMSGSIZE;
383 		err = devlink_dpipe_match_value_put(skb, &values[i]);
384 		if (err)
385 			goto err_match_value_put;
386 		nla_nest_end(skb, match_attr);
387 	}
388 	return 0;
389 
390 err_match_value_put:
391 	nla_nest_cancel(skb, match_attr);
392 	return err;
393 }
394 
395 static int devlink_dpipe_entry_put(struct sk_buff *skb,
396 				   struct devlink_dpipe_entry *entry)
397 {
398 	struct nlattr *entry_attr, *matches_attr, *actions_attr;
399 	int err;
400 
401 	entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY);
402 	if (!entry_attr)
403 		return  -EMSGSIZE;
404 
405 	if (devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index))
406 		goto nla_put_failure;
407 	if (entry->counter_valid)
408 		if (devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
409 				       entry->counter))
410 			goto nla_put_failure;
411 
412 	matches_attr = nla_nest_start_noflag(skb,
413 					     DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
414 	if (!matches_attr)
415 		goto nla_put_failure;
416 
417 	err = devlink_dpipe_match_values_put(skb, entry->match_values,
418 					     entry->match_values_count);
419 	if (err) {
420 		nla_nest_cancel(skb, matches_attr);
421 		goto err_match_values_put;
422 	}
423 	nla_nest_end(skb, matches_attr);
424 
425 	actions_attr = nla_nest_start_noflag(skb,
426 					     DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
427 	if (!actions_attr)
428 		goto nla_put_failure;
429 
430 	err = devlink_dpipe_action_values_put(skb, entry->action_values,
431 					      entry->action_values_count);
432 	if (err) {
433 		nla_nest_cancel(skb, actions_attr);
434 		goto err_action_values_put;
435 	}
436 	nla_nest_end(skb, actions_attr);
437 
438 	nla_nest_end(skb, entry_attr);
439 	return 0;
440 
441 nla_put_failure:
442 	err = -EMSGSIZE;
443 err_match_values_put:
444 err_action_values_put:
445 	nla_nest_cancel(skb, entry_attr);
446 	return err;
447 }
448 
449 static struct devlink_dpipe_table *
450 devlink_dpipe_table_find(struct list_head *dpipe_tables,
451 			 const char *table_name, struct devlink *devlink)
452 {
453 	struct devlink_dpipe_table *table;
454 
455 	list_for_each_entry_rcu(table, dpipe_tables, list,
456 				lockdep_is_held(&devlink->lock)) {
457 		if (!strcmp(table->name, table_name))
458 			return table;
459 	}
460 	return NULL;
461 }
462 
463 int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
464 {
465 	struct devlink *devlink;
466 	int err;
467 
468 	err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
469 					       dump_ctx->info);
470 	if (err)
471 		return err;
472 
473 	dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
474 				    dump_ctx->info->snd_portid,
475 				    dump_ctx->info->snd_seq,
476 				    &devlink_nl_family, NLM_F_MULTI,
477 				    dump_ctx->cmd);
478 	if (!dump_ctx->hdr)
479 		goto nla_put_failure;
480 
481 	devlink = dump_ctx->info->user_ptr[0];
482 	if (devlink_nl_put_handle(dump_ctx->skb, devlink))
483 		goto nla_put_failure;
484 	dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb,
485 					       DEVLINK_ATTR_DPIPE_ENTRIES);
486 	if (!dump_ctx->nest)
487 		goto nla_put_failure;
488 	return 0;
489 
490 nla_put_failure:
491 	nlmsg_free(dump_ctx->skb);
492 	return -EMSGSIZE;
493 }
494 EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
495 
496 int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
497 				   struct devlink_dpipe_entry *entry)
498 {
499 	return devlink_dpipe_entry_put(dump_ctx->skb, entry);
500 }
501 EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
502 
503 int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
504 {
505 	nla_nest_end(dump_ctx->skb, dump_ctx->nest);
506 	genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
507 	return 0;
508 }
509 EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
510 
511 void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
512 
513 {
514 	unsigned int value_count, value_index;
515 	struct devlink_dpipe_value *value;
516 
517 	value = entry->action_values;
518 	value_count = entry->action_values_count;
519 	for (value_index = 0; value_index < value_count; value_index++) {
520 		kfree(value[value_index].value);
521 		kfree(value[value_index].mask);
522 	}
523 
524 	value = entry->match_values;
525 	value_count = entry->match_values_count;
526 	for (value_index = 0; value_index < value_count; value_index++) {
527 		kfree(value[value_index].value);
528 		kfree(value[value_index].mask);
529 	}
530 }
531 EXPORT_SYMBOL_GPL(devlink_dpipe_entry_clear);
532 
533 static int devlink_dpipe_entries_fill(struct genl_info *info,
534 				      enum devlink_command cmd, int flags,
535 				      struct devlink_dpipe_table *table)
536 {
537 	struct devlink_dpipe_dump_ctx dump_ctx;
538 	struct nlmsghdr *nlh;
539 	int err;
540 
541 	dump_ctx.skb = NULL;
542 	dump_ctx.cmd = cmd;
543 	dump_ctx.info = info;
544 
545 	err = table->table_ops->entries_dump(table->priv,
546 					     table->counters_enabled,
547 					     &dump_ctx);
548 	if (err)
549 		return err;
550 
551 send_done:
552 	nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
553 			NLMSG_DONE, 0, flags | NLM_F_MULTI);
554 	if (!nlh) {
555 		err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
556 		if (err)
557 			return err;
558 		goto send_done;
559 	}
560 	return genlmsg_reply(dump_ctx.skb, info);
561 }
562 
563 int devlink_nl_dpipe_entries_get_doit(struct sk_buff *skb,
564 				      struct genl_info *info)
565 {
566 	struct devlink *devlink = info->user_ptr[0];
567 	struct devlink_dpipe_table *table;
568 	const char *table_name;
569 
570 	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_DPIPE_TABLE_NAME))
571 		return -EINVAL;
572 
573 	table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
574 	table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
575 					 table_name, devlink);
576 	if (!table)
577 		return -EINVAL;
578 
579 	if (!table->table_ops->entries_dump)
580 		return -EINVAL;
581 
582 	return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
583 					  0, table);
584 }
585 
586 static int devlink_dpipe_fields_put(struct sk_buff *skb,
587 				    const struct devlink_dpipe_header *header)
588 {
589 	struct devlink_dpipe_field *field;
590 	struct nlattr *field_attr;
591 	int i;
592 
593 	for (i = 0; i < header->fields_count; i++) {
594 		field = &header->fields[i];
595 		field_attr = nla_nest_start_noflag(skb,
596 						   DEVLINK_ATTR_DPIPE_FIELD);
597 		if (!field_attr)
598 			return -EMSGSIZE;
599 		if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
600 		    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
601 		    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
602 		    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
603 			goto nla_put_failure;
604 		nla_nest_end(skb, field_attr);
605 	}
606 	return 0;
607 
608 nla_put_failure:
609 	nla_nest_cancel(skb, field_attr);
610 	return -EMSGSIZE;
611 }
612 
613 static int devlink_dpipe_header_put(struct sk_buff *skb,
614 				    struct devlink_dpipe_header *header)
615 {
616 	struct nlattr *fields_attr, *header_attr;
617 	int err;
618 
619 	header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER);
620 	if (!header_attr)
621 		return -EMSGSIZE;
622 
623 	if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
624 	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
625 	    nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
626 		goto nla_put_failure;
627 
628 	fields_attr = nla_nest_start_noflag(skb,
629 					    DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
630 	if (!fields_attr)
631 		goto nla_put_failure;
632 
633 	err = devlink_dpipe_fields_put(skb, header);
634 	if (err) {
635 		nla_nest_cancel(skb, fields_attr);
636 		goto nla_put_failure;
637 	}
638 	nla_nest_end(skb, fields_attr);
639 	nla_nest_end(skb, header_attr);
640 	return 0;
641 
642 nla_put_failure:
643 	err = -EMSGSIZE;
644 	nla_nest_cancel(skb, header_attr);
645 	return err;
646 }
647 
648 static int devlink_dpipe_headers_fill(struct genl_info *info,
649 				      enum devlink_command cmd, int flags,
650 				      struct devlink_dpipe_headers *
651 				      dpipe_headers)
652 {
653 	struct devlink *devlink = info->user_ptr[0];
654 	struct nlattr *headers_attr;
655 	struct sk_buff *skb = NULL;
656 	struct nlmsghdr *nlh;
657 	void *hdr;
658 	int i, j;
659 	int err;
660 
661 	i = 0;
662 start_again:
663 	err = devlink_dpipe_send_and_alloc_skb(&skb, info);
664 	if (err)
665 		return err;
666 
667 	hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
668 			  &devlink_nl_family, NLM_F_MULTI, cmd);
669 	if (!hdr) {
670 		nlmsg_free(skb);
671 		return -EMSGSIZE;
672 	}
673 
674 	if (devlink_nl_put_handle(skb, devlink))
675 		goto nla_put_failure;
676 	headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS);
677 	if (!headers_attr)
678 		goto nla_put_failure;
679 
680 	j = 0;
681 	for (; i < dpipe_headers->headers_count; i++) {
682 		err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
683 		if (err) {
684 			if (!j)
685 				goto err_table_put;
686 			break;
687 		}
688 		j++;
689 	}
690 	nla_nest_end(skb, headers_attr);
691 	genlmsg_end(skb, hdr);
692 	if (i != dpipe_headers->headers_count)
693 		goto start_again;
694 
695 send_done:
696 	nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
697 			NLMSG_DONE, 0, flags | NLM_F_MULTI);
698 	if (!nlh) {
699 		err = devlink_dpipe_send_and_alloc_skb(&skb, info);
700 		if (err)
701 			return err;
702 		goto send_done;
703 	}
704 	return genlmsg_reply(skb, info);
705 
706 nla_put_failure:
707 	err = -EMSGSIZE;
708 err_table_put:
709 	nlmsg_free(skb);
710 	return err;
711 }
712 
713 int devlink_nl_dpipe_headers_get_doit(struct sk_buff *skb,
714 				      struct genl_info *info)
715 {
716 	struct devlink *devlink = info->user_ptr[0];
717 
718 	if (!devlink->dpipe_headers)
719 		return -EOPNOTSUPP;
720 	return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
721 					  0, devlink->dpipe_headers);
722 }
723 
724 static int devlink_dpipe_table_counters_set(struct devlink *devlink,
725 					    const char *table_name,
726 					    bool enable)
727 {
728 	struct devlink_dpipe_table *table;
729 
730 	table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
731 					 table_name, devlink);
732 	if (!table)
733 		return -EINVAL;
734 
735 	if (table->counter_control_extern)
736 		return -EOPNOTSUPP;
737 
738 	if (!(table->counters_enabled ^ enable))
739 		return 0;
740 
741 	table->counters_enabled = enable;
742 	if (table->table_ops->counters_set_update)
743 		table->table_ops->counters_set_update(table->priv, enable);
744 	return 0;
745 }
746 
747 int devlink_nl_dpipe_table_counters_set_doit(struct sk_buff *skb,
748 					     struct genl_info *info)
749 {
750 	struct devlink *devlink = info->user_ptr[0];
751 	const char *table_name;
752 	bool counters_enable;
753 
754 	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_DPIPE_TABLE_NAME) ||
755 	    GENL_REQ_ATTR_CHECK(info,
756 				DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED))
757 		return -EINVAL;
758 
759 	table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
760 	counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
761 
762 	return devlink_dpipe_table_counters_set(devlink, table_name,
763 						counters_enable);
764 }
765 
766 /**
767  * devl_dpipe_headers_register - register dpipe headers
768  *
769  * @devlink: devlink
770  * @dpipe_headers: dpipe header array
771  *
772  * Register the headers supported by hardware.
773  */
774 void devl_dpipe_headers_register(struct devlink *devlink,
775 				 struct devlink_dpipe_headers *dpipe_headers)
776 {
777 	lockdep_assert_held(&devlink->lock);
778 
779 	devlink->dpipe_headers = dpipe_headers;
780 }
781 EXPORT_SYMBOL_GPL(devl_dpipe_headers_register);
782 
783 /**
784  * devl_dpipe_headers_unregister - unregister dpipe headers
785  *
786  * @devlink: devlink
787  *
788  * Unregister the headers supported by hardware.
789  */
790 void devl_dpipe_headers_unregister(struct devlink *devlink)
791 {
792 	lockdep_assert_held(&devlink->lock);
793 
794 	devlink->dpipe_headers = NULL;
795 }
796 EXPORT_SYMBOL_GPL(devl_dpipe_headers_unregister);
797 
798 /**
799  *	devlink_dpipe_table_counter_enabled - check if counter allocation
800  *					      required
801  *	@devlink: devlink
802  *	@table_name: tables name
803  *
804  *	Used by driver to check if counter allocation is required.
805  *	After counter allocation is turned on the table entries
806  *	are updated to include counter statistics.
807  *
808  *	After that point on the driver must respect the counter
809  *	state so that each entry added to the table is added
810  *	with a counter.
811  */
812 bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
813 					 const char *table_name)
814 {
815 	struct devlink_dpipe_table *table;
816 	bool enabled;
817 
818 	rcu_read_lock();
819 	table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
820 					 table_name, devlink);
821 	enabled = false;
822 	if (table)
823 		enabled = table->counters_enabled;
824 	rcu_read_unlock();
825 	return enabled;
826 }
827 EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
828 
829 /**
830  * devl_dpipe_table_register - register dpipe table
831  *
832  * @devlink: devlink
833  * @table_name: table name
834  * @table_ops: table ops
835  * @priv: priv
836  * @counter_control_extern: external control for counters
837  */
838 int devl_dpipe_table_register(struct devlink *devlink,
839 			      const char *table_name,
840 			      const struct devlink_dpipe_table_ops *table_ops,
841 			      void *priv, bool counter_control_extern)
842 {
843 	struct devlink_dpipe_table *table;
844 
845 	lockdep_assert_held(&devlink->lock);
846 
847 	if (WARN_ON(!table_ops->size_get))
848 		return -EINVAL;
849 
850 	if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name,
851 				     devlink))
852 		return -EEXIST;
853 
854 	table = kzalloc(sizeof(*table), GFP_KERNEL);
855 	if (!table)
856 		return -ENOMEM;
857 
858 	table->name = table_name;
859 	table->table_ops = table_ops;
860 	table->priv = priv;
861 	table->counter_control_extern = counter_control_extern;
862 
863 	list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
864 
865 	return 0;
866 }
867 EXPORT_SYMBOL_GPL(devl_dpipe_table_register);
868 
869 /**
870  * devl_dpipe_table_unregister - unregister dpipe table
871  *
872  * @devlink: devlink
873  * @table_name: table name
874  */
875 void devl_dpipe_table_unregister(struct devlink *devlink,
876 				 const char *table_name)
877 {
878 	struct devlink_dpipe_table *table;
879 
880 	lockdep_assert_held(&devlink->lock);
881 
882 	table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
883 					 table_name, devlink);
884 	if (!table)
885 		return;
886 	list_del_rcu(&table->list);
887 	kfree_rcu(table, rcu);
888 }
889 EXPORT_SYMBOL_GPL(devl_dpipe_table_unregister);
890 
891 /**
892  * devl_dpipe_table_resource_set - set the resource id
893  *
894  * @devlink: devlink
895  * @table_name: table name
896  * @resource_id: resource id
897  * @resource_units: number of resource's units consumed per table's entry
898  */
899 int devl_dpipe_table_resource_set(struct devlink *devlink,
900 				  const char *table_name, u64 resource_id,
901 				  u64 resource_units)
902 {
903 	struct devlink_dpipe_table *table;
904 
905 	table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
906 					 table_name, devlink);
907 	if (!table)
908 		return -EINVAL;
909 
910 	table->resource_id = resource_id;
911 	table->resource_units = resource_units;
912 	table->resource_valid = true;
913 	return 0;
914 }
915 EXPORT_SYMBOL_GPL(devl_dpipe_table_resource_set);
916