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 <[email protected]>
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 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
devlink_dpipe_send_and_alloc_skb(struct sk_buff ** pskb,struct genl_info * info)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
devlink_dpipe_tables_fill(struct genl_info * info,enum devlink_command cmd,int flags,struct list_head * dpipe_tables,const char * table_name)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
devlink_nl_dpipe_table_get_doit(struct sk_buff * skb,struct genl_info * info)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
devlink_dpipe_value_put(struct sk_buff * skb,struct devlink_dpipe_value * value)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
devlink_dpipe_action_value_put(struct sk_buff * skb,struct devlink_dpipe_value * value)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
devlink_dpipe_action_values_put(struct sk_buff * skb,struct devlink_dpipe_value * values,unsigned int values_count)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
devlink_dpipe_match_value_put(struct sk_buff * skb,struct devlink_dpipe_value * value)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
devlink_dpipe_match_values_put(struct sk_buff * skb,struct devlink_dpipe_value * values,unsigned int values_count)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
devlink_dpipe_entry_put(struct sk_buff * skb,struct devlink_dpipe_entry * entry)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 *
devlink_dpipe_table_find(struct list_head * dpipe_tables,const char * table_name,struct devlink * devlink)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
devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx * dump_ctx)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
devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx * dump_ctx,struct devlink_dpipe_entry * entry)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
devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx * dump_ctx)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
devlink_dpipe_entry_clear(struct devlink_dpipe_entry * entry)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
devlink_dpipe_entries_fill(struct genl_info * info,enum devlink_command cmd,int flags,struct devlink_dpipe_table * table)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
devlink_nl_dpipe_entries_get_doit(struct sk_buff * skb,struct genl_info * info)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
devlink_dpipe_fields_put(struct sk_buff * skb,const struct devlink_dpipe_header * header)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
devlink_dpipe_header_put(struct sk_buff * skb,struct devlink_dpipe_header * header)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
devlink_dpipe_headers_fill(struct genl_info * info,enum devlink_command cmd,int flags,struct devlink_dpipe_headers * dpipe_headers)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
devlink_nl_dpipe_headers_get_doit(struct sk_buff * skb,struct genl_info * info)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
devlink_dpipe_table_counters_set(struct devlink * devlink,const char * table_name,bool enable)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
devlink_nl_dpipe_table_counters_set_doit(struct sk_buff * skb,struct genl_info * info)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 */
devl_dpipe_headers_register(struct devlink * devlink,struct devlink_dpipe_headers * dpipe_headers)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 */
devl_dpipe_headers_unregister(struct devlink * devlink)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 */
devlink_dpipe_table_counter_enabled(struct devlink * devlink,const char * table_name)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 */
devl_dpipe_table_register(struct devlink * devlink,const char * table_name,const struct devlink_dpipe_table_ops * table_ops,void * priv,bool counter_control_extern)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 */
devl_dpipe_table_unregister(struct devlink * devlink,const char * table_name)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 */
devl_dpipe_table_resource_set(struct devlink * devlink,const char * table_name,u64 resource_id,u64 resource_units)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