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