Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
5 */
6
7#include <net/genetlink.h>
8#include <net/sock.h>
9#include <trace/events/devlink.h>
10#include "devl_internal.h"
11
12struct devlink_fmsg_item {
13 struct list_head list;
14 int attrtype;
15 u8 nla_type;
16 u16 len;
17 int value[];
18};
19
20struct 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
31static 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
44static 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
55struct 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
74void *
75devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
76{
77 return reporter->priv;
78}
79EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
80
81static 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
93static struct devlink_health_reporter *
94devlink_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
101static struct devlink_health_reporter *
102devlink_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
109static 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 */
144struct devlink_health_reporter *
145devl_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}
165EXPORT_SYMBOL_GPL(devl_port_health_reporter_create);
166
167struct devlink_health_reporter *
168devlink_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}
180EXPORT_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 */
189struct devlink_health_reporter *
190devl_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}
208EXPORT_SYMBOL_GPL(devl_health_reporter_create);
209
210struct devlink_health_reporter *
211devlink_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}
222EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
223
224static void
225devlink_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 */
237void
238devl_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}
245EXPORT_SYMBOL_GPL(devl_health_reporter_destroy);
246
247void
248devlink_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}
256EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
257
258static int
259devlink_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
324reporter_nest_cancel:
325 nla_nest_cancel(msg, reporter_attr);
326genlmsg_cancel:
327 genlmsg_cancel(msg, hdr);
328 return -EMSGSIZE;
329}
330
331static struct devlink_health_reporter *
332devlink_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
351static struct devlink_health_reporter *
352devlink_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
358int 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
386static 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 }
425per_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
449int 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
456int 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
507static 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
537static bool
538devlink_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
546void
547devlink_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}
557EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done);
558
559static int
560devlink_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
582static void
583devlink_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
591static 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
624dump_err:
625 devlink_health_dump_clear(reporter);
626 return err;
627}
628
629static bool
630devlink_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
655int 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}
695EXPORT_SYMBOL_GPL(devlink_health_report);
696
697void
698devlink_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}
713EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
714
715int 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
728static void devlink_fmsg_err_if_binary(struct devlink_fmsg *fmsg)
729{
730 if (!fmsg->err && fmsg->putting_binary)
731 fmsg->err = -EINVAL;
732}
733
734static 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
751void 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}
756EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
757
758static 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
764void devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
765{
766 devlink_fmsg_nest_end(fmsg);
767}
768EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
769
770#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
771
772static 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
798void 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}
804EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
805
806void devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
807{
808 devlink_fmsg_nest_end(fmsg);
809}
810EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
811
812void 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}
818EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
819
820void devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
821{
822 devlink_fmsg_nest_end(fmsg);
823 devlink_fmsg_nest_end(fmsg);
824}
825EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
826
827void 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}
833EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start);
834
835void 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}
846EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end);
847
848static 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
875static 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
882static 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
889void 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}
895EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
896
897static 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
904void 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}
910EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
911
912void 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}
921EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
922
923void 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}
930EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
931
932void 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}
939EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
940
941void 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}
948EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
949
950void 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}
957EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
958
959void 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}
966EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
967
968void 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}
987EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
988
989static int
990devlink_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
1016static int
1017devlink_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
1067static 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
1119nla_put_failure:
1120 nlmsg_free(skb);
1121 return err;
1122}
1123
1124static 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
1152nla_put_failure:
1153 genlmsg_cancel(skb, hdr);
1154 return err;
1155}
1156
1157int 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
1187out:
1188 devlink_fmsg_free(fmsg);
1189 return err;
1190}
1191
1192static struct devlink_health_reporter *
1193devlink_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
1213int 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);
1246unlock:
1247 devl_unlock(devlink);
1248 devlink_put(devlink);
1249 return err;
1250}
1251
1252int 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
1269int 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 */
1293void 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}
1350EXPORT_SYMBOL_GPL(devlink_fmsg_dump_skb);