Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/devlink/trap.c
26282 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 <trace/events/devlink.h>
8
9
#include "devl_internal.h"
10
11
struct devlink_stats {
12
u64_stats_t rx_bytes;
13
u64_stats_t rx_packets;
14
struct u64_stats_sync syncp;
15
};
16
17
/**
18
* struct devlink_trap_policer_item - Packet trap policer attributes.
19
* @policer: Immutable packet trap policer attributes.
20
* @rate: Rate in packets / sec.
21
* @burst: Burst size in packets.
22
* @list: trap_policer_list member.
23
*
24
* Describes packet trap policer attributes. Created by devlink during trap
25
* policer registration.
26
*/
27
struct devlink_trap_policer_item {
28
const struct devlink_trap_policer *policer;
29
u64 rate;
30
u64 burst;
31
struct list_head list;
32
};
33
34
/**
35
* struct devlink_trap_group_item - Packet trap group attributes.
36
* @group: Immutable packet trap group attributes.
37
* @policer_item: Associated policer item. Can be NULL.
38
* @list: trap_group_list member.
39
* @stats: Trap group statistics.
40
*
41
* Describes packet trap group attributes. Created by devlink during trap
42
* group registration.
43
*/
44
struct devlink_trap_group_item {
45
const struct devlink_trap_group *group;
46
struct devlink_trap_policer_item *policer_item;
47
struct list_head list;
48
struct devlink_stats __percpu *stats;
49
};
50
51
/**
52
* struct devlink_trap_item - Packet trap attributes.
53
* @trap: Immutable packet trap attributes.
54
* @group_item: Associated group item.
55
* @list: trap_list member.
56
* @action: Trap action.
57
* @stats: Trap statistics.
58
* @priv: Driver private information.
59
*
60
* Describes both mutable and immutable packet trap attributes. Created by
61
* devlink during trap registration and used for all trap related operations.
62
*/
63
struct devlink_trap_item {
64
const struct devlink_trap *trap;
65
struct devlink_trap_group_item *group_item;
66
struct list_head list;
67
enum devlink_trap_action action;
68
struct devlink_stats __percpu *stats;
69
void *priv;
70
};
71
72
static struct devlink_trap_policer_item *
73
devlink_trap_policer_item_lookup(struct devlink *devlink, u32 id)
74
{
75
struct devlink_trap_policer_item *policer_item;
76
77
list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
78
if (policer_item->policer->id == id)
79
return policer_item;
80
}
81
82
return NULL;
83
}
84
85
static struct devlink_trap_item *
86
devlink_trap_item_lookup(struct devlink *devlink, const char *name)
87
{
88
struct devlink_trap_item *trap_item;
89
90
list_for_each_entry(trap_item, &devlink->trap_list, list) {
91
if (!strcmp(trap_item->trap->name, name))
92
return trap_item;
93
}
94
95
return NULL;
96
}
97
98
static struct devlink_trap_item *
99
devlink_trap_item_get_from_info(struct devlink *devlink,
100
struct genl_info *info)
101
{
102
struct nlattr *attr;
103
104
if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
105
return NULL;
106
attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
107
108
return devlink_trap_item_lookup(devlink, nla_data(attr));
109
}
110
111
static int
112
devlink_trap_action_get_from_info(struct genl_info *info,
113
enum devlink_trap_action *p_trap_action)
114
{
115
u8 val;
116
117
val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
118
switch (val) {
119
case DEVLINK_TRAP_ACTION_DROP:
120
case DEVLINK_TRAP_ACTION_TRAP:
121
case DEVLINK_TRAP_ACTION_MIRROR:
122
*p_trap_action = val;
123
break;
124
default:
125
return -EINVAL;
126
}
127
128
return 0;
129
}
130
131
static int devlink_trap_metadata_put(struct sk_buff *msg,
132
const struct devlink_trap *trap)
133
{
134
struct nlattr *attr;
135
136
attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
137
if (!attr)
138
return -EMSGSIZE;
139
140
if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
141
nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
142
goto nla_put_failure;
143
if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE) &&
144
nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE))
145
goto nla_put_failure;
146
147
nla_nest_end(msg, attr);
148
149
return 0;
150
151
nla_put_failure:
152
nla_nest_cancel(msg, attr);
153
return -EMSGSIZE;
154
}
155
156
static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
157
struct devlink_stats *stats)
158
{
159
int i;
160
161
memset(stats, 0, sizeof(*stats));
162
for_each_possible_cpu(i) {
163
struct devlink_stats *cpu_stats;
164
u64 rx_packets, rx_bytes;
165
unsigned int start;
166
167
cpu_stats = per_cpu_ptr(trap_stats, i);
168
do {
169
start = u64_stats_fetch_begin(&cpu_stats->syncp);
170
rx_packets = u64_stats_read(&cpu_stats->rx_packets);
171
rx_bytes = u64_stats_read(&cpu_stats->rx_bytes);
172
} while (u64_stats_fetch_retry(&cpu_stats->syncp, start));
173
174
u64_stats_add(&stats->rx_packets, rx_packets);
175
u64_stats_add(&stats->rx_bytes, rx_bytes);
176
}
177
}
178
179
static int
180
devlink_trap_group_stats_put(struct sk_buff *msg,
181
struct devlink_stats __percpu *trap_stats)
182
{
183
struct devlink_stats stats;
184
struct nlattr *attr;
185
186
devlink_trap_stats_read(trap_stats, &stats);
187
188
attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
189
if (!attr)
190
return -EMSGSIZE;
191
192
if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
193
u64_stats_read(&stats.rx_packets)))
194
goto nla_put_failure;
195
196
if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_BYTES,
197
u64_stats_read(&stats.rx_bytes)))
198
goto nla_put_failure;
199
200
nla_nest_end(msg, attr);
201
202
return 0;
203
204
nla_put_failure:
205
nla_nest_cancel(msg, attr);
206
return -EMSGSIZE;
207
}
208
209
static int devlink_trap_stats_put(struct sk_buff *msg, struct devlink *devlink,
210
const struct devlink_trap_item *trap_item)
211
{
212
struct devlink_stats stats;
213
struct nlattr *attr;
214
u64 drops = 0;
215
int err;
216
217
if (devlink->ops->trap_drop_counter_get) {
218
err = devlink->ops->trap_drop_counter_get(devlink,
219
trap_item->trap,
220
&drops);
221
if (err)
222
return err;
223
}
224
225
devlink_trap_stats_read(trap_item->stats, &stats);
226
227
attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
228
if (!attr)
229
return -EMSGSIZE;
230
231
if (devlink->ops->trap_drop_counter_get &&
232
devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops))
233
goto nla_put_failure;
234
235
if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
236
u64_stats_read(&stats.rx_packets)))
237
goto nla_put_failure;
238
239
if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_BYTES,
240
u64_stats_read(&stats.rx_bytes)))
241
goto nla_put_failure;
242
243
nla_nest_end(msg, attr);
244
245
return 0;
246
247
nla_put_failure:
248
nla_nest_cancel(msg, attr);
249
return -EMSGSIZE;
250
}
251
252
static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
253
const struct devlink_trap_item *trap_item,
254
enum devlink_command cmd, u32 portid, u32 seq,
255
int flags)
256
{
257
struct devlink_trap_group_item *group_item = trap_item->group_item;
258
void *hdr;
259
int err;
260
261
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
262
if (!hdr)
263
return -EMSGSIZE;
264
265
if (devlink_nl_put_handle(msg, devlink))
266
goto nla_put_failure;
267
268
if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
269
group_item->group->name))
270
goto nla_put_failure;
271
272
if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
273
goto nla_put_failure;
274
275
if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
276
goto nla_put_failure;
277
278
if (trap_item->trap->generic &&
279
nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
280
goto nla_put_failure;
281
282
if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
283
goto nla_put_failure;
284
285
err = devlink_trap_metadata_put(msg, trap_item->trap);
286
if (err)
287
goto nla_put_failure;
288
289
err = devlink_trap_stats_put(msg, devlink, trap_item);
290
if (err)
291
goto nla_put_failure;
292
293
genlmsg_end(msg, hdr);
294
295
return 0;
296
297
nla_put_failure:
298
genlmsg_cancel(msg, hdr);
299
return -EMSGSIZE;
300
}
301
302
int devlink_nl_trap_get_doit(struct sk_buff *skb, struct genl_info *info)
303
{
304
struct netlink_ext_ack *extack = info->extack;
305
struct devlink *devlink = info->user_ptr[0];
306
struct devlink_trap_item *trap_item;
307
struct sk_buff *msg;
308
int err;
309
310
if (list_empty(&devlink->trap_list))
311
return -EOPNOTSUPP;
312
313
trap_item = devlink_trap_item_get_from_info(devlink, info);
314
if (!trap_item) {
315
NL_SET_ERR_MSG(extack, "Device did not register this trap");
316
return -ENOENT;
317
}
318
319
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
320
if (!msg)
321
return -ENOMEM;
322
323
err = devlink_nl_trap_fill(msg, devlink, trap_item,
324
DEVLINK_CMD_TRAP_NEW, info->snd_portid,
325
info->snd_seq, 0);
326
if (err)
327
goto err_trap_fill;
328
329
return genlmsg_reply(msg, info);
330
331
err_trap_fill:
332
nlmsg_free(msg);
333
return err;
334
}
335
336
static int devlink_nl_trap_get_dump_one(struct sk_buff *msg,
337
struct devlink *devlink,
338
struct netlink_callback *cb, int flags)
339
{
340
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
341
struct devlink_trap_item *trap_item;
342
int idx = 0;
343
int err = 0;
344
345
list_for_each_entry(trap_item, &devlink->trap_list, list) {
346
if (idx < state->idx) {
347
idx++;
348
continue;
349
}
350
err = devlink_nl_trap_fill(msg, devlink, trap_item,
351
DEVLINK_CMD_TRAP_NEW,
352
NETLINK_CB(cb->skb).portid,
353
cb->nlh->nlmsg_seq, flags);
354
if (err) {
355
state->idx = idx;
356
break;
357
}
358
idx++;
359
}
360
361
return err;
362
}
363
364
int devlink_nl_trap_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
365
{
366
return devlink_nl_dumpit(skb, cb, devlink_nl_trap_get_dump_one);
367
}
368
369
static int __devlink_trap_action_set(struct devlink *devlink,
370
struct devlink_trap_item *trap_item,
371
enum devlink_trap_action trap_action,
372
struct netlink_ext_ack *extack)
373
{
374
int err;
375
376
if (trap_item->action != trap_action &&
377
trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
378
NL_SET_ERR_MSG(extack, "Cannot change action of non-drop traps. Skipping");
379
return 0;
380
}
381
382
err = devlink->ops->trap_action_set(devlink, trap_item->trap,
383
trap_action, extack);
384
if (err)
385
return err;
386
387
trap_item->action = trap_action;
388
389
return 0;
390
}
391
392
static int devlink_trap_action_set(struct devlink *devlink,
393
struct devlink_trap_item *trap_item,
394
struct genl_info *info)
395
{
396
enum devlink_trap_action trap_action;
397
int err;
398
399
if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
400
return 0;
401
402
err = devlink_trap_action_get_from_info(info, &trap_action);
403
if (err) {
404
NL_SET_ERR_MSG(info->extack, "Invalid trap action");
405
return -EINVAL;
406
}
407
408
return __devlink_trap_action_set(devlink, trap_item, trap_action,
409
info->extack);
410
}
411
412
int devlink_nl_trap_set_doit(struct sk_buff *skb, struct genl_info *info)
413
{
414
struct netlink_ext_ack *extack = info->extack;
415
struct devlink *devlink = info->user_ptr[0];
416
struct devlink_trap_item *trap_item;
417
418
if (list_empty(&devlink->trap_list))
419
return -EOPNOTSUPP;
420
421
trap_item = devlink_trap_item_get_from_info(devlink, info);
422
if (!trap_item) {
423
NL_SET_ERR_MSG(extack, "Device did not register this trap");
424
return -ENOENT;
425
}
426
427
return devlink_trap_action_set(devlink, trap_item, info);
428
}
429
430
static struct devlink_trap_group_item *
431
devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
432
{
433
struct devlink_trap_group_item *group_item;
434
435
list_for_each_entry(group_item, &devlink->trap_group_list, list) {
436
if (!strcmp(group_item->group->name, name))
437
return group_item;
438
}
439
440
return NULL;
441
}
442
443
static struct devlink_trap_group_item *
444
devlink_trap_group_item_lookup_by_id(struct devlink *devlink, u16 id)
445
{
446
struct devlink_trap_group_item *group_item;
447
448
list_for_each_entry(group_item, &devlink->trap_group_list, list) {
449
if (group_item->group->id == id)
450
return group_item;
451
}
452
453
return NULL;
454
}
455
456
static struct devlink_trap_group_item *
457
devlink_trap_group_item_get_from_info(struct devlink *devlink,
458
struct genl_info *info)
459
{
460
char *name;
461
462
if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
463
return NULL;
464
name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
465
466
return devlink_trap_group_item_lookup(devlink, name);
467
}
468
469
static int
470
devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
471
const struct devlink_trap_group_item *group_item,
472
enum devlink_command cmd, u32 portid, u32 seq,
473
int flags)
474
{
475
void *hdr;
476
int err;
477
478
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
479
if (!hdr)
480
return -EMSGSIZE;
481
482
if (devlink_nl_put_handle(msg, devlink))
483
goto nla_put_failure;
484
485
if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
486
group_item->group->name))
487
goto nla_put_failure;
488
489
if (group_item->group->generic &&
490
nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
491
goto nla_put_failure;
492
493
if (group_item->policer_item &&
494
nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
495
group_item->policer_item->policer->id))
496
goto nla_put_failure;
497
498
err = devlink_trap_group_stats_put(msg, group_item->stats);
499
if (err)
500
goto nla_put_failure;
501
502
genlmsg_end(msg, hdr);
503
504
return 0;
505
506
nla_put_failure:
507
genlmsg_cancel(msg, hdr);
508
return -EMSGSIZE;
509
}
510
511
int devlink_nl_trap_group_get_doit(struct sk_buff *skb, struct genl_info *info)
512
{
513
struct netlink_ext_ack *extack = info->extack;
514
struct devlink *devlink = info->user_ptr[0];
515
struct devlink_trap_group_item *group_item;
516
struct sk_buff *msg;
517
int err;
518
519
if (list_empty(&devlink->trap_group_list))
520
return -EOPNOTSUPP;
521
522
group_item = devlink_trap_group_item_get_from_info(devlink, info);
523
if (!group_item) {
524
NL_SET_ERR_MSG(extack, "Device did not register this trap group");
525
return -ENOENT;
526
}
527
528
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
529
if (!msg)
530
return -ENOMEM;
531
532
err = devlink_nl_trap_group_fill(msg, devlink, group_item,
533
DEVLINK_CMD_TRAP_GROUP_NEW,
534
info->snd_portid, info->snd_seq, 0);
535
if (err)
536
goto err_trap_group_fill;
537
538
return genlmsg_reply(msg, info);
539
540
err_trap_group_fill:
541
nlmsg_free(msg);
542
return err;
543
}
544
545
static int devlink_nl_trap_group_get_dump_one(struct sk_buff *msg,
546
struct devlink *devlink,
547
struct netlink_callback *cb,
548
int flags)
549
{
550
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
551
struct devlink_trap_group_item *group_item;
552
int idx = 0;
553
int err = 0;
554
555
list_for_each_entry(group_item, &devlink->trap_group_list, list) {
556
if (idx < state->idx) {
557
idx++;
558
continue;
559
}
560
err = devlink_nl_trap_group_fill(msg, devlink, group_item,
561
DEVLINK_CMD_TRAP_GROUP_NEW,
562
NETLINK_CB(cb->skb).portid,
563
cb->nlh->nlmsg_seq, flags);
564
if (err) {
565
state->idx = idx;
566
break;
567
}
568
idx++;
569
}
570
571
return err;
572
}
573
574
int devlink_nl_trap_group_get_dumpit(struct sk_buff *skb,
575
struct netlink_callback *cb)
576
{
577
return devlink_nl_dumpit(skb, cb, devlink_nl_trap_group_get_dump_one);
578
}
579
580
static int
581
__devlink_trap_group_action_set(struct devlink *devlink,
582
struct devlink_trap_group_item *group_item,
583
enum devlink_trap_action trap_action,
584
struct netlink_ext_ack *extack)
585
{
586
const char *group_name = group_item->group->name;
587
struct devlink_trap_item *trap_item;
588
int err;
589
590
if (devlink->ops->trap_group_action_set) {
591
err = devlink->ops->trap_group_action_set(devlink, group_item->group,
592
trap_action, extack);
593
if (err)
594
return err;
595
596
list_for_each_entry(trap_item, &devlink->trap_list, list) {
597
if (strcmp(trap_item->group_item->group->name, group_name))
598
continue;
599
if (trap_item->action != trap_action &&
600
trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP)
601
continue;
602
trap_item->action = trap_action;
603
}
604
605
return 0;
606
}
607
608
list_for_each_entry(trap_item, &devlink->trap_list, list) {
609
if (strcmp(trap_item->group_item->group->name, group_name))
610
continue;
611
err = __devlink_trap_action_set(devlink, trap_item,
612
trap_action, extack);
613
if (err)
614
return err;
615
}
616
617
return 0;
618
}
619
620
static int
621
devlink_trap_group_action_set(struct devlink *devlink,
622
struct devlink_trap_group_item *group_item,
623
struct genl_info *info, bool *p_modified)
624
{
625
enum devlink_trap_action trap_action;
626
int err;
627
628
if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
629
return 0;
630
631
err = devlink_trap_action_get_from_info(info, &trap_action);
632
if (err) {
633
NL_SET_ERR_MSG(info->extack, "Invalid trap action");
634
return -EINVAL;
635
}
636
637
err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
638
info->extack);
639
if (err)
640
return err;
641
642
*p_modified = true;
643
644
return 0;
645
}
646
647
static int devlink_trap_group_set(struct devlink *devlink,
648
struct devlink_trap_group_item *group_item,
649
struct genl_info *info)
650
{
651
struct devlink_trap_policer_item *policer_item;
652
struct netlink_ext_ack *extack = info->extack;
653
const struct devlink_trap_policer *policer;
654
struct nlattr **attrs = info->attrs;
655
u32 policer_id;
656
int err;
657
658
if (!attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
659
return 0;
660
661
if (!devlink->ops->trap_group_set)
662
return -EOPNOTSUPP;
663
664
policer_id = nla_get_u32(attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
665
policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
666
if (policer_id && !policer_item) {
667
NL_SET_ERR_MSG(extack, "Device did not register this trap policer");
668
return -ENOENT;
669
}
670
policer = policer_item ? policer_item->policer : NULL;
671
672
err = devlink->ops->trap_group_set(devlink, group_item->group, policer,
673
extack);
674
if (err)
675
return err;
676
677
group_item->policer_item = policer_item;
678
679
return 0;
680
}
681
682
int devlink_nl_trap_group_set_doit(struct sk_buff *skb, struct genl_info *info)
683
{
684
struct netlink_ext_ack *extack = info->extack;
685
struct devlink *devlink = info->user_ptr[0];
686
struct devlink_trap_group_item *group_item;
687
bool modified = false;
688
int err;
689
690
if (list_empty(&devlink->trap_group_list))
691
return -EOPNOTSUPP;
692
693
group_item = devlink_trap_group_item_get_from_info(devlink, info);
694
if (!group_item) {
695
NL_SET_ERR_MSG(extack, "Device did not register this trap group");
696
return -ENOENT;
697
}
698
699
err = devlink_trap_group_action_set(devlink, group_item, info,
700
&modified);
701
if (err)
702
return err;
703
704
err = devlink_trap_group_set(devlink, group_item, info);
705
if (err)
706
goto err_trap_group_set;
707
708
return 0;
709
710
err_trap_group_set:
711
if (modified)
712
NL_SET_ERR_MSG(extack, "Trap group set failed, but some changes were committed already");
713
return err;
714
}
715
716
static struct devlink_trap_policer_item *
717
devlink_trap_policer_item_get_from_info(struct devlink *devlink,
718
struct genl_info *info)
719
{
720
u32 id;
721
722
if (!info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
723
return NULL;
724
id = nla_get_u32(info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
725
726
return devlink_trap_policer_item_lookup(devlink, id);
727
}
728
729
static int
730
devlink_trap_policer_stats_put(struct sk_buff *msg, struct devlink *devlink,
731
const struct devlink_trap_policer *policer)
732
{
733
struct nlattr *attr;
734
u64 drops;
735
int err;
736
737
if (!devlink->ops->trap_policer_counter_get)
738
return 0;
739
740
err = devlink->ops->trap_policer_counter_get(devlink, policer, &drops);
741
if (err)
742
return err;
743
744
attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
745
if (!attr)
746
return -EMSGSIZE;
747
748
if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops))
749
goto nla_put_failure;
750
751
nla_nest_end(msg, attr);
752
753
return 0;
754
755
nla_put_failure:
756
nla_nest_cancel(msg, attr);
757
return -EMSGSIZE;
758
}
759
760
static int
761
devlink_nl_trap_policer_fill(struct sk_buff *msg, struct devlink *devlink,
762
const struct devlink_trap_policer_item *policer_item,
763
enum devlink_command cmd, u32 portid, u32 seq,
764
int flags)
765
{
766
void *hdr;
767
int err;
768
769
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
770
if (!hdr)
771
return -EMSGSIZE;
772
773
if (devlink_nl_put_handle(msg, devlink))
774
goto nla_put_failure;
775
776
if (nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
777
policer_item->policer->id))
778
goto nla_put_failure;
779
780
if (devlink_nl_put_u64(msg, DEVLINK_ATTR_TRAP_POLICER_RATE,
781
policer_item->rate))
782
goto nla_put_failure;
783
784
if (devlink_nl_put_u64(msg, DEVLINK_ATTR_TRAP_POLICER_BURST,
785
policer_item->burst))
786
goto nla_put_failure;
787
788
err = devlink_trap_policer_stats_put(msg, devlink,
789
policer_item->policer);
790
if (err)
791
goto nla_put_failure;
792
793
genlmsg_end(msg, hdr);
794
795
return 0;
796
797
nla_put_failure:
798
genlmsg_cancel(msg, hdr);
799
return -EMSGSIZE;
800
}
801
802
int devlink_nl_trap_policer_get_doit(struct sk_buff *skb,
803
struct genl_info *info)
804
{
805
struct devlink_trap_policer_item *policer_item;
806
struct netlink_ext_ack *extack = info->extack;
807
struct devlink *devlink = info->user_ptr[0];
808
struct sk_buff *msg;
809
int err;
810
811
if (list_empty(&devlink->trap_policer_list))
812
return -EOPNOTSUPP;
813
814
policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
815
if (!policer_item) {
816
NL_SET_ERR_MSG(extack, "Device did not register this trap policer");
817
return -ENOENT;
818
}
819
820
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
821
if (!msg)
822
return -ENOMEM;
823
824
err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
825
DEVLINK_CMD_TRAP_POLICER_NEW,
826
info->snd_portid, info->snd_seq, 0);
827
if (err)
828
goto err_trap_policer_fill;
829
830
return genlmsg_reply(msg, info);
831
832
err_trap_policer_fill:
833
nlmsg_free(msg);
834
return err;
835
}
836
837
static int devlink_nl_trap_policer_get_dump_one(struct sk_buff *msg,
838
struct devlink *devlink,
839
struct netlink_callback *cb,
840
int flags)
841
{
842
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
843
struct devlink_trap_policer_item *policer_item;
844
int idx = 0;
845
int err = 0;
846
847
list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
848
if (idx < state->idx) {
849
idx++;
850
continue;
851
}
852
err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
853
DEVLINK_CMD_TRAP_POLICER_NEW,
854
NETLINK_CB(cb->skb).portid,
855
cb->nlh->nlmsg_seq, flags);
856
if (err) {
857
state->idx = idx;
858
break;
859
}
860
idx++;
861
}
862
863
return err;
864
}
865
866
int devlink_nl_trap_policer_get_dumpit(struct sk_buff *skb,
867
struct netlink_callback *cb)
868
{
869
return devlink_nl_dumpit(skb, cb, devlink_nl_trap_policer_get_dump_one);
870
}
871
872
static int
873
devlink_trap_policer_set(struct devlink *devlink,
874
struct devlink_trap_policer_item *policer_item,
875
struct genl_info *info)
876
{
877
struct netlink_ext_ack *extack = info->extack;
878
struct nlattr **attrs = info->attrs;
879
u64 rate, burst;
880
int err;
881
882
rate = policer_item->rate;
883
burst = policer_item->burst;
884
885
if (attrs[DEVLINK_ATTR_TRAP_POLICER_RATE])
886
rate = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]);
887
888
if (attrs[DEVLINK_ATTR_TRAP_POLICER_BURST])
889
burst = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]);
890
891
if (rate < policer_item->policer->min_rate) {
892
NL_SET_ERR_MSG(extack, "Policer rate lower than limit");
893
return -EINVAL;
894
}
895
896
if (rate > policer_item->policer->max_rate) {
897
NL_SET_ERR_MSG(extack, "Policer rate higher than limit");
898
return -EINVAL;
899
}
900
901
if (burst < policer_item->policer->min_burst) {
902
NL_SET_ERR_MSG(extack, "Policer burst size lower than limit");
903
return -EINVAL;
904
}
905
906
if (burst > policer_item->policer->max_burst) {
907
NL_SET_ERR_MSG(extack, "Policer burst size higher than limit");
908
return -EINVAL;
909
}
910
911
err = devlink->ops->trap_policer_set(devlink, policer_item->policer,
912
rate, burst, info->extack);
913
if (err)
914
return err;
915
916
policer_item->rate = rate;
917
policer_item->burst = burst;
918
919
return 0;
920
}
921
922
int devlink_nl_trap_policer_set_doit(struct sk_buff *skb,
923
struct genl_info *info)
924
{
925
struct devlink_trap_policer_item *policer_item;
926
struct netlink_ext_ack *extack = info->extack;
927
struct devlink *devlink = info->user_ptr[0];
928
929
if (list_empty(&devlink->trap_policer_list))
930
return -EOPNOTSUPP;
931
932
if (!devlink->ops->trap_policer_set)
933
return -EOPNOTSUPP;
934
935
policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
936
if (!policer_item) {
937
NL_SET_ERR_MSG(extack, "Device did not register this trap policer");
938
return -ENOENT;
939
}
940
941
return devlink_trap_policer_set(devlink, policer_item, info);
942
}
943
944
#define DEVLINK_TRAP(_id, _type) \
945
{ \
946
.type = DEVLINK_TRAP_TYPE_##_type, \
947
.id = DEVLINK_TRAP_GENERIC_ID_##_id, \
948
.name = DEVLINK_TRAP_GENERIC_NAME_##_id, \
949
}
950
951
static const struct devlink_trap devlink_trap_generic[] = {
952
DEVLINK_TRAP(SMAC_MC, DROP),
953
DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
954
DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
955
DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
956
DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
957
DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
958
DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
959
DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
960
DEVLINK_TRAP(TAIL_DROP, DROP),
961
DEVLINK_TRAP(NON_IP_PACKET, DROP),
962
DEVLINK_TRAP(UC_DIP_MC_DMAC, DROP),
963
DEVLINK_TRAP(DIP_LB, DROP),
964
DEVLINK_TRAP(SIP_MC, DROP),
965
DEVLINK_TRAP(SIP_LB, DROP),
966
DEVLINK_TRAP(CORRUPTED_IP_HDR, DROP),
967
DEVLINK_TRAP(IPV4_SIP_BC, DROP),
968
DEVLINK_TRAP(IPV6_MC_DIP_RESERVED_SCOPE, DROP),
969
DEVLINK_TRAP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, DROP),
970
DEVLINK_TRAP(MTU_ERROR, EXCEPTION),
971
DEVLINK_TRAP(UNRESOLVED_NEIGH, EXCEPTION),
972
DEVLINK_TRAP(RPF, EXCEPTION),
973
DEVLINK_TRAP(REJECT_ROUTE, EXCEPTION),
974
DEVLINK_TRAP(IPV4_LPM_UNICAST_MISS, EXCEPTION),
975
DEVLINK_TRAP(IPV6_LPM_UNICAST_MISS, EXCEPTION),
976
DEVLINK_TRAP(NON_ROUTABLE, DROP),
977
DEVLINK_TRAP(DECAP_ERROR, EXCEPTION),
978
DEVLINK_TRAP(OVERLAY_SMAC_MC, DROP),
979
DEVLINK_TRAP(INGRESS_FLOW_ACTION_DROP, DROP),
980
DEVLINK_TRAP(EGRESS_FLOW_ACTION_DROP, DROP),
981
DEVLINK_TRAP(STP, CONTROL),
982
DEVLINK_TRAP(LACP, CONTROL),
983
DEVLINK_TRAP(LLDP, CONTROL),
984
DEVLINK_TRAP(IGMP_QUERY, CONTROL),
985
DEVLINK_TRAP(IGMP_V1_REPORT, CONTROL),
986
DEVLINK_TRAP(IGMP_V2_REPORT, CONTROL),
987
DEVLINK_TRAP(IGMP_V3_REPORT, CONTROL),
988
DEVLINK_TRAP(IGMP_V2_LEAVE, CONTROL),
989
DEVLINK_TRAP(MLD_QUERY, CONTROL),
990
DEVLINK_TRAP(MLD_V1_REPORT, CONTROL),
991
DEVLINK_TRAP(MLD_V2_REPORT, CONTROL),
992
DEVLINK_TRAP(MLD_V1_DONE, CONTROL),
993
DEVLINK_TRAP(IPV4_DHCP, CONTROL),
994
DEVLINK_TRAP(IPV6_DHCP, CONTROL),
995
DEVLINK_TRAP(ARP_REQUEST, CONTROL),
996
DEVLINK_TRAP(ARP_RESPONSE, CONTROL),
997
DEVLINK_TRAP(ARP_OVERLAY, CONTROL),
998
DEVLINK_TRAP(IPV6_NEIGH_SOLICIT, CONTROL),
999
DEVLINK_TRAP(IPV6_NEIGH_ADVERT, CONTROL),
1000
DEVLINK_TRAP(IPV4_BFD, CONTROL),
1001
DEVLINK_TRAP(IPV6_BFD, CONTROL),
1002
DEVLINK_TRAP(IPV4_OSPF, CONTROL),
1003
DEVLINK_TRAP(IPV6_OSPF, CONTROL),
1004
DEVLINK_TRAP(IPV4_BGP, CONTROL),
1005
DEVLINK_TRAP(IPV6_BGP, CONTROL),
1006
DEVLINK_TRAP(IPV4_VRRP, CONTROL),
1007
DEVLINK_TRAP(IPV6_VRRP, CONTROL),
1008
DEVLINK_TRAP(IPV4_PIM, CONTROL),
1009
DEVLINK_TRAP(IPV6_PIM, CONTROL),
1010
DEVLINK_TRAP(UC_LB, CONTROL),
1011
DEVLINK_TRAP(LOCAL_ROUTE, CONTROL),
1012
DEVLINK_TRAP(EXTERNAL_ROUTE, CONTROL),
1013
DEVLINK_TRAP(IPV6_UC_DIP_LINK_LOCAL_SCOPE, CONTROL),
1014
DEVLINK_TRAP(IPV6_DIP_ALL_NODES, CONTROL),
1015
DEVLINK_TRAP(IPV6_DIP_ALL_ROUTERS, CONTROL),
1016
DEVLINK_TRAP(IPV6_ROUTER_SOLICIT, CONTROL),
1017
DEVLINK_TRAP(IPV6_ROUTER_ADVERT, CONTROL),
1018
DEVLINK_TRAP(IPV6_REDIRECT, CONTROL),
1019
DEVLINK_TRAP(IPV4_ROUTER_ALERT, CONTROL),
1020
DEVLINK_TRAP(IPV6_ROUTER_ALERT, CONTROL),
1021
DEVLINK_TRAP(PTP_EVENT, CONTROL),
1022
DEVLINK_TRAP(PTP_GENERAL, CONTROL),
1023
DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL),
1024
DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL),
1025
DEVLINK_TRAP(EARLY_DROP, DROP),
1026
DEVLINK_TRAP(VXLAN_PARSING, DROP),
1027
DEVLINK_TRAP(LLC_SNAP_PARSING, DROP),
1028
DEVLINK_TRAP(VLAN_PARSING, DROP),
1029
DEVLINK_TRAP(PPPOE_PPP_PARSING, DROP),
1030
DEVLINK_TRAP(MPLS_PARSING, DROP),
1031
DEVLINK_TRAP(ARP_PARSING, DROP),
1032
DEVLINK_TRAP(IP_1_PARSING, DROP),
1033
DEVLINK_TRAP(IP_N_PARSING, DROP),
1034
DEVLINK_TRAP(GRE_PARSING, DROP),
1035
DEVLINK_TRAP(UDP_PARSING, DROP),
1036
DEVLINK_TRAP(TCP_PARSING, DROP),
1037
DEVLINK_TRAP(IPSEC_PARSING, DROP),
1038
DEVLINK_TRAP(SCTP_PARSING, DROP),
1039
DEVLINK_TRAP(DCCP_PARSING, DROP),
1040
DEVLINK_TRAP(GTP_PARSING, DROP),
1041
DEVLINK_TRAP(ESP_PARSING, DROP),
1042
DEVLINK_TRAP(BLACKHOLE_NEXTHOP, DROP),
1043
DEVLINK_TRAP(DMAC_FILTER, DROP),
1044
DEVLINK_TRAP(EAPOL, CONTROL),
1045
DEVLINK_TRAP(LOCKED_PORT, DROP),
1046
};
1047
1048
#define DEVLINK_TRAP_GROUP(_id) \
1049
{ \
1050
.id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \
1051
.name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \
1052
}
1053
1054
static const struct devlink_trap_group devlink_trap_group_generic[] = {
1055
DEVLINK_TRAP_GROUP(L2_DROPS),
1056
DEVLINK_TRAP_GROUP(L3_DROPS),
1057
DEVLINK_TRAP_GROUP(L3_EXCEPTIONS),
1058
DEVLINK_TRAP_GROUP(BUFFER_DROPS),
1059
DEVLINK_TRAP_GROUP(TUNNEL_DROPS),
1060
DEVLINK_TRAP_GROUP(ACL_DROPS),
1061
DEVLINK_TRAP_GROUP(STP),
1062
DEVLINK_TRAP_GROUP(LACP),
1063
DEVLINK_TRAP_GROUP(LLDP),
1064
DEVLINK_TRAP_GROUP(MC_SNOOPING),
1065
DEVLINK_TRAP_GROUP(DHCP),
1066
DEVLINK_TRAP_GROUP(NEIGH_DISCOVERY),
1067
DEVLINK_TRAP_GROUP(BFD),
1068
DEVLINK_TRAP_GROUP(OSPF),
1069
DEVLINK_TRAP_GROUP(BGP),
1070
DEVLINK_TRAP_GROUP(VRRP),
1071
DEVLINK_TRAP_GROUP(PIM),
1072
DEVLINK_TRAP_GROUP(UC_LB),
1073
DEVLINK_TRAP_GROUP(LOCAL_DELIVERY),
1074
DEVLINK_TRAP_GROUP(EXTERNAL_DELIVERY),
1075
DEVLINK_TRAP_GROUP(IPV6),
1076
DEVLINK_TRAP_GROUP(PTP_EVENT),
1077
DEVLINK_TRAP_GROUP(PTP_GENERAL),
1078
DEVLINK_TRAP_GROUP(ACL_SAMPLE),
1079
DEVLINK_TRAP_GROUP(ACL_TRAP),
1080
DEVLINK_TRAP_GROUP(PARSER_ERROR_DROPS),
1081
DEVLINK_TRAP_GROUP(EAPOL),
1082
};
1083
1084
static int devlink_trap_generic_verify(const struct devlink_trap *trap)
1085
{
1086
if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
1087
return -EINVAL;
1088
1089
if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
1090
return -EINVAL;
1091
1092
if (trap->type != devlink_trap_generic[trap->id].type)
1093
return -EINVAL;
1094
1095
return 0;
1096
}
1097
1098
static int devlink_trap_driver_verify(const struct devlink_trap *trap)
1099
{
1100
int i;
1101
1102
if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
1103
return -EINVAL;
1104
1105
for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
1106
if (!strcmp(trap->name, devlink_trap_generic[i].name))
1107
return -EEXIST;
1108
}
1109
1110
return 0;
1111
}
1112
1113
static int devlink_trap_verify(const struct devlink_trap *trap)
1114
{
1115
if (!trap || !trap->name)
1116
return -EINVAL;
1117
1118
if (trap->generic)
1119
return devlink_trap_generic_verify(trap);
1120
else
1121
return devlink_trap_driver_verify(trap);
1122
}
1123
1124
static int
1125
devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
1126
{
1127
if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
1128
return -EINVAL;
1129
1130
if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
1131
return -EINVAL;
1132
1133
return 0;
1134
}
1135
1136
static int
1137
devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
1138
{
1139
int i;
1140
1141
if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
1142
return -EINVAL;
1143
1144
for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
1145
if (!strcmp(group->name, devlink_trap_group_generic[i].name))
1146
return -EEXIST;
1147
}
1148
1149
return 0;
1150
}
1151
1152
static int devlink_trap_group_verify(const struct devlink_trap_group *group)
1153
{
1154
if (group->generic)
1155
return devlink_trap_group_generic_verify(group);
1156
else
1157
return devlink_trap_group_driver_verify(group);
1158
}
1159
1160
static void
1161
devlink_trap_group_notify(struct devlink *devlink,
1162
const struct devlink_trap_group_item *group_item,
1163
enum devlink_command cmd)
1164
{
1165
struct sk_buff *msg;
1166
int err;
1167
1168
WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
1169
cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
1170
1171
if (!devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
1172
return;
1173
1174
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1175
if (!msg)
1176
return;
1177
1178
err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
1179
0);
1180
if (err) {
1181
nlmsg_free(msg);
1182
return;
1183
}
1184
1185
devlink_nl_notify_send(devlink, msg);
1186
}
1187
1188
void devlink_trap_groups_notify_register(struct devlink *devlink)
1189
{
1190
struct devlink_trap_group_item *group_item;
1191
1192
list_for_each_entry(group_item, &devlink->trap_group_list, list)
1193
devlink_trap_group_notify(devlink, group_item,
1194
DEVLINK_CMD_TRAP_GROUP_NEW);
1195
}
1196
1197
void devlink_trap_groups_notify_unregister(struct devlink *devlink)
1198
{
1199
struct devlink_trap_group_item *group_item;
1200
1201
list_for_each_entry_reverse(group_item, &devlink->trap_group_list, list)
1202
devlink_trap_group_notify(devlink, group_item,
1203
DEVLINK_CMD_TRAP_GROUP_DEL);
1204
}
1205
1206
static int
1207
devlink_trap_item_group_link(struct devlink *devlink,
1208
struct devlink_trap_item *trap_item)
1209
{
1210
u16 group_id = trap_item->trap->init_group_id;
1211
struct devlink_trap_group_item *group_item;
1212
1213
group_item = devlink_trap_group_item_lookup_by_id(devlink, group_id);
1214
if (WARN_ON_ONCE(!group_item))
1215
return -EINVAL;
1216
1217
trap_item->group_item = group_item;
1218
1219
return 0;
1220
}
1221
1222
static void devlink_trap_notify(struct devlink *devlink,
1223
const struct devlink_trap_item *trap_item,
1224
enum devlink_command cmd)
1225
{
1226
struct sk_buff *msg;
1227
int err;
1228
1229
WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
1230
cmd != DEVLINK_CMD_TRAP_DEL);
1231
1232
if (!devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
1233
return;
1234
1235
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1236
if (!msg)
1237
return;
1238
1239
err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
1240
if (err) {
1241
nlmsg_free(msg);
1242
return;
1243
}
1244
1245
devlink_nl_notify_send(devlink, msg);
1246
}
1247
1248
void devlink_traps_notify_register(struct devlink *devlink)
1249
{
1250
struct devlink_trap_item *trap_item;
1251
1252
list_for_each_entry(trap_item, &devlink->trap_list, list)
1253
devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
1254
}
1255
1256
void devlink_traps_notify_unregister(struct devlink *devlink)
1257
{
1258
struct devlink_trap_item *trap_item;
1259
1260
list_for_each_entry_reverse(trap_item, &devlink->trap_list, list)
1261
devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
1262
}
1263
1264
static int
1265
devlink_trap_register(struct devlink *devlink,
1266
const struct devlink_trap *trap, void *priv)
1267
{
1268
struct devlink_trap_item *trap_item;
1269
int err;
1270
1271
if (devlink_trap_item_lookup(devlink, trap->name))
1272
return -EEXIST;
1273
1274
trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
1275
if (!trap_item)
1276
return -ENOMEM;
1277
1278
trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
1279
if (!trap_item->stats) {
1280
err = -ENOMEM;
1281
goto err_stats_alloc;
1282
}
1283
1284
trap_item->trap = trap;
1285
trap_item->action = trap->init_action;
1286
trap_item->priv = priv;
1287
1288
err = devlink_trap_item_group_link(devlink, trap_item);
1289
if (err)
1290
goto err_group_link;
1291
1292
err = devlink->ops->trap_init(devlink, trap, trap_item);
1293
if (err)
1294
goto err_trap_init;
1295
1296
list_add_tail(&trap_item->list, &devlink->trap_list);
1297
devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
1298
1299
return 0;
1300
1301
err_trap_init:
1302
err_group_link:
1303
free_percpu(trap_item->stats);
1304
err_stats_alloc:
1305
kfree(trap_item);
1306
return err;
1307
}
1308
1309
static void devlink_trap_unregister(struct devlink *devlink,
1310
const struct devlink_trap *trap)
1311
{
1312
struct devlink_trap_item *trap_item;
1313
1314
trap_item = devlink_trap_item_lookup(devlink, trap->name);
1315
if (WARN_ON_ONCE(!trap_item))
1316
return;
1317
1318
devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
1319
list_del(&trap_item->list);
1320
if (devlink->ops->trap_fini)
1321
devlink->ops->trap_fini(devlink, trap, trap_item);
1322
free_percpu(trap_item->stats);
1323
kfree(trap_item);
1324
}
1325
1326
static void devlink_trap_disable(struct devlink *devlink,
1327
const struct devlink_trap *trap)
1328
{
1329
struct devlink_trap_item *trap_item;
1330
1331
trap_item = devlink_trap_item_lookup(devlink, trap->name);
1332
if (WARN_ON_ONCE(!trap_item))
1333
return;
1334
1335
devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP,
1336
NULL);
1337
trap_item->action = DEVLINK_TRAP_ACTION_DROP;
1338
}
1339
1340
/**
1341
* devl_traps_register - Register packet traps with devlink.
1342
* @devlink: devlink.
1343
* @traps: Packet traps.
1344
* @traps_count: Count of provided packet traps.
1345
* @priv: Driver private information.
1346
*
1347
* Return: Non-zero value on failure.
1348
*/
1349
int devl_traps_register(struct devlink *devlink,
1350
const struct devlink_trap *traps,
1351
size_t traps_count, void *priv)
1352
{
1353
int i, err;
1354
1355
if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
1356
return -EINVAL;
1357
1358
devl_assert_locked(devlink);
1359
for (i = 0; i < traps_count; i++) {
1360
const struct devlink_trap *trap = &traps[i];
1361
1362
err = devlink_trap_verify(trap);
1363
if (err)
1364
goto err_trap_verify;
1365
1366
err = devlink_trap_register(devlink, trap, priv);
1367
if (err)
1368
goto err_trap_register;
1369
}
1370
1371
return 0;
1372
1373
err_trap_register:
1374
err_trap_verify:
1375
for (i--; i >= 0; i--)
1376
devlink_trap_unregister(devlink, &traps[i]);
1377
return err;
1378
}
1379
EXPORT_SYMBOL_GPL(devl_traps_register);
1380
1381
/**
1382
* devlink_traps_register - Register packet traps with devlink.
1383
* @devlink: devlink.
1384
* @traps: Packet traps.
1385
* @traps_count: Count of provided packet traps.
1386
* @priv: Driver private information.
1387
*
1388
* Context: Takes and release devlink->lock <mutex>.
1389
*
1390
* Return: Non-zero value on failure.
1391
*/
1392
int devlink_traps_register(struct devlink *devlink,
1393
const struct devlink_trap *traps,
1394
size_t traps_count, void *priv)
1395
{
1396
int err;
1397
1398
devl_lock(devlink);
1399
err = devl_traps_register(devlink, traps, traps_count, priv);
1400
devl_unlock(devlink);
1401
return err;
1402
}
1403
EXPORT_SYMBOL_GPL(devlink_traps_register);
1404
1405
/**
1406
* devl_traps_unregister - Unregister packet traps from devlink.
1407
* @devlink: devlink.
1408
* @traps: Packet traps.
1409
* @traps_count: Count of provided packet traps.
1410
*/
1411
void devl_traps_unregister(struct devlink *devlink,
1412
const struct devlink_trap *traps,
1413
size_t traps_count)
1414
{
1415
int i;
1416
1417
devl_assert_locked(devlink);
1418
/* Make sure we do not have any packets in-flight while unregistering
1419
* traps by disabling all of them and waiting for a grace period.
1420
*/
1421
for (i = traps_count - 1; i >= 0; i--)
1422
devlink_trap_disable(devlink, &traps[i]);
1423
synchronize_rcu();
1424
for (i = traps_count - 1; i >= 0; i--)
1425
devlink_trap_unregister(devlink, &traps[i]);
1426
}
1427
EXPORT_SYMBOL_GPL(devl_traps_unregister);
1428
1429
/**
1430
* devlink_traps_unregister - Unregister packet traps from devlink.
1431
* @devlink: devlink.
1432
* @traps: Packet traps.
1433
* @traps_count: Count of provided packet traps.
1434
*
1435
* Context: Takes and release devlink->lock <mutex>.
1436
*/
1437
void devlink_traps_unregister(struct devlink *devlink,
1438
const struct devlink_trap *traps,
1439
size_t traps_count)
1440
{
1441
devl_lock(devlink);
1442
devl_traps_unregister(devlink, traps, traps_count);
1443
devl_unlock(devlink);
1444
}
1445
EXPORT_SYMBOL_GPL(devlink_traps_unregister);
1446
1447
static void
1448
devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
1449
size_t skb_len)
1450
{
1451
struct devlink_stats *stats;
1452
1453
stats = this_cpu_ptr(trap_stats);
1454
u64_stats_update_begin(&stats->syncp);
1455
u64_stats_add(&stats->rx_bytes, skb_len);
1456
u64_stats_inc(&stats->rx_packets);
1457
u64_stats_update_end(&stats->syncp);
1458
}
1459
1460
static void
1461
devlink_trap_report_metadata_set(struct devlink_trap_metadata *metadata,
1462
const struct devlink_trap_item *trap_item,
1463
struct devlink_port *in_devlink_port,
1464
const struct flow_action_cookie *fa_cookie)
1465
{
1466
metadata->trap_name = trap_item->trap->name;
1467
metadata->trap_group_name = trap_item->group_item->group->name;
1468
metadata->fa_cookie = fa_cookie;
1469
metadata->trap_type = trap_item->trap->type;
1470
1471
spin_lock(&in_devlink_port->type_lock);
1472
if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
1473
metadata->input_dev = in_devlink_port->type_eth.netdev;
1474
spin_unlock(&in_devlink_port->type_lock);
1475
}
1476
1477
/**
1478
* devlink_trap_report - Report trapped packet to drop monitor.
1479
* @devlink: devlink.
1480
* @skb: Trapped packet.
1481
* @trap_ctx: Trap context.
1482
* @in_devlink_port: Input devlink port.
1483
* @fa_cookie: Flow action cookie. Could be NULL.
1484
*/
1485
void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
1486
void *trap_ctx, struct devlink_port *in_devlink_port,
1487
const struct flow_action_cookie *fa_cookie)
1488
1489
{
1490
struct devlink_trap_item *trap_item = trap_ctx;
1491
1492
devlink_trap_stats_update(trap_item->stats, skb->len);
1493
devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
1494
1495
if (tracepoint_enabled(devlink_trap_report)) {
1496
struct devlink_trap_metadata metadata = {};
1497
1498
devlink_trap_report_metadata_set(&metadata, trap_item,
1499
in_devlink_port, fa_cookie);
1500
trace_devlink_trap_report(devlink, skb, &metadata);
1501
}
1502
}
1503
EXPORT_SYMBOL_GPL(devlink_trap_report);
1504
1505
/**
1506
* devlink_trap_ctx_priv - Trap context to driver private information.
1507
* @trap_ctx: Trap context.
1508
*
1509
* Return: Driver private information passed during registration.
1510
*/
1511
void *devlink_trap_ctx_priv(void *trap_ctx)
1512
{
1513
struct devlink_trap_item *trap_item = trap_ctx;
1514
1515
return trap_item->priv;
1516
}
1517
EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
1518
1519
static int
1520
devlink_trap_group_item_policer_link(struct devlink *devlink,
1521
struct devlink_trap_group_item *group_item)
1522
{
1523
u32 policer_id = group_item->group->init_policer_id;
1524
struct devlink_trap_policer_item *policer_item;
1525
1526
if (policer_id == 0)
1527
return 0;
1528
1529
policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
1530
if (WARN_ON_ONCE(!policer_item))
1531
return -EINVAL;
1532
1533
group_item->policer_item = policer_item;
1534
1535
return 0;
1536
}
1537
1538
static int
1539
devlink_trap_group_register(struct devlink *devlink,
1540
const struct devlink_trap_group *group)
1541
{
1542
struct devlink_trap_group_item *group_item;
1543
int err;
1544
1545
if (devlink_trap_group_item_lookup(devlink, group->name))
1546
return -EEXIST;
1547
1548
group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
1549
if (!group_item)
1550
return -ENOMEM;
1551
1552
group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
1553
if (!group_item->stats) {
1554
err = -ENOMEM;
1555
goto err_stats_alloc;
1556
}
1557
1558
group_item->group = group;
1559
1560
err = devlink_trap_group_item_policer_link(devlink, group_item);
1561
if (err)
1562
goto err_policer_link;
1563
1564
if (devlink->ops->trap_group_init) {
1565
err = devlink->ops->trap_group_init(devlink, group);
1566
if (err)
1567
goto err_group_init;
1568
}
1569
1570
list_add_tail(&group_item->list, &devlink->trap_group_list);
1571
devlink_trap_group_notify(devlink, group_item,
1572
DEVLINK_CMD_TRAP_GROUP_NEW);
1573
1574
return 0;
1575
1576
err_group_init:
1577
err_policer_link:
1578
free_percpu(group_item->stats);
1579
err_stats_alloc:
1580
kfree(group_item);
1581
return err;
1582
}
1583
1584
static void
1585
devlink_trap_group_unregister(struct devlink *devlink,
1586
const struct devlink_trap_group *group)
1587
{
1588
struct devlink_trap_group_item *group_item;
1589
1590
group_item = devlink_trap_group_item_lookup(devlink, group->name);
1591
if (WARN_ON_ONCE(!group_item))
1592
return;
1593
1594
devlink_trap_group_notify(devlink, group_item,
1595
DEVLINK_CMD_TRAP_GROUP_DEL);
1596
list_del(&group_item->list);
1597
free_percpu(group_item->stats);
1598
kfree(group_item);
1599
}
1600
1601
/**
1602
* devl_trap_groups_register - Register packet trap groups with devlink.
1603
* @devlink: devlink.
1604
* @groups: Packet trap groups.
1605
* @groups_count: Count of provided packet trap groups.
1606
*
1607
* Return: Non-zero value on failure.
1608
*/
1609
int devl_trap_groups_register(struct devlink *devlink,
1610
const struct devlink_trap_group *groups,
1611
size_t groups_count)
1612
{
1613
int i, err;
1614
1615
devl_assert_locked(devlink);
1616
for (i = 0; i < groups_count; i++) {
1617
const struct devlink_trap_group *group = &groups[i];
1618
1619
err = devlink_trap_group_verify(group);
1620
if (err)
1621
goto err_trap_group_verify;
1622
1623
err = devlink_trap_group_register(devlink, group);
1624
if (err)
1625
goto err_trap_group_register;
1626
}
1627
1628
return 0;
1629
1630
err_trap_group_register:
1631
err_trap_group_verify:
1632
for (i--; i >= 0; i--)
1633
devlink_trap_group_unregister(devlink, &groups[i]);
1634
return err;
1635
}
1636
EXPORT_SYMBOL_GPL(devl_trap_groups_register);
1637
1638
/**
1639
* devlink_trap_groups_register - Register packet trap groups with devlink.
1640
* @devlink: devlink.
1641
* @groups: Packet trap groups.
1642
* @groups_count: Count of provided packet trap groups.
1643
*
1644
* Context: Takes and release devlink->lock <mutex>.
1645
*
1646
* Return: Non-zero value on failure.
1647
*/
1648
int devlink_trap_groups_register(struct devlink *devlink,
1649
const struct devlink_trap_group *groups,
1650
size_t groups_count)
1651
{
1652
int err;
1653
1654
devl_lock(devlink);
1655
err = devl_trap_groups_register(devlink, groups, groups_count);
1656
devl_unlock(devlink);
1657
return err;
1658
}
1659
EXPORT_SYMBOL_GPL(devlink_trap_groups_register);
1660
1661
/**
1662
* devl_trap_groups_unregister - Unregister packet trap groups from devlink.
1663
* @devlink: devlink.
1664
* @groups: Packet trap groups.
1665
* @groups_count: Count of provided packet trap groups.
1666
*/
1667
void devl_trap_groups_unregister(struct devlink *devlink,
1668
const struct devlink_trap_group *groups,
1669
size_t groups_count)
1670
{
1671
int i;
1672
1673
devl_assert_locked(devlink);
1674
for (i = groups_count - 1; i >= 0; i--)
1675
devlink_trap_group_unregister(devlink, &groups[i]);
1676
}
1677
EXPORT_SYMBOL_GPL(devl_trap_groups_unregister);
1678
1679
/**
1680
* devlink_trap_groups_unregister - Unregister packet trap groups from devlink.
1681
* @devlink: devlink.
1682
* @groups: Packet trap groups.
1683
* @groups_count: Count of provided packet trap groups.
1684
*
1685
* Context: Takes and release devlink->lock <mutex>.
1686
*/
1687
void devlink_trap_groups_unregister(struct devlink *devlink,
1688
const struct devlink_trap_group *groups,
1689
size_t groups_count)
1690
{
1691
devl_lock(devlink);
1692
devl_trap_groups_unregister(devlink, groups, groups_count);
1693
devl_unlock(devlink);
1694
}
1695
EXPORT_SYMBOL_GPL(devlink_trap_groups_unregister);
1696
1697
static void
1698
devlink_trap_policer_notify(struct devlink *devlink,
1699
const struct devlink_trap_policer_item *policer_item,
1700
enum devlink_command cmd)
1701
{
1702
struct sk_buff *msg;
1703
int err;
1704
1705
WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_POLICER_NEW &&
1706
cmd != DEVLINK_CMD_TRAP_POLICER_DEL);
1707
1708
if (!devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
1709
return;
1710
1711
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1712
if (!msg)
1713
return;
1714
1715
err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, cmd, 0,
1716
0, 0);
1717
if (err) {
1718
nlmsg_free(msg);
1719
return;
1720
}
1721
1722
devlink_nl_notify_send(devlink, msg);
1723
}
1724
1725
void devlink_trap_policers_notify_register(struct devlink *devlink)
1726
{
1727
struct devlink_trap_policer_item *policer_item;
1728
1729
list_for_each_entry(policer_item, &devlink->trap_policer_list, list)
1730
devlink_trap_policer_notify(devlink, policer_item,
1731
DEVLINK_CMD_TRAP_POLICER_NEW);
1732
}
1733
1734
void devlink_trap_policers_notify_unregister(struct devlink *devlink)
1735
{
1736
struct devlink_trap_policer_item *policer_item;
1737
1738
list_for_each_entry_reverse(policer_item, &devlink->trap_policer_list,
1739
list)
1740
devlink_trap_policer_notify(devlink, policer_item,
1741
DEVLINK_CMD_TRAP_POLICER_DEL);
1742
}
1743
1744
static int
1745
devlink_trap_policer_register(struct devlink *devlink,
1746
const struct devlink_trap_policer *policer)
1747
{
1748
struct devlink_trap_policer_item *policer_item;
1749
int err;
1750
1751
if (devlink_trap_policer_item_lookup(devlink, policer->id))
1752
return -EEXIST;
1753
1754
policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL);
1755
if (!policer_item)
1756
return -ENOMEM;
1757
1758
policer_item->policer = policer;
1759
policer_item->rate = policer->init_rate;
1760
policer_item->burst = policer->init_burst;
1761
1762
if (devlink->ops->trap_policer_init) {
1763
err = devlink->ops->trap_policer_init(devlink, policer);
1764
if (err)
1765
goto err_policer_init;
1766
}
1767
1768
list_add_tail(&policer_item->list, &devlink->trap_policer_list);
1769
devlink_trap_policer_notify(devlink, policer_item,
1770
DEVLINK_CMD_TRAP_POLICER_NEW);
1771
1772
return 0;
1773
1774
err_policer_init:
1775
kfree(policer_item);
1776
return err;
1777
}
1778
1779
static void
1780
devlink_trap_policer_unregister(struct devlink *devlink,
1781
const struct devlink_trap_policer *policer)
1782
{
1783
struct devlink_trap_policer_item *policer_item;
1784
1785
policer_item = devlink_trap_policer_item_lookup(devlink, policer->id);
1786
if (WARN_ON_ONCE(!policer_item))
1787
return;
1788
1789
devlink_trap_policer_notify(devlink, policer_item,
1790
DEVLINK_CMD_TRAP_POLICER_DEL);
1791
list_del(&policer_item->list);
1792
if (devlink->ops->trap_policer_fini)
1793
devlink->ops->trap_policer_fini(devlink, policer);
1794
kfree(policer_item);
1795
}
1796
1797
/**
1798
* devl_trap_policers_register - Register packet trap policers with devlink.
1799
* @devlink: devlink.
1800
* @policers: Packet trap policers.
1801
* @policers_count: Count of provided packet trap policers.
1802
*
1803
* Return: Non-zero value on failure.
1804
*/
1805
int
1806
devl_trap_policers_register(struct devlink *devlink,
1807
const struct devlink_trap_policer *policers,
1808
size_t policers_count)
1809
{
1810
int i, err;
1811
1812
devl_assert_locked(devlink);
1813
for (i = 0; i < policers_count; i++) {
1814
const struct devlink_trap_policer *policer = &policers[i];
1815
1816
if (WARN_ON(policer->id == 0 ||
1817
policer->max_rate < policer->min_rate ||
1818
policer->max_burst < policer->min_burst)) {
1819
err = -EINVAL;
1820
goto err_trap_policer_verify;
1821
}
1822
1823
err = devlink_trap_policer_register(devlink, policer);
1824
if (err)
1825
goto err_trap_policer_register;
1826
}
1827
return 0;
1828
1829
err_trap_policer_register:
1830
err_trap_policer_verify:
1831
for (i--; i >= 0; i--)
1832
devlink_trap_policer_unregister(devlink, &policers[i]);
1833
return err;
1834
}
1835
EXPORT_SYMBOL_GPL(devl_trap_policers_register);
1836
1837
/**
1838
* devl_trap_policers_unregister - Unregister packet trap policers from devlink.
1839
* @devlink: devlink.
1840
* @policers: Packet trap policers.
1841
* @policers_count: Count of provided packet trap policers.
1842
*/
1843
void
1844
devl_trap_policers_unregister(struct devlink *devlink,
1845
const struct devlink_trap_policer *policers,
1846
size_t policers_count)
1847
{
1848
int i;
1849
1850
devl_assert_locked(devlink);
1851
for (i = policers_count - 1; i >= 0; i--)
1852
devlink_trap_policer_unregister(devlink, &policers[i]);
1853
}
1854
EXPORT_SYMBOL_GPL(devl_trap_policers_unregister);
1855
1856