Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/devlink/health.c
29267 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 <net/genetlink.h>
8
#include <net/sock.h>
9
#include <trace/events/devlink.h>
10
#include "devl_internal.h"
11
12
struct devlink_fmsg_item {
13
struct list_head list;
14
int attrtype;
15
u8 nla_type;
16
u16 len;
17
int value[];
18
};
19
20
struct devlink_fmsg {
21
struct list_head item_list;
22
int err; /* first error encountered on some devlink_fmsg_XXX() call */
23
bool putting_binary; /* This flag forces enclosing of binary data
24
* in an array brackets. It forces using
25
* of designated API:
26
* devlink_fmsg_binary_pair_nest_start()
27
* devlink_fmsg_binary_pair_nest_end()
28
*/
29
};
30
31
static struct devlink_fmsg *devlink_fmsg_alloc(void)
32
{
33
struct devlink_fmsg *fmsg;
34
35
fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
36
if (!fmsg)
37
return NULL;
38
39
INIT_LIST_HEAD(&fmsg->item_list);
40
41
return fmsg;
42
}
43
44
static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
45
{
46
struct devlink_fmsg_item *item, *tmp;
47
48
list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
49
list_del(&item->list);
50
kfree(item);
51
}
52
kfree(fmsg);
53
}
54
55
struct devlink_health_reporter {
56
struct list_head list;
57
void *priv;
58
const struct devlink_health_reporter_ops *ops;
59
struct devlink *devlink;
60
struct devlink_port *devlink_port;
61
struct devlink_fmsg *dump_fmsg;
62
u64 graceful_period;
63
u64 burst_period;
64
bool auto_recover;
65
bool auto_dump;
66
u8 health_state;
67
u64 dump_ts;
68
u64 dump_real_ts;
69
u64 error_count;
70
u64 recovery_count;
71
u64 last_recovery_ts;
72
};
73
74
void *
75
devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
76
{
77
return reporter->priv;
78
}
79
EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
80
81
static struct devlink_health_reporter *
82
__devlink_health_reporter_find_by_name(struct list_head *reporter_list,
83
const char *reporter_name)
84
{
85
struct devlink_health_reporter *reporter;
86
87
list_for_each_entry(reporter, reporter_list, list)
88
if (!strcmp(reporter->ops->name, reporter_name))
89
return reporter;
90
return NULL;
91
}
92
93
static struct devlink_health_reporter *
94
devlink_health_reporter_find_by_name(struct devlink *devlink,
95
const char *reporter_name)
96
{
97
return __devlink_health_reporter_find_by_name(&devlink->reporter_list,
98
reporter_name);
99
}
100
101
static struct devlink_health_reporter *
102
devlink_port_health_reporter_find_by_name(struct devlink_port *devlink_port,
103
const char *reporter_name)
104
{
105
return __devlink_health_reporter_find_by_name(&devlink_port->reporter_list,
106
reporter_name);
107
}
108
109
static struct devlink_health_reporter *
110
__devlink_health_reporter_create(struct devlink *devlink,
111
const struct devlink_health_reporter_ops *ops,
112
void *priv)
113
{
114
struct devlink_health_reporter *reporter;
115
116
if (WARN_ON(ops->default_graceful_period && !ops->recover))
117
return ERR_PTR(-EINVAL);
118
119
if (WARN_ON(ops->default_burst_period && !ops->default_graceful_period))
120
return ERR_PTR(-EINVAL);
121
122
reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
123
if (!reporter)
124
return ERR_PTR(-ENOMEM);
125
126
reporter->priv = priv;
127
reporter->ops = ops;
128
reporter->devlink = devlink;
129
reporter->graceful_period = ops->default_graceful_period;
130
reporter->burst_period = ops->default_burst_period;
131
reporter->auto_recover = !!ops->recover;
132
reporter->auto_dump = !!ops->dump;
133
return reporter;
134
}
135
136
/**
137
* devl_port_health_reporter_create() - create devlink health reporter for
138
* specified port instance
139
*
140
* @port: devlink_port to which health reports will relate
141
* @ops: devlink health reporter ops
142
* @priv: driver priv pointer
143
*/
144
struct devlink_health_reporter *
145
devl_port_health_reporter_create(struct devlink_port *port,
146
const struct devlink_health_reporter_ops *ops,
147
void *priv)
148
{
149
struct devlink_health_reporter *reporter;
150
151
devl_assert_locked(port->devlink);
152
153
if (__devlink_health_reporter_find_by_name(&port->reporter_list,
154
ops->name))
155
return ERR_PTR(-EEXIST);
156
157
reporter = __devlink_health_reporter_create(port->devlink, ops, priv);
158
if (IS_ERR(reporter))
159
return reporter;
160
161
reporter->devlink_port = port;
162
list_add_tail(&reporter->list, &port->reporter_list);
163
return reporter;
164
}
165
EXPORT_SYMBOL_GPL(devl_port_health_reporter_create);
166
167
struct devlink_health_reporter *
168
devlink_port_health_reporter_create(struct devlink_port *port,
169
const struct devlink_health_reporter_ops *ops,
170
void *priv)
171
{
172
struct devlink_health_reporter *reporter;
173
struct devlink *devlink = port->devlink;
174
175
devl_lock(devlink);
176
reporter = devl_port_health_reporter_create(port, ops, priv);
177
devl_unlock(devlink);
178
return reporter;
179
}
180
EXPORT_SYMBOL_GPL(devlink_port_health_reporter_create);
181
182
/**
183
* devl_health_reporter_create - create devlink health reporter
184
*
185
* @devlink: devlink instance which the health reports will relate
186
* @ops: devlink health reporter ops
187
* @priv: driver priv pointer
188
*/
189
struct devlink_health_reporter *
190
devl_health_reporter_create(struct devlink *devlink,
191
const struct devlink_health_reporter_ops *ops,
192
void *priv)
193
{
194
struct devlink_health_reporter *reporter;
195
196
devl_assert_locked(devlink);
197
198
if (devlink_health_reporter_find_by_name(devlink, ops->name))
199
return ERR_PTR(-EEXIST);
200
201
reporter = __devlink_health_reporter_create(devlink, ops, priv);
202
if (IS_ERR(reporter))
203
return reporter;
204
205
list_add_tail(&reporter->list, &devlink->reporter_list);
206
return reporter;
207
}
208
EXPORT_SYMBOL_GPL(devl_health_reporter_create);
209
210
struct devlink_health_reporter *
211
devlink_health_reporter_create(struct devlink *devlink,
212
const struct devlink_health_reporter_ops *ops,
213
void *priv)
214
{
215
struct devlink_health_reporter *reporter;
216
217
devl_lock(devlink);
218
reporter = devl_health_reporter_create(devlink, ops, priv);
219
devl_unlock(devlink);
220
return reporter;
221
}
222
EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
223
224
static void
225
devlink_health_reporter_free(struct devlink_health_reporter *reporter)
226
{
227
if (reporter->dump_fmsg)
228
devlink_fmsg_free(reporter->dump_fmsg);
229
kfree(reporter);
230
}
231
232
/**
233
* devl_health_reporter_destroy() - destroy devlink health reporter
234
*
235
* @reporter: devlink health reporter to destroy
236
*/
237
void
238
devl_health_reporter_destroy(struct devlink_health_reporter *reporter)
239
{
240
devl_assert_locked(reporter->devlink);
241
242
list_del(&reporter->list);
243
devlink_health_reporter_free(reporter);
244
}
245
EXPORT_SYMBOL_GPL(devl_health_reporter_destroy);
246
247
void
248
devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
249
{
250
struct devlink *devlink = reporter->devlink;
251
252
devl_lock(devlink);
253
devl_health_reporter_destroy(reporter);
254
devl_unlock(devlink);
255
}
256
EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
257
258
static int
259
devlink_nl_health_reporter_fill(struct sk_buff *msg,
260
struct devlink_health_reporter *reporter,
261
enum devlink_command cmd, u32 portid,
262
u32 seq, int flags)
263
{
264
struct devlink *devlink = reporter->devlink;
265
struct nlattr *reporter_attr;
266
void *hdr;
267
268
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
269
if (!hdr)
270
return -EMSGSIZE;
271
272
if (devlink_nl_put_handle(msg, devlink))
273
goto genlmsg_cancel;
274
275
if (reporter->devlink_port) {
276
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, reporter->devlink_port->index))
277
goto genlmsg_cancel;
278
}
279
reporter_attr = nla_nest_start_noflag(msg,
280
DEVLINK_ATTR_HEALTH_REPORTER);
281
if (!reporter_attr)
282
goto genlmsg_cancel;
283
if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
284
reporter->ops->name))
285
goto reporter_nest_cancel;
286
if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
287
reporter->health_state))
288
goto reporter_nest_cancel;
289
if (devlink_nl_put_u64(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
290
reporter->error_count))
291
goto reporter_nest_cancel;
292
if (devlink_nl_put_u64(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
293
reporter->recovery_count))
294
goto reporter_nest_cancel;
295
if (reporter->ops->recover &&
296
devlink_nl_put_u64(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
297
reporter->graceful_period))
298
goto reporter_nest_cancel;
299
if (reporter->ops->recover &&
300
devlink_nl_put_u64(msg, DEVLINK_ATTR_HEALTH_REPORTER_BURST_PERIOD,
301
reporter->burst_period))
302
goto reporter_nest_cancel;
303
if (reporter->ops->recover &&
304
nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
305
reporter->auto_recover))
306
goto reporter_nest_cancel;
307
if (reporter->dump_fmsg &&
308
devlink_nl_put_u64(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
309
jiffies_to_msecs(reporter->dump_ts)))
310
goto reporter_nest_cancel;
311
if (reporter->dump_fmsg &&
312
devlink_nl_put_u64(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS,
313
reporter->dump_real_ts))
314
goto reporter_nest_cancel;
315
if (reporter->ops->dump &&
316
nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
317
reporter->auto_dump))
318
goto reporter_nest_cancel;
319
320
nla_nest_end(msg, reporter_attr);
321
genlmsg_end(msg, hdr);
322
return 0;
323
324
reporter_nest_cancel:
325
nla_nest_cancel(msg, reporter_attr);
326
genlmsg_cancel:
327
genlmsg_cancel(msg, hdr);
328
return -EMSGSIZE;
329
}
330
331
static struct devlink_health_reporter *
332
devlink_health_reporter_get_from_attrs(struct devlink *devlink,
333
struct nlattr **attrs)
334
{
335
struct devlink_port *devlink_port;
336
char *reporter_name;
337
338
if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
339
return NULL;
340
341
reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
342
devlink_port = devlink_port_get_from_attrs(devlink, attrs);
343
if (IS_ERR(devlink_port))
344
return devlink_health_reporter_find_by_name(devlink,
345
reporter_name);
346
else
347
return devlink_port_health_reporter_find_by_name(devlink_port,
348
reporter_name);
349
}
350
351
static struct devlink_health_reporter *
352
devlink_health_reporter_get_from_info(struct devlink *devlink,
353
struct genl_info *info)
354
{
355
return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
356
}
357
358
int devlink_nl_health_reporter_get_doit(struct sk_buff *skb,
359
struct genl_info *info)
360
{
361
struct devlink *devlink = info->user_ptr[0];
362
struct devlink_health_reporter *reporter;
363
struct sk_buff *msg;
364
int err;
365
366
reporter = devlink_health_reporter_get_from_info(devlink, info);
367
if (!reporter)
368
return -EINVAL;
369
370
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
371
if (!msg)
372
return -ENOMEM;
373
374
err = devlink_nl_health_reporter_fill(msg, reporter,
375
DEVLINK_CMD_HEALTH_REPORTER_GET,
376
info->snd_portid, info->snd_seq,
377
0);
378
if (err) {
379
nlmsg_free(msg);
380
return err;
381
}
382
383
return genlmsg_reply(msg, info);
384
}
385
386
static int devlink_nl_health_reporter_get_dump_one(struct sk_buff *msg,
387
struct devlink *devlink,
388
struct netlink_callback *cb,
389
int flags)
390
{
391
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
392
const struct genl_info *info = genl_info_dump(cb);
393
struct devlink_health_reporter *reporter;
394
unsigned long port_index_end = ULONG_MAX;
395
struct nlattr **attrs = info->attrs;
396
unsigned long port_index_start = 0;
397
struct devlink_port *port;
398
unsigned long port_index;
399
int idx = 0;
400
int err;
401
402
if (attrs && attrs[DEVLINK_ATTR_PORT_INDEX]) {
403
port_index_start = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
404
port_index_end = port_index_start;
405
flags |= NLM_F_DUMP_FILTERED;
406
goto per_port_dump;
407
}
408
409
list_for_each_entry(reporter, &devlink->reporter_list, list) {
410
if (idx < state->idx) {
411
idx++;
412
continue;
413
}
414
err = devlink_nl_health_reporter_fill(msg, reporter,
415
DEVLINK_CMD_HEALTH_REPORTER_GET,
416
NETLINK_CB(cb->skb).portid,
417
cb->nlh->nlmsg_seq,
418
flags);
419
if (err) {
420
state->idx = idx;
421
return err;
422
}
423
idx++;
424
}
425
per_port_dump:
426
xa_for_each_range(&devlink->ports, port_index, port,
427
port_index_start, port_index_end) {
428
list_for_each_entry(reporter, &port->reporter_list, list) {
429
if (idx < state->idx) {
430
idx++;
431
continue;
432
}
433
err = devlink_nl_health_reporter_fill(msg, reporter,
434
DEVLINK_CMD_HEALTH_REPORTER_GET,
435
NETLINK_CB(cb->skb).portid,
436
cb->nlh->nlmsg_seq,
437
flags);
438
if (err) {
439
state->idx = idx;
440
return err;
441
}
442
idx++;
443
}
444
}
445
446
return 0;
447
}
448
449
int devlink_nl_health_reporter_get_dumpit(struct sk_buff *skb,
450
struct netlink_callback *cb)
451
{
452
return devlink_nl_dumpit(skb, cb,
453
devlink_nl_health_reporter_get_dump_one);
454
}
455
456
int devlink_nl_health_reporter_set_doit(struct sk_buff *skb,
457
struct genl_info *info)
458
{
459
struct devlink *devlink = info->user_ptr[0];
460
struct devlink_health_reporter *reporter;
461
462
reporter = devlink_health_reporter_get_from_info(devlink, info);
463
if (!reporter)
464
return -EINVAL;
465
466
if (!reporter->ops->recover &&
467
(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
468
info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] ||
469
info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_BURST_PERIOD]))
470
return -EOPNOTSUPP;
471
472
if (!reporter->ops->dump &&
473
info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
474
return -EOPNOTSUPP;
475
476
if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]) {
477
reporter->graceful_period =
478
nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
479
if (!reporter->graceful_period)
480
reporter->burst_period = 0;
481
}
482
483
if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_BURST_PERIOD]) {
484
u64 burst_period =
485
nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_BURST_PERIOD]);
486
487
if (!reporter->graceful_period && burst_period) {
488
NL_SET_ERR_MSG_MOD(info->extack,
489
"Cannot set burst period without a grace period.");
490
return -EINVAL;
491
}
492
493
reporter->burst_period = burst_period;
494
}
495
496
if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
497
reporter->auto_recover =
498
nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
499
500
if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
501
reporter->auto_dump =
502
nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]);
503
504
return 0;
505
}
506
507
static void devlink_recover_notify(struct devlink_health_reporter *reporter,
508
enum devlink_command cmd)
509
{
510
struct devlink *devlink = reporter->devlink;
511
struct devlink_obj_desc desc;
512
struct sk_buff *msg;
513
int err;
514
515
WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
516
ASSERT_DEVLINK_REGISTERED(devlink);
517
518
if (!devlink_nl_notify_need(devlink))
519
return;
520
521
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
522
if (!msg)
523
return;
524
525
err = devlink_nl_health_reporter_fill(msg, reporter, cmd, 0, 0, 0);
526
if (err) {
527
nlmsg_free(msg);
528
return;
529
}
530
531
devlink_nl_obj_desc_init(&desc, devlink);
532
if (reporter->devlink_port)
533
devlink_nl_obj_desc_port_set(&desc, reporter->devlink_port);
534
devlink_nl_notify_send_desc(devlink, msg, &desc);
535
}
536
537
static bool
538
devlink_health_reporter_in_burst(struct devlink_health_reporter *reporter)
539
{
540
unsigned long burst_threshold = reporter->last_recovery_ts +
541
msecs_to_jiffies(reporter->burst_period);
542
543
return time_is_after_jiffies(burst_threshold);
544
}
545
546
void
547
devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter)
548
{
549
reporter->recovery_count++;
550
if (!devlink_health_reporter_in_burst(reporter))
551
/* When burst period is set, last_recovery_ts marks the first
552
* recovery within the burst period, not necessarily the last
553
* one.
554
*/
555
reporter->last_recovery_ts = jiffies;
556
}
557
EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done);
558
559
static int
560
devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
561
void *priv_ctx, struct netlink_ext_ack *extack)
562
{
563
int err;
564
565
if (reporter->health_state == DEVLINK_HEALTH_REPORTER_STATE_HEALTHY)
566
return 0;
567
568
if (!reporter->ops->recover)
569
return -EOPNOTSUPP;
570
571
err = reporter->ops->recover(reporter, priv_ctx, extack);
572
if (err)
573
return err;
574
575
devlink_health_reporter_recovery_done(reporter);
576
reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
577
devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
578
579
return 0;
580
}
581
582
static void
583
devlink_health_dump_clear(struct devlink_health_reporter *reporter)
584
{
585
if (!reporter->dump_fmsg)
586
return;
587
devlink_fmsg_free(reporter->dump_fmsg);
588
reporter->dump_fmsg = NULL;
589
}
590
591
static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
592
void *priv_ctx,
593
struct netlink_ext_ack *extack)
594
{
595
int err;
596
597
if (!reporter->ops->dump)
598
return 0;
599
600
if (reporter->dump_fmsg)
601
return 0;
602
603
reporter->dump_fmsg = devlink_fmsg_alloc();
604
if (!reporter->dump_fmsg)
605
return -ENOMEM;
606
607
devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
608
609
err = reporter->ops->dump(reporter, reporter->dump_fmsg,
610
priv_ctx, extack);
611
if (err)
612
goto dump_err;
613
614
devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
615
err = reporter->dump_fmsg->err;
616
if (err)
617
goto dump_err;
618
619
reporter->dump_ts = jiffies;
620
reporter->dump_real_ts = ktime_get_real_ns();
621
622
return 0;
623
624
dump_err:
625
devlink_health_dump_clear(reporter);
626
return err;
627
}
628
629
static bool
630
devlink_health_recover_abort(struct devlink_health_reporter *reporter,
631
enum devlink_health_reporter_state prev_state)
632
{
633
unsigned long recover_ts_threshold;
634
635
if (!reporter->auto_recover)
636
return false;
637
638
/* abort if the previous error wasn't recovered */
639
if (prev_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY)
640
return true;
641
642
if (devlink_health_reporter_in_burst(reporter))
643
return false;
644
645
recover_ts_threshold = reporter->last_recovery_ts +
646
msecs_to_jiffies(reporter->burst_period) +
647
msecs_to_jiffies(reporter->graceful_period);
648
if (reporter->last_recovery_ts && reporter->recovery_count &&
649
time_is_after_jiffies(recover_ts_threshold))
650
return true;
651
652
return false;
653
}
654
655
int devlink_health_report(struct devlink_health_reporter *reporter,
656
const char *msg, void *priv_ctx)
657
{
658
enum devlink_health_reporter_state prev_health_state;
659
struct devlink *devlink = reporter->devlink;
660
int ret;
661
662
/* write a log message of the current error */
663
WARN_ON(!msg);
664
trace_devlink_health_report(devlink, reporter->ops->name, msg);
665
reporter->error_count++;
666
prev_health_state = reporter->health_state;
667
reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
668
devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
669
670
if (devlink_health_recover_abort(reporter, prev_health_state)) {
671
trace_devlink_health_recover_aborted(devlink,
672
reporter->ops->name,
673
reporter->health_state,
674
jiffies -
675
reporter->last_recovery_ts);
676
return -ECANCELED;
677
}
678
679
if (reporter->auto_dump) {
680
devl_lock(devlink);
681
/* store current dump of current error, for later analysis */
682
devlink_health_do_dump(reporter, priv_ctx, NULL);
683
devl_unlock(devlink);
684
}
685
686
if (!reporter->auto_recover)
687
return 0;
688
689
devl_lock(devlink);
690
ret = devlink_health_reporter_recover(reporter, priv_ctx, NULL);
691
devl_unlock(devlink);
692
693
return ret;
694
}
695
EXPORT_SYMBOL_GPL(devlink_health_report);
696
697
void
698
devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
699
enum devlink_health_reporter_state state)
700
{
701
if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
702
state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
703
return;
704
705
if (reporter->health_state == state)
706
return;
707
708
reporter->health_state = state;
709
trace_devlink_health_reporter_state_update(reporter->devlink,
710
reporter->ops->name, state);
711
devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
712
}
713
EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
714
715
int devlink_nl_health_reporter_recover_doit(struct sk_buff *skb,
716
struct genl_info *info)
717
{
718
struct devlink *devlink = info->user_ptr[0];
719
struct devlink_health_reporter *reporter;
720
721
reporter = devlink_health_reporter_get_from_info(devlink, info);
722
if (!reporter)
723
return -EINVAL;
724
725
return devlink_health_reporter_recover(reporter, NULL, info->extack);
726
}
727
728
static void devlink_fmsg_err_if_binary(struct devlink_fmsg *fmsg)
729
{
730
if (!fmsg->err && fmsg->putting_binary)
731
fmsg->err = -EINVAL;
732
}
733
734
static void devlink_fmsg_nest_common(struct devlink_fmsg *fmsg, int attrtype)
735
{
736
struct devlink_fmsg_item *item;
737
738
if (fmsg->err)
739
return;
740
741
item = kzalloc(sizeof(*item), GFP_KERNEL);
742
if (!item) {
743
fmsg->err = -ENOMEM;
744
return;
745
}
746
747
item->attrtype = attrtype;
748
list_add_tail(&item->list, &fmsg->item_list);
749
}
750
751
void devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
752
{
753
devlink_fmsg_err_if_binary(fmsg);
754
devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
755
}
756
EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
757
758
static void devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
759
{
760
devlink_fmsg_err_if_binary(fmsg);
761
devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
762
}
763
764
void devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
765
{
766
devlink_fmsg_nest_end(fmsg);
767
}
768
EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
769
770
#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
771
772
static void devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
773
{
774
struct devlink_fmsg_item *item;
775
776
devlink_fmsg_err_if_binary(fmsg);
777
if (fmsg->err)
778
return;
779
780
if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE) {
781
fmsg->err = -EMSGSIZE;
782
return;
783
}
784
785
item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
786
if (!item) {
787
fmsg->err = -ENOMEM;
788
return;
789
}
790
791
item->nla_type = DEVLINK_VAR_ATTR_TYPE_NUL_STRING;
792
item->len = strlen(name) + 1;
793
item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
794
memcpy(&item->value, name, item->len);
795
list_add_tail(&item->list, &fmsg->item_list);
796
}
797
798
void devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
799
{
800
devlink_fmsg_err_if_binary(fmsg);
801
devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
802
devlink_fmsg_put_name(fmsg, name);
803
}
804
EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
805
806
void devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
807
{
808
devlink_fmsg_nest_end(fmsg);
809
}
810
EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
811
812
void devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
813
const char *name)
814
{
815
devlink_fmsg_pair_nest_start(fmsg, name);
816
devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
817
}
818
EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
819
820
void devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
821
{
822
devlink_fmsg_nest_end(fmsg);
823
devlink_fmsg_nest_end(fmsg);
824
}
825
EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
826
827
void devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg,
828
const char *name)
829
{
830
devlink_fmsg_arr_pair_nest_start(fmsg, name);
831
fmsg->putting_binary = true;
832
}
833
EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start);
834
835
void devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg)
836
{
837
if (fmsg->err)
838
return;
839
840
if (!fmsg->putting_binary)
841
fmsg->err = -EINVAL;
842
843
fmsg->putting_binary = false;
844
devlink_fmsg_arr_pair_nest_end(fmsg);
845
}
846
EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end);
847
848
static void devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
849
const void *value, u16 value_len,
850
u8 value_nla_type)
851
{
852
struct devlink_fmsg_item *item;
853
854
if (fmsg->err)
855
return;
856
857
if (value_len > DEVLINK_FMSG_MAX_SIZE) {
858
fmsg->err = -EMSGSIZE;
859
return;
860
}
861
862
item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
863
if (!item) {
864
fmsg->err = -ENOMEM;
865
return;
866
}
867
868
item->nla_type = value_nla_type;
869
item->len = value_len;
870
item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
871
memcpy(&item->value, value, item->len);
872
list_add_tail(&item->list, &fmsg->item_list);
873
}
874
875
static void devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
876
{
877
devlink_fmsg_err_if_binary(fmsg);
878
devlink_fmsg_put_value(fmsg, &value, sizeof(value),
879
DEVLINK_VAR_ATTR_TYPE_FLAG);
880
}
881
882
static void devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
883
{
884
devlink_fmsg_err_if_binary(fmsg);
885
devlink_fmsg_put_value(fmsg, &value, sizeof(value),
886
DEVLINK_VAR_ATTR_TYPE_U8);
887
}
888
889
void devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
890
{
891
devlink_fmsg_err_if_binary(fmsg);
892
devlink_fmsg_put_value(fmsg, &value, sizeof(value),
893
DEVLINK_VAR_ATTR_TYPE_U32);
894
}
895
EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
896
897
static void devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
898
{
899
devlink_fmsg_err_if_binary(fmsg);
900
devlink_fmsg_put_value(fmsg, &value, sizeof(value),
901
DEVLINK_VAR_ATTR_TYPE_U64);
902
}
903
904
void devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
905
{
906
devlink_fmsg_err_if_binary(fmsg);
907
devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
908
DEVLINK_VAR_ATTR_TYPE_NUL_STRING);
909
}
910
EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
911
912
void devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
913
u16 value_len)
914
{
915
if (!fmsg->err && !fmsg->putting_binary)
916
fmsg->err = -EINVAL;
917
918
devlink_fmsg_put_value(fmsg, value, value_len,
919
DEVLINK_VAR_ATTR_TYPE_BINARY);
920
}
921
EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
922
923
void devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
924
bool value)
925
{
926
devlink_fmsg_pair_nest_start(fmsg, name);
927
devlink_fmsg_bool_put(fmsg, value);
928
devlink_fmsg_pair_nest_end(fmsg);
929
}
930
EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
931
932
void devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
933
u8 value)
934
{
935
devlink_fmsg_pair_nest_start(fmsg, name);
936
devlink_fmsg_u8_put(fmsg, value);
937
devlink_fmsg_pair_nest_end(fmsg);
938
}
939
EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
940
941
void devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
942
u32 value)
943
{
944
devlink_fmsg_pair_nest_start(fmsg, name);
945
devlink_fmsg_u32_put(fmsg, value);
946
devlink_fmsg_pair_nest_end(fmsg);
947
}
948
EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
949
950
void devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
951
u64 value)
952
{
953
devlink_fmsg_pair_nest_start(fmsg, name);
954
devlink_fmsg_u64_put(fmsg, value);
955
devlink_fmsg_pair_nest_end(fmsg);
956
}
957
EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
958
959
void devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
960
const char *value)
961
{
962
devlink_fmsg_pair_nest_start(fmsg, name);
963
devlink_fmsg_string_put(fmsg, value);
964
devlink_fmsg_pair_nest_end(fmsg);
965
}
966
EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
967
968
void devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
969
const void *value, u32 value_len)
970
{
971
u32 data_size;
972
u32 offset;
973
974
devlink_fmsg_binary_pair_nest_start(fmsg, name);
975
976
for (offset = 0; offset < value_len; offset += data_size) {
977
data_size = value_len - offset;
978
if (data_size > DEVLINK_FMSG_MAX_SIZE)
979
data_size = DEVLINK_FMSG_MAX_SIZE;
980
981
devlink_fmsg_binary_put(fmsg, value + offset, data_size);
982
}
983
984
devlink_fmsg_binary_pair_nest_end(fmsg);
985
fmsg->putting_binary = false;
986
}
987
EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
988
989
static int
990
devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
991
{
992
int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
993
u8 tmp;
994
995
switch (msg->nla_type) {
996
case DEVLINK_VAR_ATTR_TYPE_FLAG:
997
/* Always provide flag data, regardless of its value */
998
tmp = *(bool *)msg->value;
999
1000
return nla_put_u8(skb, attrtype, tmp);
1001
case DEVLINK_VAR_ATTR_TYPE_U8:
1002
return nla_put_u8(skb, attrtype, *(u8 *)msg->value);
1003
case DEVLINK_VAR_ATTR_TYPE_U32:
1004
return nla_put_u32(skb, attrtype, *(u32 *)msg->value);
1005
case DEVLINK_VAR_ATTR_TYPE_U64:
1006
return devlink_nl_put_u64(skb, attrtype, *(u64 *)msg->value);
1007
case DEVLINK_VAR_ATTR_TYPE_NUL_STRING:
1008
return nla_put_string(skb, attrtype, (char *)&msg->value);
1009
case DEVLINK_VAR_ATTR_TYPE_BINARY:
1010
return nla_put(skb, attrtype, msg->len, (void *)&msg->value);
1011
default:
1012
return -EINVAL;
1013
}
1014
}
1015
1016
static int
1017
devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
1018
int *start)
1019
{
1020
struct devlink_fmsg_item *item;
1021
struct nlattr *fmsg_nlattr;
1022
int err = 0;
1023
int i = 0;
1024
1025
fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
1026
if (!fmsg_nlattr)
1027
return -EMSGSIZE;
1028
1029
list_for_each_entry(item, &fmsg->item_list, list) {
1030
if (i < *start) {
1031
i++;
1032
continue;
1033
}
1034
1035
switch (item->attrtype) {
1036
case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
1037
case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
1038
case DEVLINK_ATTR_FMSG_ARR_NEST_START:
1039
case DEVLINK_ATTR_FMSG_NEST_END:
1040
err = nla_put_flag(skb, item->attrtype);
1041
break;
1042
case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
1043
err = nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
1044
item->nla_type);
1045
if (err)
1046
break;
1047
err = devlink_fmsg_item_fill_data(item, skb);
1048
break;
1049
case DEVLINK_ATTR_FMSG_OBJ_NAME:
1050
err = nla_put_string(skb, item->attrtype,
1051
(char *)&item->value);
1052
break;
1053
default:
1054
err = -EINVAL;
1055
break;
1056
}
1057
if (!err)
1058
*start = ++i;
1059
else
1060
break;
1061
}
1062
1063
nla_nest_end(skb, fmsg_nlattr);
1064
return err;
1065
}
1066
1067
static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
1068
struct genl_info *info,
1069
enum devlink_command cmd, int flags)
1070
{
1071
struct nlmsghdr *nlh;
1072
struct sk_buff *skb;
1073
bool last = false;
1074
int index = 0;
1075
void *hdr;
1076
int err;
1077
1078
if (fmsg->err)
1079
return fmsg->err;
1080
1081
while (!last) {
1082
int tmp_index = index;
1083
1084
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
1085
if (!skb)
1086
return -ENOMEM;
1087
1088
hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
1089
&devlink_nl_family, flags | NLM_F_MULTI, cmd);
1090
if (!hdr) {
1091
err = -EMSGSIZE;
1092
goto nla_put_failure;
1093
}
1094
1095
err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
1096
if (!err)
1097
last = true;
1098
else if (err != -EMSGSIZE || tmp_index == index)
1099
goto nla_put_failure;
1100
1101
genlmsg_end(skb, hdr);
1102
err = genlmsg_reply(skb, info);
1103
if (err)
1104
return err;
1105
}
1106
1107
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
1108
if (!skb)
1109
return -ENOMEM;
1110
nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
1111
NLMSG_DONE, 0, flags | NLM_F_MULTI);
1112
if (!nlh) {
1113
err = -EMSGSIZE;
1114
goto nla_put_failure;
1115
}
1116
1117
return genlmsg_reply(skb, info);
1118
1119
nla_put_failure:
1120
nlmsg_free(skb);
1121
return err;
1122
}
1123
1124
static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
1125
struct netlink_callback *cb,
1126
enum devlink_command cmd)
1127
{
1128
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
1129
int index = state->idx;
1130
int tmp_index = index;
1131
void *hdr;
1132
int err;
1133
1134
if (fmsg->err)
1135
return fmsg->err;
1136
1137
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
1138
&devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
1139
if (!hdr) {
1140
err = -EMSGSIZE;
1141
goto nla_put_failure;
1142
}
1143
1144
err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
1145
if ((err && err != -EMSGSIZE) || tmp_index == index)
1146
goto nla_put_failure;
1147
1148
state->idx = index;
1149
genlmsg_end(skb, hdr);
1150
return skb->len;
1151
1152
nla_put_failure:
1153
genlmsg_cancel(skb, hdr);
1154
return err;
1155
}
1156
1157
int devlink_nl_health_reporter_diagnose_doit(struct sk_buff *skb,
1158
struct genl_info *info)
1159
{
1160
struct devlink *devlink = info->user_ptr[0];
1161
struct devlink_health_reporter *reporter;
1162
struct devlink_fmsg *fmsg;
1163
int err;
1164
1165
reporter = devlink_health_reporter_get_from_info(devlink, info);
1166
if (!reporter)
1167
return -EINVAL;
1168
1169
if (!reporter->ops->diagnose)
1170
return -EOPNOTSUPP;
1171
1172
fmsg = devlink_fmsg_alloc();
1173
if (!fmsg)
1174
return -ENOMEM;
1175
1176
devlink_fmsg_obj_nest_start(fmsg);
1177
1178
err = reporter->ops->diagnose(reporter, fmsg, info->extack);
1179
if (err)
1180
goto out;
1181
1182
devlink_fmsg_obj_nest_end(fmsg);
1183
1184
err = devlink_fmsg_snd(fmsg, info,
1185
DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
1186
1187
out:
1188
devlink_fmsg_free(fmsg);
1189
return err;
1190
}
1191
1192
static struct devlink_health_reporter *
1193
devlink_health_reporter_get_from_cb_lock(struct netlink_callback *cb)
1194
{
1195
const struct genl_info *info = genl_info_dump(cb);
1196
struct devlink_health_reporter *reporter;
1197
struct nlattr **attrs = info->attrs;
1198
struct devlink *devlink;
1199
1200
devlink = devlink_get_from_attrs_lock(sock_net(cb->skb->sk), attrs,
1201
false);
1202
if (IS_ERR(devlink))
1203
return NULL;
1204
1205
reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
1206
if (!reporter) {
1207
devl_unlock(devlink);
1208
devlink_put(devlink);
1209
}
1210
return reporter;
1211
}
1212
1213
int devlink_nl_health_reporter_dump_get_dumpit(struct sk_buff *skb,
1214
struct netlink_callback *cb)
1215
{
1216
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
1217
struct devlink_health_reporter *reporter;
1218
struct devlink *devlink;
1219
int err;
1220
1221
reporter = devlink_health_reporter_get_from_cb_lock(cb);
1222
if (!reporter)
1223
return -EINVAL;
1224
1225
devlink = reporter->devlink;
1226
if (!reporter->ops->dump) {
1227
devl_unlock(devlink);
1228
devlink_put(devlink);
1229
return -EOPNOTSUPP;
1230
}
1231
1232
if (!state->idx) {
1233
err = devlink_health_do_dump(reporter, NULL, cb->extack);
1234
if (err)
1235
goto unlock;
1236
state->dump_ts = reporter->dump_ts;
1237
}
1238
if (!reporter->dump_fmsg || state->dump_ts != reporter->dump_ts) {
1239
NL_SET_ERR_MSG(cb->extack, "Dump trampled, please retry");
1240
err = -EAGAIN;
1241
goto unlock;
1242
}
1243
1244
err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
1245
DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
1246
unlock:
1247
devl_unlock(devlink);
1248
devlink_put(devlink);
1249
return err;
1250
}
1251
1252
int devlink_nl_health_reporter_dump_clear_doit(struct sk_buff *skb,
1253
struct genl_info *info)
1254
{
1255
struct devlink *devlink = info->user_ptr[0];
1256
struct devlink_health_reporter *reporter;
1257
1258
reporter = devlink_health_reporter_get_from_info(devlink, info);
1259
if (!reporter)
1260
return -EINVAL;
1261
1262
if (!reporter->ops->dump)
1263
return -EOPNOTSUPP;
1264
1265
devlink_health_dump_clear(reporter);
1266
return 0;
1267
}
1268
1269
int devlink_nl_health_reporter_test_doit(struct sk_buff *skb,
1270
struct genl_info *info)
1271
{
1272
struct devlink *devlink = info->user_ptr[0];
1273
struct devlink_health_reporter *reporter;
1274
1275
reporter = devlink_health_reporter_get_from_info(devlink, info);
1276
if (!reporter)
1277
return -EINVAL;
1278
1279
if (!reporter->ops->test)
1280
return -EOPNOTSUPP;
1281
1282
return reporter->ops->test(reporter, info->extack);
1283
}
1284
1285
/**
1286
* devlink_fmsg_dump_skb - Dump sk_buffer structure
1287
* @fmsg: devlink formatted message pointer
1288
* @skb: pointer to skb
1289
*
1290
* Dump diagnostic information about sk_buff structure, like headroom, length,
1291
* tailroom, MAC, etc.
1292
*/
1293
void devlink_fmsg_dump_skb(struct devlink_fmsg *fmsg, const struct sk_buff *skb)
1294
{
1295
struct skb_shared_info *sh = skb_shinfo(skb);
1296
struct sock *sk = skb->sk;
1297
bool has_mac, has_trans;
1298
1299
has_mac = skb_mac_header_was_set(skb);
1300
has_trans = skb_transport_header_was_set(skb);
1301
1302
devlink_fmsg_pair_nest_start(fmsg, "skb");
1303
devlink_fmsg_obj_nest_start(fmsg);
1304
devlink_fmsg_put(fmsg, "actual len", skb->len);
1305
devlink_fmsg_put(fmsg, "head len", skb_headlen(skb));
1306
devlink_fmsg_put(fmsg, "data len", skb->data_len);
1307
devlink_fmsg_put(fmsg, "tail len", skb_tailroom(skb));
1308
devlink_fmsg_put(fmsg, "MAC", has_mac ? skb->mac_header : -1);
1309
devlink_fmsg_put(fmsg, "MAC len",
1310
has_mac ? skb_mac_header_len(skb) : -1);
1311
devlink_fmsg_put(fmsg, "network hdr", skb->network_header);
1312
devlink_fmsg_put(fmsg, "network hdr len",
1313
has_trans ? skb_network_header_len(skb) : -1);
1314
devlink_fmsg_put(fmsg, "transport hdr",
1315
has_trans ? skb->transport_header : -1);
1316
devlink_fmsg_put(fmsg, "csum", (__force u32)skb->csum);
1317
devlink_fmsg_put(fmsg, "csum_ip_summed", (u8)skb->ip_summed);
1318
devlink_fmsg_put(fmsg, "csum_complete_sw", !!skb->csum_complete_sw);
1319
devlink_fmsg_put(fmsg, "csum_valid", !!skb->csum_valid);
1320
devlink_fmsg_put(fmsg, "csum_level", (u8)skb->csum_level);
1321
devlink_fmsg_put(fmsg, "sw_hash", !!skb->sw_hash);
1322
devlink_fmsg_put(fmsg, "l4_hash", !!skb->l4_hash);
1323
devlink_fmsg_put(fmsg, "proto", ntohs(skb->protocol));
1324
devlink_fmsg_put(fmsg, "pkt_type", (u8)skb->pkt_type);
1325
devlink_fmsg_put(fmsg, "iif", skb->skb_iif);
1326
1327
if (sk) {
1328
devlink_fmsg_pair_nest_start(fmsg, "sk");
1329
devlink_fmsg_obj_nest_start(fmsg);
1330
devlink_fmsg_put(fmsg, "family", sk->sk_type);
1331
devlink_fmsg_put(fmsg, "type", sk->sk_type);
1332
devlink_fmsg_put(fmsg, "proto", sk->sk_protocol);
1333
devlink_fmsg_obj_nest_end(fmsg);
1334
devlink_fmsg_pair_nest_end(fmsg);
1335
}
1336
1337
devlink_fmsg_obj_nest_end(fmsg);
1338
devlink_fmsg_pair_nest_end(fmsg);
1339
1340
devlink_fmsg_pair_nest_start(fmsg, "shinfo");
1341
devlink_fmsg_obj_nest_start(fmsg);
1342
devlink_fmsg_put(fmsg, "tx_flags", sh->tx_flags);
1343
devlink_fmsg_put(fmsg, "nr_frags", sh->nr_frags);
1344
devlink_fmsg_put(fmsg, "gso_size", sh->gso_size);
1345
devlink_fmsg_put(fmsg, "gso_type", sh->gso_type);
1346
devlink_fmsg_put(fmsg, "gso_segs", sh->gso_segs);
1347
devlink_fmsg_obj_nest_end(fmsg);
1348
devlink_fmsg_pair_nest_end(fmsg);
1349
}
1350
EXPORT_SYMBOL_GPL(devlink_fmsg_dump_skb);
1351
1352