1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
7 #include <net/genetlink.h>
9 #include <trace/events/devlink.h>
10 #include "devl_internal.h"
12 struct devlink_fmsg_item
{
13 struct list_head list
;
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
26 * devlink_fmsg_binary_pair_nest_start()
27 * devlink_fmsg_binary_pair_nest_end()
31 static struct devlink_fmsg
*devlink_fmsg_alloc(void)
33 struct devlink_fmsg
*fmsg
;
35 fmsg
= kzalloc(sizeof(*fmsg
), GFP_KERNEL
);
39 INIT_LIST_HEAD(&fmsg
->item_list
);
44 static void devlink_fmsg_free(struct devlink_fmsg
*fmsg
)
46 struct devlink_fmsg_item
*item
, *tmp
;
48 list_for_each_entry_safe(item
, tmp
, &fmsg
->item_list
, list
) {
49 list_del(&item
->list
);
55 struct devlink_health_reporter
{
56 struct list_head list
;
58 const struct devlink_health_reporter_ops
*ops
;
59 struct devlink
*devlink
;
60 struct devlink_port
*devlink_port
;
61 struct devlink_fmsg
*dump_fmsg
;
74 devlink_health_reporter_priv(struct devlink_health_reporter
*reporter
)
76 return reporter
->priv
;
78 EXPORT_SYMBOL_GPL(devlink_health_reporter_priv
);
80 static struct devlink_health_reporter
*
81 __devlink_health_reporter_find_by_name(struct list_head
*reporter_list
,
82 const char *reporter_name
)
84 struct devlink_health_reporter
*reporter
;
86 list_for_each_entry(reporter
, reporter_list
, list
)
87 if (!strcmp(reporter
->ops
->name
, reporter_name
))
92 static struct devlink_health_reporter
*
93 devlink_health_reporter_find_by_name(struct devlink
*devlink
,
94 const char *reporter_name
)
96 return __devlink_health_reporter_find_by_name(&devlink
->reporter_list
,
100 static struct devlink_health_reporter
*
101 devlink_port_health_reporter_find_by_name(struct devlink_port
*devlink_port
,
102 const char *reporter_name
)
104 return __devlink_health_reporter_find_by_name(&devlink_port
->reporter_list
,
108 static struct devlink_health_reporter
*
109 __devlink_health_reporter_create(struct devlink
*devlink
,
110 const struct devlink_health_reporter_ops
*ops
,
111 u64 graceful_period
, void *priv
)
113 struct devlink_health_reporter
*reporter
;
115 if (WARN_ON(graceful_period
&& !ops
->recover
))
116 return ERR_PTR(-EINVAL
);
118 reporter
= kzalloc(sizeof(*reporter
), GFP_KERNEL
);
120 return ERR_PTR(-ENOMEM
);
122 reporter
->priv
= priv
;
124 reporter
->devlink
= devlink
;
125 reporter
->graceful_period
= graceful_period
;
126 reporter
->auto_recover
= !!ops
->recover
;
127 reporter
->auto_dump
= !!ops
->dump
;
132 * devl_port_health_reporter_create() - create devlink health reporter for
133 * specified port instance
135 * @port: devlink_port to which health reports will relate
136 * @ops: devlink health reporter ops
137 * @graceful_period: min time (in msec) between recovery attempts
138 * @priv: driver priv pointer
140 struct devlink_health_reporter
*
141 devl_port_health_reporter_create(struct devlink_port
*port
,
142 const struct devlink_health_reporter_ops
*ops
,
143 u64 graceful_period
, void *priv
)
145 struct devlink_health_reporter
*reporter
;
147 devl_assert_locked(port
->devlink
);
149 if (__devlink_health_reporter_find_by_name(&port
->reporter_list
,
151 return ERR_PTR(-EEXIST
);
153 reporter
= __devlink_health_reporter_create(port
->devlink
, ops
,
154 graceful_period
, priv
);
155 if (IS_ERR(reporter
))
158 reporter
->devlink_port
= port
;
159 list_add_tail(&reporter
->list
, &port
->reporter_list
);
162 EXPORT_SYMBOL_GPL(devl_port_health_reporter_create
);
164 struct devlink_health_reporter
*
165 devlink_port_health_reporter_create(struct devlink_port
*port
,
166 const struct devlink_health_reporter_ops
*ops
,
167 u64 graceful_period
, void *priv
)
169 struct devlink_health_reporter
*reporter
;
170 struct devlink
*devlink
= port
->devlink
;
173 reporter
= devl_port_health_reporter_create(port
, ops
,
174 graceful_period
, priv
);
175 devl_unlock(devlink
);
178 EXPORT_SYMBOL_GPL(devlink_port_health_reporter_create
);
181 * devl_health_reporter_create - create devlink health reporter
183 * @devlink: devlink instance which the health reports will relate
184 * @ops: devlink health reporter ops
185 * @graceful_period: min time (in msec) between recovery attempts
186 * @priv: driver priv pointer
188 struct devlink_health_reporter
*
189 devl_health_reporter_create(struct devlink
*devlink
,
190 const struct devlink_health_reporter_ops
*ops
,
191 u64 graceful_period
, void *priv
)
193 struct devlink_health_reporter
*reporter
;
195 devl_assert_locked(devlink
);
197 if (devlink_health_reporter_find_by_name(devlink
, ops
->name
))
198 return ERR_PTR(-EEXIST
);
200 reporter
= __devlink_health_reporter_create(devlink
, ops
,
201 graceful_period
, priv
);
202 if (IS_ERR(reporter
))
205 list_add_tail(&reporter
->list
, &devlink
->reporter_list
);
208 EXPORT_SYMBOL_GPL(devl_health_reporter_create
);
210 struct devlink_health_reporter
*
211 devlink_health_reporter_create(struct devlink
*devlink
,
212 const struct devlink_health_reporter_ops
*ops
,
213 u64 graceful_period
, void *priv
)
215 struct devlink_health_reporter
*reporter
;
218 reporter
= devl_health_reporter_create(devlink
, ops
,
219 graceful_period
, priv
);
220 devl_unlock(devlink
);
223 EXPORT_SYMBOL_GPL(devlink_health_reporter_create
);
226 devlink_health_reporter_free(struct devlink_health_reporter
*reporter
)
228 if (reporter
->dump_fmsg
)
229 devlink_fmsg_free(reporter
->dump_fmsg
);
234 * devl_health_reporter_destroy() - destroy devlink health reporter
236 * @reporter: devlink health reporter to destroy
239 devl_health_reporter_destroy(struct devlink_health_reporter
*reporter
)
241 devl_assert_locked(reporter
->devlink
);
243 list_del(&reporter
->list
);
244 devlink_health_reporter_free(reporter
);
246 EXPORT_SYMBOL_GPL(devl_health_reporter_destroy
);
249 devlink_health_reporter_destroy(struct devlink_health_reporter
*reporter
)
251 struct devlink
*devlink
= reporter
->devlink
;
254 devl_health_reporter_destroy(reporter
);
255 devl_unlock(devlink
);
257 EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy
);
260 devlink_nl_health_reporter_fill(struct sk_buff
*msg
,
261 struct devlink_health_reporter
*reporter
,
262 enum devlink_command cmd
, u32 portid
,
265 struct devlink
*devlink
= reporter
->devlink
;
266 struct nlattr
*reporter_attr
;
269 hdr
= genlmsg_put(msg
, portid
, seq
, &devlink_nl_family
, flags
, cmd
);
273 if (devlink_nl_put_handle(msg
, devlink
))
276 if (reporter
->devlink_port
) {
277 if (nla_put_u32(msg
, DEVLINK_ATTR_PORT_INDEX
, reporter
->devlink_port
->index
))
280 reporter_attr
= nla_nest_start_noflag(msg
,
281 DEVLINK_ATTR_HEALTH_REPORTER
);
284 if (nla_put_string(msg
, DEVLINK_ATTR_HEALTH_REPORTER_NAME
,
285 reporter
->ops
->name
))
286 goto reporter_nest_cancel
;
287 if (nla_put_u8(msg
, DEVLINK_ATTR_HEALTH_REPORTER_STATE
,
288 reporter
->health_state
))
289 goto reporter_nest_cancel
;
290 if (devlink_nl_put_u64(msg
, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
,
291 reporter
->error_count
))
292 goto reporter_nest_cancel
;
293 if (devlink_nl_put_u64(msg
, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
,
294 reporter
->recovery_count
))
295 goto reporter_nest_cancel
;
296 if (reporter
->ops
->recover
&&
297 devlink_nl_put_u64(msg
, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
,
298 reporter
->graceful_period
))
299 goto reporter_nest_cancel
;
300 if (reporter
->ops
->recover
&&
301 nla_put_u8(msg
, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
,
302 reporter
->auto_recover
))
303 goto reporter_nest_cancel
;
304 if (reporter
->dump_fmsg
&&
305 devlink_nl_put_u64(msg
, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
,
306 jiffies_to_msecs(reporter
->dump_ts
)))
307 goto reporter_nest_cancel
;
308 if (reporter
->dump_fmsg
&&
309 devlink_nl_put_u64(msg
, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS
,
310 reporter
->dump_real_ts
))
311 goto reporter_nest_cancel
;
312 if (reporter
->ops
->dump
&&
313 nla_put_u8(msg
, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
,
314 reporter
->auto_dump
))
315 goto reporter_nest_cancel
;
317 nla_nest_end(msg
, reporter_attr
);
318 genlmsg_end(msg
, hdr
);
321 reporter_nest_cancel
:
322 nla_nest_cancel(msg
, reporter_attr
);
324 genlmsg_cancel(msg
, hdr
);
328 static struct devlink_health_reporter
*
329 devlink_health_reporter_get_from_attrs(struct devlink
*devlink
,
330 struct nlattr
**attrs
)
332 struct devlink_port
*devlink_port
;
335 if (!attrs
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
])
338 reporter_name
= nla_data(attrs
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
]);
339 devlink_port
= devlink_port_get_from_attrs(devlink
, attrs
);
340 if (IS_ERR(devlink_port
))
341 return devlink_health_reporter_find_by_name(devlink
,
344 return devlink_port_health_reporter_find_by_name(devlink_port
,
348 static struct devlink_health_reporter
*
349 devlink_health_reporter_get_from_info(struct devlink
*devlink
,
350 struct genl_info
*info
)
352 return devlink_health_reporter_get_from_attrs(devlink
, info
->attrs
);
355 int devlink_nl_health_reporter_get_doit(struct sk_buff
*skb
,
356 struct genl_info
*info
)
358 struct devlink
*devlink
= info
->user_ptr
[0];
359 struct devlink_health_reporter
*reporter
;
363 reporter
= devlink_health_reporter_get_from_info(devlink
, info
);
367 msg
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
371 err
= devlink_nl_health_reporter_fill(msg
, reporter
,
372 DEVLINK_CMD_HEALTH_REPORTER_GET
,
373 info
->snd_portid
, info
->snd_seq
,
380 return genlmsg_reply(msg
, info
);
383 static int devlink_nl_health_reporter_get_dump_one(struct sk_buff
*msg
,
384 struct devlink
*devlink
,
385 struct netlink_callback
*cb
,
388 struct devlink_nl_dump_state
*state
= devlink_dump_state(cb
);
389 const struct genl_info
*info
= genl_info_dump(cb
);
390 struct devlink_health_reporter
*reporter
;
391 unsigned long port_index_end
= ULONG_MAX
;
392 struct nlattr
**attrs
= info
->attrs
;
393 unsigned long port_index_start
= 0;
394 struct devlink_port
*port
;
395 unsigned long port_index
;
399 if (attrs
&& attrs
[DEVLINK_ATTR_PORT_INDEX
]) {
400 port_index_start
= nla_get_u32(attrs
[DEVLINK_ATTR_PORT_INDEX
]);
401 port_index_end
= port_index_start
;
402 flags
|= NLM_F_DUMP_FILTERED
;
406 list_for_each_entry(reporter
, &devlink
->reporter_list
, list
) {
407 if (idx
< state
->idx
) {
411 err
= devlink_nl_health_reporter_fill(msg
, reporter
,
412 DEVLINK_CMD_HEALTH_REPORTER_GET
,
413 NETLINK_CB(cb
->skb
).portid
,
423 xa_for_each_range(&devlink
->ports
, port_index
, port
,
424 port_index_start
, port_index_end
) {
425 list_for_each_entry(reporter
, &port
->reporter_list
, list
) {
426 if (idx
< state
->idx
) {
430 err
= devlink_nl_health_reporter_fill(msg
, reporter
,
431 DEVLINK_CMD_HEALTH_REPORTER_GET
,
432 NETLINK_CB(cb
->skb
).portid
,
446 int devlink_nl_health_reporter_get_dumpit(struct sk_buff
*skb
,
447 struct netlink_callback
*cb
)
449 return devlink_nl_dumpit(skb
, cb
,
450 devlink_nl_health_reporter_get_dump_one
);
453 int devlink_nl_health_reporter_set_doit(struct sk_buff
*skb
,
454 struct genl_info
*info
)
456 struct devlink
*devlink
= info
->user_ptr
[0];
457 struct devlink_health_reporter
*reporter
;
459 reporter
= devlink_health_reporter_get_from_info(devlink
, info
);
463 if (!reporter
->ops
->recover
&&
464 (info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
] ||
465 info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
]))
468 if (!reporter
->ops
->dump
&&
469 info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
])
472 if (info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
])
473 reporter
->graceful_period
=
474 nla_get_u64(info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
]);
476 if (info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
])
477 reporter
->auto_recover
=
478 nla_get_u8(info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
]);
480 if (info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
])
481 reporter
->auto_dump
=
482 nla_get_u8(info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
]);
487 static void devlink_recover_notify(struct devlink_health_reporter
*reporter
,
488 enum devlink_command cmd
)
490 struct devlink
*devlink
= reporter
->devlink
;
491 struct devlink_obj_desc desc
;
495 WARN_ON(cmd
!= DEVLINK_CMD_HEALTH_REPORTER_RECOVER
);
496 ASSERT_DEVLINK_REGISTERED(devlink
);
498 if (!devlink_nl_notify_need(devlink
))
501 msg
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
505 err
= devlink_nl_health_reporter_fill(msg
, reporter
, cmd
, 0, 0, 0);
511 devlink_nl_obj_desc_init(&desc
, devlink
);
512 if (reporter
->devlink_port
)
513 devlink_nl_obj_desc_port_set(&desc
, reporter
->devlink_port
);
514 devlink_nl_notify_send_desc(devlink
, msg
, &desc
);
518 devlink_health_reporter_recovery_done(struct devlink_health_reporter
*reporter
)
520 reporter
->recovery_count
++;
521 reporter
->last_recovery_ts
= jiffies
;
523 EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done
);
526 devlink_health_reporter_recover(struct devlink_health_reporter
*reporter
,
527 void *priv_ctx
, struct netlink_ext_ack
*extack
)
531 if (reporter
->health_state
== DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
)
534 if (!reporter
->ops
->recover
)
537 err
= reporter
->ops
->recover(reporter
, priv_ctx
, extack
);
541 devlink_health_reporter_recovery_done(reporter
);
542 reporter
->health_state
= DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
;
543 devlink_recover_notify(reporter
, DEVLINK_CMD_HEALTH_REPORTER_RECOVER
);
549 devlink_health_dump_clear(struct devlink_health_reporter
*reporter
)
551 if (!reporter
->dump_fmsg
)
553 devlink_fmsg_free(reporter
->dump_fmsg
);
554 reporter
->dump_fmsg
= NULL
;
557 static int devlink_health_do_dump(struct devlink_health_reporter
*reporter
,
559 struct netlink_ext_ack
*extack
)
563 if (!reporter
->ops
->dump
)
566 if (reporter
->dump_fmsg
)
569 reporter
->dump_fmsg
= devlink_fmsg_alloc();
570 if (!reporter
->dump_fmsg
)
573 devlink_fmsg_obj_nest_start(reporter
->dump_fmsg
);
575 err
= reporter
->ops
->dump(reporter
, reporter
->dump_fmsg
,
580 devlink_fmsg_obj_nest_end(reporter
->dump_fmsg
);
581 err
= reporter
->dump_fmsg
->err
;
585 reporter
->dump_ts
= jiffies
;
586 reporter
->dump_real_ts
= ktime_get_real_ns();
591 devlink_health_dump_clear(reporter
);
595 int devlink_health_report(struct devlink_health_reporter
*reporter
,
596 const char *msg
, void *priv_ctx
)
598 enum devlink_health_reporter_state prev_health_state
;
599 struct devlink
*devlink
= reporter
->devlink
;
600 unsigned long recover_ts_threshold
;
603 /* write a log message of the current error */
605 trace_devlink_health_report(devlink
, reporter
->ops
->name
, msg
);
606 reporter
->error_count
++;
607 prev_health_state
= reporter
->health_state
;
608 reporter
->health_state
= DEVLINK_HEALTH_REPORTER_STATE_ERROR
;
609 devlink_recover_notify(reporter
, DEVLINK_CMD_HEALTH_REPORTER_RECOVER
);
611 /* abort if the previous error wasn't recovered */
612 recover_ts_threshold
= reporter
->last_recovery_ts
+
613 msecs_to_jiffies(reporter
->graceful_period
);
614 if (reporter
->auto_recover
&&
615 (prev_health_state
!= DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
||
616 (reporter
->last_recovery_ts
&& reporter
->recovery_count
&&
617 time_is_after_jiffies(recover_ts_threshold
)))) {
618 trace_devlink_health_recover_aborted(devlink
,
620 reporter
->health_state
,
622 reporter
->last_recovery_ts
);
626 if (reporter
->auto_dump
) {
628 /* store current dump of current error, for later analysis */
629 devlink_health_do_dump(reporter
, priv_ctx
, NULL
);
630 devl_unlock(devlink
);
633 if (!reporter
->auto_recover
)
637 ret
= devlink_health_reporter_recover(reporter
, priv_ctx
, NULL
);
638 devl_unlock(devlink
);
642 EXPORT_SYMBOL_GPL(devlink_health_report
);
645 devlink_health_reporter_state_update(struct devlink_health_reporter
*reporter
,
646 enum devlink_health_reporter_state state
)
648 if (WARN_ON(state
!= DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
&&
649 state
!= DEVLINK_HEALTH_REPORTER_STATE_ERROR
))
652 if (reporter
->health_state
== state
)
655 reporter
->health_state
= state
;
656 trace_devlink_health_reporter_state_update(reporter
->devlink
,
657 reporter
->ops
->name
, state
);
658 devlink_recover_notify(reporter
, DEVLINK_CMD_HEALTH_REPORTER_RECOVER
);
660 EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update
);
662 int devlink_nl_health_reporter_recover_doit(struct sk_buff
*skb
,
663 struct genl_info
*info
)
665 struct devlink
*devlink
= info
->user_ptr
[0];
666 struct devlink_health_reporter
*reporter
;
668 reporter
= devlink_health_reporter_get_from_info(devlink
, info
);
672 return devlink_health_reporter_recover(reporter
, NULL
, info
->extack
);
675 static void devlink_fmsg_err_if_binary(struct devlink_fmsg
*fmsg
)
677 if (!fmsg
->err
&& fmsg
->putting_binary
)
681 static void devlink_fmsg_nest_common(struct devlink_fmsg
*fmsg
, int attrtype
)
683 struct devlink_fmsg_item
*item
;
688 item
= kzalloc(sizeof(*item
), GFP_KERNEL
);
694 item
->attrtype
= attrtype
;
695 list_add_tail(&item
->list
, &fmsg
->item_list
);
698 void devlink_fmsg_obj_nest_start(struct devlink_fmsg
*fmsg
)
700 devlink_fmsg_err_if_binary(fmsg
);
701 devlink_fmsg_nest_common(fmsg
, DEVLINK_ATTR_FMSG_OBJ_NEST_START
);
703 EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start
);
705 static void devlink_fmsg_nest_end(struct devlink_fmsg
*fmsg
)
707 devlink_fmsg_err_if_binary(fmsg
);
708 devlink_fmsg_nest_common(fmsg
, DEVLINK_ATTR_FMSG_NEST_END
);
711 void devlink_fmsg_obj_nest_end(struct devlink_fmsg
*fmsg
)
713 devlink_fmsg_nest_end(fmsg
);
715 EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end
);
717 #define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
719 static void devlink_fmsg_put_name(struct devlink_fmsg
*fmsg
, const char *name
)
721 struct devlink_fmsg_item
*item
;
723 devlink_fmsg_err_if_binary(fmsg
);
727 if (strlen(name
) + 1 > DEVLINK_FMSG_MAX_SIZE
) {
728 fmsg
->err
= -EMSGSIZE
;
732 item
= kzalloc(sizeof(*item
) + strlen(name
) + 1, GFP_KERNEL
);
738 item
->nla_type
= NLA_NUL_STRING
;
739 item
->len
= strlen(name
) + 1;
740 item
->attrtype
= DEVLINK_ATTR_FMSG_OBJ_NAME
;
741 memcpy(&item
->value
, name
, item
->len
);
742 list_add_tail(&item
->list
, &fmsg
->item_list
);
745 void devlink_fmsg_pair_nest_start(struct devlink_fmsg
*fmsg
, const char *name
)
747 devlink_fmsg_err_if_binary(fmsg
);
748 devlink_fmsg_nest_common(fmsg
, DEVLINK_ATTR_FMSG_PAIR_NEST_START
);
749 devlink_fmsg_put_name(fmsg
, name
);
751 EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start
);
753 void devlink_fmsg_pair_nest_end(struct devlink_fmsg
*fmsg
)
755 devlink_fmsg_nest_end(fmsg
);
757 EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end
);
759 void devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg
*fmsg
,
762 devlink_fmsg_pair_nest_start(fmsg
, name
);
763 devlink_fmsg_nest_common(fmsg
, DEVLINK_ATTR_FMSG_ARR_NEST_START
);
765 EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start
);
767 void devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg
*fmsg
)
769 devlink_fmsg_nest_end(fmsg
);
770 devlink_fmsg_nest_end(fmsg
);
772 EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end
);
774 void devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg
*fmsg
,
777 devlink_fmsg_arr_pair_nest_start(fmsg
, name
);
778 fmsg
->putting_binary
= true;
780 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start
);
782 void devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg
*fmsg
)
787 if (!fmsg
->putting_binary
)
790 fmsg
->putting_binary
= false;
791 devlink_fmsg_arr_pair_nest_end(fmsg
);
793 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end
);
795 static void devlink_fmsg_put_value(struct devlink_fmsg
*fmsg
,
796 const void *value
, u16 value_len
,
799 struct devlink_fmsg_item
*item
;
804 if (value_len
> DEVLINK_FMSG_MAX_SIZE
) {
805 fmsg
->err
= -EMSGSIZE
;
809 item
= kzalloc(sizeof(*item
) + value_len
, GFP_KERNEL
);
815 item
->nla_type
= value_nla_type
;
816 item
->len
= value_len
;
817 item
->attrtype
= DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA
;
818 memcpy(&item
->value
, value
, item
->len
);
819 list_add_tail(&item
->list
, &fmsg
->item_list
);
822 static void devlink_fmsg_bool_put(struct devlink_fmsg
*fmsg
, bool value
)
824 devlink_fmsg_err_if_binary(fmsg
);
825 devlink_fmsg_put_value(fmsg
, &value
, sizeof(value
), NLA_FLAG
);
828 static void devlink_fmsg_u8_put(struct devlink_fmsg
*fmsg
, u8 value
)
830 devlink_fmsg_err_if_binary(fmsg
);
831 devlink_fmsg_put_value(fmsg
, &value
, sizeof(value
), NLA_U8
);
834 void devlink_fmsg_u32_put(struct devlink_fmsg
*fmsg
, u32 value
)
836 devlink_fmsg_err_if_binary(fmsg
);
837 devlink_fmsg_put_value(fmsg
, &value
, sizeof(value
), NLA_U32
);
839 EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put
);
841 static void devlink_fmsg_u64_put(struct devlink_fmsg
*fmsg
, u64 value
)
843 devlink_fmsg_err_if_binary(fmsg
);
844 devlink_fmsg_put_value(fmsg
, &value
, sizeof(value
), NLA_U64
);
847 void devlink_fmsg_string_put(struct devlink_fmsg
*fmsg
, const char *value
)
849 devlink_fmsg_err_if_binary(fmsg
);
850 devlink_fmsg_put_value(fmsg
, value
, strlen(value
) + 1, NLA_NUL_STRING
);
852 EXPORT_SYMBOL_GPL(devlink_fmsg_string_put
);
854 void devlink_fmsg_binary_put(struct devlink_fmsg
*fmsg
, const void *value
,
857 if (!fmsg
->err
&& !fmsg
->putting_binary
)
860 devlink_fmsg_put_value(fmsg
, value
, value_len
, NLA_BINARY
);
862 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put
);
864 void devlink_fmsg_bool_pair_put(struct devlink_fmsg
*fmsg
, const char *name
,
867 devlink_fmsg_pair_nest_start(fmsg
, name
);
868 devlink_fmsg_bool_put(fmsg
, value
);
869 devlink_fmsg_pair_nest_end(fmsg
);
871 EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put
);
873 void devlink_fmsg_u8_pair_put(struct devlink_fmsg
*fmsg
, const char *name
,
876 devlink_fmsg_pair_nest_start(fmsg
, name
);
877 devlink_fmsg_u8_put(fmsg
, value
);
878 devlink_fmsg_pair_nest_end(fmsg
);
880 EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put
);
882 void devlink_fmsg_u32_pair_put(struct devlink_fmsg
*fmsg
, const char *name
,
885 devlink_fmsg_pair_nest_start(fmsg
, name
);
886 devlink_fmsg_u32_put(fmsg
, value
);
887 devlink_fmsg_pair_nest_end(fmsg
);
889 EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put
);
891 void devlink_fmsg_u64_pair_put(struct devlink_fmsg
*fmsg
, const char *name
,
894 devlink_fmsg_pair_nest_start(fmsg
, name
);
895 devlink_fmsg_u64_put(fmsg
, value
);
896 devlink_fmsg_pair_nest_end(fmsg
);
898 EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put
);
900 void devlink_fmsg_string_pair_put(struct devlink_fmsg
*fmsg
, const char *name
,
903 devlink_fmsg_pair_nest_start(fmsg
, name
);
904 devlink_fmsg_string_put(fmsg
, value
);
905 devlink_fmsg_pair_nest_end(fmsg
);
907 EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put
);
909 void devlink_fmsg_binary_pair_put(struct devlink_fmsg
*fmsg
, const char *name
,
910 const void *value
, u32 value_len
)
915 devlink_fmsg_binary_pair_nest_start(fmsg
, name
);
917 for (offset
= 0; offset
< value_len
; offset
+= data_size
) {
918 data_size
= value_len
- offset
;
919 if (data_size
> DEVLINK_FMSG_MAX_SIZE
)
920 data_size
= DEVLINK_FMSG_MAX_SIZE
;
922 devlink_fmsg_binary_put(fmsg
, value
+ offset
, data_size
);
925 devlink_fmsg_binary_pair_nest_end(fmsg
);
926 fmsg
->putting_binary
= false;
928 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put
);
931 devlink_fmsg_item_fill_type(struct devlink_fmsg_item
*msg
, struct sk_buff
*skb
)
933 switch (msg
->nla_type
) {
940 return nla_put_u8(skb
, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE
,
948 devlink_fmsg_item_fill_data(struct devlink_fmsg_item
*msg
, struct sk_buff
*skb
)
950 int attrtype
= DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA
;
953 switch (msg
->nla_type
) {
955 /* Always provide flag data, regardless of its value */
956 tmp
= *(bool *)msg
->value
;
958 return nla_put_u8(skb
, attrtype
, tmp
);
960 return nla_put_u8(skb
, attrtype
, *(u8
*)msg
->value
);
962 return nla_put_u32(skb
, attrtype
, *(u32
*)msg
->value
);
964 return devlink_nl_put_u64(skb
, attrtype
, *(u64
*)msg
->value
);
966 return nla_put_string(skb
, attrtype
, (char *)&msg
->value
);
968 return nla_put(skb
, attrtype
, msg
->len
, (void *)&msg
->value
);
975 devlink_fmsg_prepare_skb(struct devlink_fmsg
*fmsg
, struct sk_buff
*skb
,
978 struct devlink_fmsg_item
*item
;
979 struct nlattr
*fmsg_nlattr
;
983 fmsg_nlattr
= nla_nest_start_noflag(skb
, DEVLINK_ATTR_FMSG
);
987 list_for_each_entry(item
, &fmsg
->item_list
, list
) {
993 switch (item
->attrtype
) {
994 case DEVLINK_ATTR_FMSG_OBJ_NEST_START
:
995 case DEVLINK_ATTR_FMSG_PAIR_NEST_START
:
996 case DEVLINK_ATTR_FMSG_ARR_NEST_START
:
997 case DEVLINK_ATTR_FMSG_NEST_END
:
998 err
= nla_put_flag(skb
, item
->attrtype
);
1000 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA
:
1001 err
= devlink_fmsg_item_fill_type(item
, skb
);
1004 err
= devlink_fmsg_item_fill_data(item
, skb
);
1006 case DEVLINK_ATTR_FMSG_OBJ_NAME
:
1007 err
= nla_put_string(skb
, item
->attrtype
,
1008 (char *)&item
->value
);
1020 nla_nest_end(skb
, fmsg_nlattr
);
1024 static int devlink_fmsg_snd(struct devlink_fmsg
*fmsg
,
1025 struct genl_info
*info
,
1026 enum devlink_command cmd
, int flags
)
1028 struct nlmsghdr
*nlh
;
1029 struct sk_buff
*skb
;
1039 int tmp_index
= index
;
1041 skb
= genlmsg_new(GENLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
1045 hdr
= genlmsg_put(skb
, info
->snd_portid
, info
->snd_seq
,
1046 &devlink_nl_family
, flags
| NLM_F_MULTI
, cmd
);
1049 goto nla_put_failure
;
1052 err
= devlink_fmsg_prepare_skb(fmsg
, skb
, &index
);
1055 else if (err
!= -EMSGSIZE
|| tmp_index
== index
)
1056 goto nla_put_failure
;
1058 genlmsg_end(skb
, hdr
);
1059 err
= genlmsg_reply(skb
, info
);
1064 skb
= genlmsg_new(GENLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
1067 nlh
= nlmsg_put(skb
, info
->snd_portid
, info
->snd_seq
,
1068 NLMSG_DONE
, 0, flags
| NLM_F_MULTI
);
1071 goto nla_put_failure
;
1074 return genlmsg_reply(skb
, info
);
1081 static int devlink_fmsg_dumpit(struct devlink_fmsg
*fmsg
, struct sk_buff
*skb
,
1082 struct netlink_callback
*cb
,
1083 enum devlink_command cmd
)
1085 struct devlink_nl_dump_state
*state
= devlink_dump_state(cb
);
1086 int index
= state
->idx
;
1087 int tmp_index
= index
;
1094 hdr
= genlmsg_put(skb
, NETLINK_CB(cb
->skb
).portid
, cb
->nlh
->nlmsg_seq
,
1095 &devlink_nl_family
, NLM_F_ACK
| NLM_F_MULTI
, cmd
);
1098 goto nla_put_failure
;
1101 err
= devlink_fmsg_prepare_skb(fmsg
, skb
, &index
);
1102 if ((err
&& err
!= -EMSGSIZE
) || tmp_index
== index
)
1103 goto nla_put_failure
;
1106 genlmsg_end(skb
, hdr
);
1110 genlmsg_cancel(skb
, hdr
);
1114 int devlink_nl_health_reporter_diagnose_doit(struct sk_buff
*skb
,
1115 struct genl_info
*info
)
1117 struct devlink
*devlink
= info
->user_ptr
[0];
1118 struct devlink_health_reporter
*reporter
;
1119 struct devlink_fmsg
*fmsg
;
1122 reporter
= devlink_health_reporter_get_from_info(devlink
, info
);
1126 if (!reporter
->ops
->diagnose
)
1129 fmsg
= devlink_fmsg_alloc();
1133 devlink_fmsg_obj_nest_start(fmsg
);
1135 err
= reporter
->ops
->diagnose(reporter
, fmsg
, info
->extack
);
1139 devlink_fmsg_obj_nest_end(fmsg
);
1141 err
= devlink_fmsg_snd(fmsg
, info
,
1142 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE
, 0);
1145 devlink_fmsg_free(fmsg
);
1149 static struct devlink_health_reporter
*
1150 devlink_health_reporter_get_from_cb_lock(struct netlink_callback
*cb
)
1152 const struct genl_info
*info
= genl_info_dump(cb
);
1153 struct devlink_health_reporter
*reporter
;
1154 struct nlattr
**attrs
= info
->attrs
;
1155 struct devlink
*devlink
;
1157 devlink
= devlink_get_from_attrs_lock(sock_net(cb
->skb
->sk
), attrs
,
1159 if (IS_ERR(devlink
))
1162 reporter
= devlink_health_reporter_get_from_attrs(devlink
, attrs
);
1164 devl_unlock(devlink
);
1165 devlink_put(devlink
);
1170 int devlink_nl_health_reporter_dump_get_dumpit(struct sk_buff
*skb
,
1171 struct netlink_callback
*cb
)
1173 struct devlink_nl_dump_state
*state
= devlink_dump_state(cb
);
1174 struct devlink_health_reporter
*reporter
;
1175 struct devlink
*devlink
;
1178 reporter
= devlink_health_reporter_get_from_cb_lock(cb
);
1182 devlink
= reporter
->devlink
;
1183 if (!reporter
->ops
->dump
) {
1184 devl_unlock(devlink
);
1185 devlink_put(devlink
);
1190 err
= devlink_health_do_dump(reporter
, NULL
, cb
->extack
);
1193 state
->dump_ts
= reporter
->dump_ts
;
1195 if (!reporter
->dump_fmsg
|| state
->dump_ts
!= reporter
->dump_ts
) {
1196 NL_SET_ERR_MSG(cb
->extack
, "Dump trampled, please retry");
1201 err
= devlink_fmsg_dumpit(reporter
->dump_fmsg
, skb
, cb
,
1202 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET
);
1204 devl_unlock(devlink
);
1205 devlink_put(devlink
);
1209 int devlink_nl_health_reporter_dump_clear_doit(struct sk_buff
*skb
,
1210 struct genl_info
*info
)
1212 struct devlink
*devlink
= info
->user_ptr
[0];
1213 struct devlink_health_reporter
*reporter
;
1215 reporter
= devlink_health_reporter_get_from_info(devlink
, info
);
1219 if (!reporter
->ops
->dump
)
1222 devlink_health_dump_clear(reporter
);
1226 int devlink_nl_health_reporter_test_doit(struct sk_buff
*skb
,
1227 struct genl_info
*info
)
1229 struct devlink
*devlink
= info
->user_ptr
[0];
1230 struct devlink_health_reporter
*reporter
;
1232 reporter
= devlink_health_reporter_get_from_info(devlink
, info
);
1236 if (!reporter
->ops
->test
)
1239 return reporter
->ops
->test(reporter
, info
->extack
);