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