Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/devlink/dpipe.c
26278 views
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
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
917