Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.10.11.
  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
  9static 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
 17struct 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};
 24EXPORT_SYMBOL_GPL(devlink_dpipe_header_ethernet);
 25
 26static 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
 34struct 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};
 41EXPORT_SYMBOL_GPL(devlink_dpipe_header_ipv4);
 42
 43static 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
 51struct 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};
 58EXPORT_SYMBOL_GPL(devlink_dpipe_header_ipv6);
 59
 60int 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
 81nla_put_failure:
 82	nla_nest_cancel(skb, match_attr);
 83	return -EMSGSIZE;
 84}
 85EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
 86
 87static 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
103nla_put_failure:
104	nla_nest_cancel(skb, matches_attr);
105	return -EMSGSIZE;
106}
107
108int 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
129nla_put_failure:
130	nla_nest_cancel(skb, action_attr);
131	return -EMSGSIZE;
132}
133EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
134
135static 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
151nla_put_failure:
152	nla_nest_cancel(skb, actions_attr);
153	return -EMSGSIZE;
154}
155
156static 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
190nla_put_failure:
191	nla_nest_cancel(skb, table_attr);
192	return -EMSGSIZE;
193}
194
195static 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
211static 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);
228start_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
272send_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
284nla_put_failure:
285	err = -EMSGSIZE;
286err_table_put:
287	nlmsg_free(skb);
288	return err;
289}
290
291int 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
304static 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
321static 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
333static 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
353err_action_value_put:
354	nla_nest_cancel(skb, action_attr);
355	return err;
356}
357
358static 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
370static 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
390err_match_value_put:
391	nla_nest_cancel(skb, match_attr);
392	return err;
393}
394
395static 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
441nla_put_failure:
442	err = -EMSGSIZE;
443err_match_values_put:
444err_action_values_put:
445	nla_nest_cancel(skb, entry_attr);
446	return err;
447}
448
449static struct devlink_dpipe_table *
450devlink_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
463int 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
490nla_put_failure:
491	nlmsg_free(dump_ctx->skb);
492	return -EMSGSIZE;
493}
494EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
495
496int 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}
501EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
502
503int 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}
509EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
510
511void 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}
531EXPORT_SYMBOL_GPL(devlink_dpipe_entry_clear);
532
533static 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
551send_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
563int 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
586static 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
608nla_put_failure:
609	nla_nest_cancel(skb, field_attr);
610	return -EMSGSIZE;
611}
612
613static 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
642nla_put_failure:
643	err = -EMSGSIZE;
644	nla_nest_cancel(skb, header_attr);
645	return err;
646}
647
648static 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;
662start_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
695send_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
706nla_put_failure:
707	err = -EMSGSIZE;
708err_table_put:
709	nlmsg_free(skb);
710	return err;
711}
712
713int 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
724static 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
747int 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 */
774void 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}
781EXPORT_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 */
790void devl_dpipe_headers_unregister(struct devlink *devlink)
791{
792	lockdep_assert_held(&devlink->lock);
793
794	devlink->dpipe_headers = NULL;
795}
796EXPORT_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 */
812bool 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}
827EXPORT_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 */
838int 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}
867EXPORT_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 */
875void 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}
889EXPORT_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 */
899int 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}
915EXPORT_SYMBOL_GPL(devl_dpipe_table_resource_set);