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 bool putting_binary
; /* This flag forces enclosing of binary data
23 * in an array brackets. It forces using
25 * devlink_fmsg_binary_pair_nest_start()
26 * devlink_fmsg_binary_pair_nest_end()
30 static struct devlink_fmsg
*devlink_fmsg_alloc(void)
32 struct devlink_fmsg
*fmsg
;
34 fmsg
= kzalloc(sizeof(*fmsg
), GFP_KERNEL
);
38 INIT_LIST_HEAD(&fmsg
->item_list
);
43 static void devlink_fmsg_free(struct devlink_fmsg
*fmsg
)
45 struct devlink_fmsg_item
*item
, *tmp
;
47 list_for_each_entry_safe(item
, tmp
, &fmsg
->item_list
, list
) {
48 list_del(&item
->list
);
54 struct devlink_health_reporter
{
55 struct list_head list
;
57 const struct devlink_health_reporter_ops
*ops
;
58 struct devlink
*devlink
;
59 struct devlink_port
*devlink_port
;
60 struct devlink_fmsg
*dump_fmsg
;
73 devlink_health_reporter_priv(struct devlink_health_reporter
*reporter
)
75 return reporter
->priv
;
77 EXPORT_SYMBOL_GPL(devlink_health_reporter_priv
);
79 static struct devlink_health_reporter
*
80 __devlink_health_reporter_find_by_name(struct list_head
*reporter_list
,
81 const char *reporter_name
)
83 struct devlink_health_reporter
*reporter
;
85 list_for_each_entry(reporter
, reporter_list
, list
)
86 if (!strcmp(reporter
->ops
->name
, reporter_name
))
91 static struct devlink_health_reporter
*
92 devlink_health_reporter_find_by_name(struct devlink
*devlink
,
93 const char *reporter_name
)
95 return __devlink_health_reporter_find_by_name(&devlink
->reporter_list
,
99 static struct devlink_health_reporter
*
100 devlink_port_health_reporter_find_by_name(struct devlink_port
*devlink_port
,
101 const char *reporter_name
)
103 return __devlink_health_reporter_find_by_name(&devlink_port
->reporter_list
,
107 static struct devlink_health_reporter
*
108 __devlink_health_reporter_create(struct devlink
*devlink
,
109 const struct devlink_health_reporter_ops
*ops
,
110 u64 graceful_period
, void *priv
)
112 struct devlink_health_reporter
*reporter
;
114 if (WARN_ON(graceful_period
&& !ops
->recover
))
115 return ERR_PTR(-EINVAL
);
117 reporter
= kzalloc(sizeof(*reporter
), GFP_KERNEL
);
119 return ERR_PTR(-ENOMEM
);
121 reporter
->priv
= priv
;
123 reporter
->devlink
= devlink
;
124 reporter
->graceful_period
= graceful_period
;
125 reporter
->auto_recover
= !!ops
->recover
;
126 reporter
->auto_dump
= !!ops
->dump
;
131 * devl_port_health_reporter_create() - create devlink health reporter for
132 * specified port instance
134 * @port: devlink_port to which health reports will relate
135 * @ops: devlink health reporter ops
136 * @graceful_period: min time (in msec) between recovery attempts
137 * @priv: driver priv pointer
139 struct devlink_health_reporter
*
140 devl_port_health_reporter_create(struct devlink_port
*port
,
141 const struct devlink_health_reporter_ops
*ops
,
142 u64 graceful_period
, void *priv
)
144 struct devlink_health_reporter
*reporter
;
146 devl_assert_locked(port
->devlink
);
148 if (__devlink_health_reporter_find_by_name(&port
->reporter_list
,
150 return ERR_PTR(-EEXIST
);
152 reporter
= __devlink_health_reporter_create(port
->devlink
, ops
,
153 graceful_period
, priv
);
154 if (IS_ERR(reporter
))
157 reporter
->devlink_port
= port
;
158 list_add_tail(&reporter
->list
, &port
->reporter_list
);
161 EXPORT_SYMBOL_GPL(devl_port_health_reporter_create
);
163 struct devlink_health_reporter
*
164 devlink_port_health_reporter_create(struct devlink_port
*port
,
165 const struct devlink_health_reporter_ops
*ops
,
166 u64 graceful_period
, void *priv
)
168 struct devlink_health_reporter
*reporter
;
169 struct devlink
*devlink
= port
->devlink
;
172 reporter
= devl_port_health_reporter_create(port
, ops
,
173 graceful_period
, priv
);
174 devl_unlock(devlink
);
177 EXPORT_SYMBOL_GPL(devlink_port_health_reporter_create
);
180 * devl_health_reporter_create - create devlink health reporter
182 * @devlink: devlink instance which the health reports will relate
183 * @ops: devlink health reporter ops
184 * @graceful_period: min time (in msec) between recovery attempts
185 * @priv: driver priv pointer
187 struct devlink_health_reporter
*
188 devl_health_reporter_create(struct devlink
*devlink
,
189 const struct devlink_health_reporter_ops
*ops
,
190 u64 graceful_period
, void *priv
)
192 struct devlink_health_reporter
*reporter
;
194 devl_assert_locked(devlink
);
196 if (devlink_health_reporter_find_by_name(devlink
, ops
->name
))
197 return ERR_PTR(-EEXIST
);
199 reporter
= __devlink_health_reporter_create(devlink
, ops
,
200 graceful_period
, priv
);
201 if (IS_ERR(reporter
))
204 list_add_tail(&reporter
->list
, &devlink
->reporter_list
);
207 EXPORT_SYMBOL_GPL(devl_health_reporter_create
);
209 struct devlink_health_reporter
*
210 devlink_health_reporter_create(struct devlink
*devlink
,
211 const struct devlink_health_reporter_ops
*ops
,
212 u64 graceful_period
, void *priv
)
214 struct devlink_health_reporter
*reporter
;
217 reporter
= devl_health_reporter_create(devlink
, ops
,
218 graceful_period
, priv
);
219 devl_unlock(devlink
);
222 EXPORT_SYMBOL_GPL(devlink_health_reporter_create
);
225 devlink_health_reporter_free(struct devlink_health_reporter
*reporter
)
227 if (reporter
->dump_fmsg
)
228 devlink_fmsg_free(reporter
->dump_fmsg
);
233 * devl_health_reporter_destroy() - destroy devlink health reporter
235 * @reporter: devlink health reporter to destroy
238 devl_health_reporter_destroy(struct devlink_health_reporter
*reporter
)
240 devl_assert_locked(reporter
->devlink
);
242 list_del(&reporter
->list
);
243 devlink_health_reporter_free(reporter
);
245 EXPORT_SYMBOL_GPL(devl_health_reporter_destroy
);
248 devlink_health_reporter_destroy(struct devlink_health_reporter
*reporter
)
250 struct devlink
*devlink
= reporter
->devlink
;
253 devl_health_reporter_destroy(reporter
);
254 devl_unlock(devlink
);
256 EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy
);
259 devlink_nl_health_reporter_fill(struct sk_buff
*msg
,
260 struct devlink_health_reporter
*reporter
,
261 enum devlink_command cmd
, u32 portid
,
264 struct devlink
*devlink
= reporter
->devlink
;
265 struct nlattr
*reporter_attr
;
268 hdr
= genlmsg_put(msg
, portid
, seq
, &devlink_nl_family
, flags
, cmd
);
272 if (devlink_nl_put_handle(msg
, devlink
))
275 if (reporter
->devlink_port
) {
276 if (nla_put_u32(msg
, DEVLINK_ATTR_PORT_INDEX
, reporter
->devlink_port
->index
))
279 reporter_attr
= nla_nest_start_noflag(msg
,
280 DEVLINK_ATTR_HEALTH_REPORTER
);
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 (nla_put_u64_64bit(msg
, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
,
290 reporter
->error_count
, DEVLINK_ATTR_PAD
))
291 goto reporter_nest_cancel
;
292 if (nla_put_u64_64bit(msg
, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
,
293 reporter
->recovery_count
, DEVLINK_ATTR_PAD
))
294 goto reporter_nest_cancel
;
295 if (reporter
->ops
->recover
&&
296 nla_put_u64_64bit(msg
, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
,
297 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 nla_put_u64_64bit(msg
, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
,
306 jiffies_to_msecs(reporter
->dump_ts
),
308 goto reporter_nest_cancel
;
309 if (reporter
->dump_fmsg
&&
310 nla_put_u64_64bit(msg
, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS
,
311 reporter
->dump_real_ts
, DEVLINK_ATTR_PAD
))
312 goto reporter_nest_cancel
;
313 if (reporter
->ops
->dump
&&
314 nla_put_u8(msg
, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
,
315 reporter
->auto_dump
))
316 goto reporter_nest_cancel
;
318 nla_nest_end(msg
, reporter_attr
);
319 genlmsg_end(msg
, hdr
);
322 reporter_nest_cancel
:
323 nla_nest_cancel(msg
, reporter_attr
);
325 genlmsg_cancel(msg
, hdr
);
329 static struct devlink_health_reporter
*
330 devlink_health_reporter_get_from_attrs(struct devlink
*devlink
,
331 struct nlattr
**attrs
)
333 struct devlink_port
*devlink_port
;
336 if (!attrs
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
])
339 reporter_name
= nla_data(attrs
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
]);
340 devlink_port
= devlink_port_get_from_attrs(devlink
, attrs
);
341 if (IS_ERR(devlink_port
))
342 return devlink_health_reporter_find_by_name(devlink
,
345 return devlink_port_health_reporter_find_by_name(devlink_port
,
349 static struct devlink_health_reporter
*
350 devlink_health_reporter_get_from_info(struct devlink
*devlink
,
351 struct genl_info
*info
)
353 return devlink_health_reporter_get_from_attrs(devlink
, info
->attrs
);
356 int devlink_nl_health_reporter_get_doit(struct sk_buff
*skb
,
357 struct genl_info
*info
)
359 struct devlink
*devlink
= info
->user_ptr
[0];
360 struct devlink_health_reporter
*reporter
;
364 reporter
= devlink_health_reporter_get_from_info(devlink
, info
);
368 msg
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
372 err
= devlink_nl_health_reporter_fill(msg
, reporter
,
373 DEVLINK_CMD_HEALTH_REPORTER_GET
,
374 info
->snd_portid
, info
->snd_seq
,
381 return genlmsg_reply(msg
, info
);
384 static int devlink_nl_health_reporter_get_dump_one(struct sk_buff
*msg
,
385 struct devlink
*devlink
,
386 struct netlink_callback
*cb
,
389 struct devlink_nl_dump_state
*state
= devlink_dump_state(cb
);
390 const struct genl_info
*info
= genl_info_dump(cb
);
391 struct devlink_health_reporter
*reporter
;
392 unsigned long port_index_end
= ULONG_MAX
;
393 struct nlattr
**attrs
= info
->attrs
;
394 unsigned long port_index_start
= 0;
395 struct devlink_port
*port
;
396 unsigned long port_index
;
400 if (attrs
&& attrs
[DEVLINK_ATTR_PORT_INDEX
]) {
401 port_index_start
= nla_get_u32(attrs
[DEVLINK_ATTR_PORT_INDEX
]);
402 port_index_end
= port_index_start
;
403 flags
|= NLM_F_DUMP_FILTERED
;
407 list_for_each_entry(reporter
, &devlink
->reporter_list
, list
) {
408 if (idx
< state
->idx
) {
412 err
= devlink_nl_health_reporter_fill(msg
, reporter
,
413 DEVLINK_CMD_HEALTH_REPORTER_GET
,
414 NETLINK_CB(cb
->skb
).portid
,
424 xa_for_each_range(&devlink
->ports
, port_index
, port
,
425 port_index_start
, port_index_end
) {
426 list_for_each_entry(reporter
, &port
->reporter_list
, list
) {
427 if (idx
< state
->idx
) {
431 err
= devlink_nl_health_reporter_fill(msg
, reporter
,
432 DEVLINK_CMD_HEALTH_REPORTER_GET
,
433 NETLINK_CB(cb
->skb
).portid
,
447 int devlink_nl_health_reporter_get_dumpit(struct sk_buff
*skb
,
448 struct netlink_callback
*cb
)
450 return devlink_nl_dumpit(skb
, cb
,
451 devlink_nl_health_reporter_get_dump_one
);
454 int devlink_nl_cmd_health_reporter_set_doit(struct sk_buff
*skb
,
455 struct genl_info
*info
)
457 struct devlink
*devlink
= info
->user_ptr
[0];
458 struct devlink_health_reporter
*reporter
;
460 reporter
= devlink_health_reporter_get_from_info(devlink
, info
);
464 if (!reporter
->ops
->recover
&&
465 (info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
] ||
466 info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
]))
469 if (!reporter
->ops
->dump
&&
470 info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
])
473 if (info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
])
474 reporter
->graceful_period
=
475 nla_get_u64(info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
]);
477 if (info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
])
478 reporter
->auto_recover
=
479 nla_get_u8(info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
]);
481 if (info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
])
482 reporter
->auto_dump
=
483 nla_get_u8(info
->attrs
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
]);
488 static void devlink_recover_notify(struct devlink_health_reporter
*reporter
,
489 enum devlink_command cmd
)
491 struct devlink
*devlink
= reporter
->devlink
;
495 WARN_ON(cmd
!= DEVLINK_CMD_HEALTH_REPORTER_RECOVER
);
496 ASSERT_DEVLINK_REGISTERED(devlink
);
498 msg
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
502 err
= devlink_nl_health_reporter_fill(msg
, reporter
, cmd
, 0, 0, 0);
508 genlmsg_multicast_netns(&devlink_nl_family
, devlink_net(devlink
), msg
,
509 0, DEVLINK_MCGRP_CONFIG
, GFP_KERNEL
);
513 devlink_health_reporter_recovery_done(struct devlink_health_reporter
*reporter
)
515 reporter
->recovery_count
++;
516 reporter
->last_recovery_ts
= jiffies
;
518 EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done
);
521 devlink_health_reporter_recover(struct devlink_health_reporter
*reporter
,
522 void *priv_ctx
, struct netlink_ext_ack
*extack
)
526 if (reporter
->health_state
== DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
)
529 if (!reporter
->ops
->recover
)
532 err
= reporter
->ops
->recover(reporter
, priv_ctx
, extack
);
536 devlink_health_reporter_recovery_done(reporter
);
537 reporter
->health_state
= DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
;
538 devlink_recover_notify(reporter
, DEVLINK_CMD_HEALTH_REPORTER_RECOVER
);
544 devlink_health_dump_clear(struct devlink_health_reporter
*reporter
)
546 if (!reporter
->dump_fmsg
)
548 devlink_fmsg_free(reporter
->dump_fmsg
);
549 reporter
->dump_fmsg
= NULL
;
552 static int devlink_health_do_dump(struct devlink_health_reporter
*reporter
,
554 struct netlink_ext_ack
*extack
)
558 if (!reporter
->ops
->dump
)
561 if (reporter
->dump_fmsg
)
564 reporter
->dump_fmsg
= devlink_fmsg_alloc();
565 if (!reporter
->dump_fmsg
) {
570 err
= devlink_fmsg_obj_nest_start(reporter
->dump_fmsg
);
574 err
= reporter
->ops
->dump(reporter
, reporter
->dump_fmsg
,
579 err
= devlink_fmsg_obj_nest_end(reporter
->dump_fmsg
);
583 reporter
->dump_ts
= jiffies
;
584 reporter
->dump_real_ts
= ktime_get_real_ns();
589 devlink_health_dump_clear(reporter
);
593 int devlink_health_report(struct devlink_health_reporter
*reporter
,
594 const char *msg
, void *priv_ctx
)
596 enum devlink_health_reporter_state prev_health_state
;
597 struct devlink
*devlink
= reporter
->devlink
;
598 unsigned long recover_ts_threshold
;
601 /* write a log message of the current error */
603 trace_devlink_health_report(devlink
, reporter
->ops
->name
, msg
);
604 reporter
->error_count
++;
605 prev_health_state
= reporter
->health_state
;
606 reporter
->health_state
= DEVLINK_HEALTH_REPORTER_STATE_ERROR
;
607 devlink_recover_notify(reporter
, DEVLINK_CMD_HEALTH_REPORTER_RECOVER
);
609 /* abort if the previous error wasn't recovered */
610 recover_ts_threshold
= reporter
->last_recovery_ts
+
611 msecs_to_jiffies(reporter
->graceful_period
);
612 if (reporter
->auto_recover
&&
613 (prev_health_state
!= DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
||
614 (reporter
->last_recovery_ts
&& reporter
->recovery_count
&&
615 time_is_after_jiffies(recover_ts_threshold
)))) {
616 trace_devlink_health_recover_aborted(devlink
,
618 reporter
->health_state
,
620 reporter
->last_recovery_ts
);
624 if (reporter
->auto_dump
) {
626 /* store current dump of current error, for later analysis */
627 devlink_health_do_dump(reporter
, priv_ctx
, NULL
);
628 devl_unlock(devlink
);
631 if (!reporter
->auto_recover
)
635 ret
= devlink_health_reporter_recover(reporter
, priv_ctx
, NULL
);
636 devl_unlock(devlink
);
640 EXPORT_SYMBOL_GPL(devlink_health_report
);
643 devlink_health_reporter_state_update(struct devlink_health_reporter
*reporter
,
644 enum devlink_health_reporter_state state
)
646 if (WARN_ON(state
!= DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
&&
647 state
!= DEVLINK_HEALTH_REPORTER_STATE_ERROR
))
650 if (reporter
->health_state
== state
)
653 reporter
->health_state
= state
;
654 trace_devlink_health_reporter_state_update(reporter
->devlink
,
655 reporter
->ops
->name
, state
);
656 devlink_recover_notify(reporter
, DEVLINK_CMD_HEALTH_REPORTER_RECOVER
);
658 EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update
);
660 int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff
*skb
,
661 struct genl_info
*info
)
663 struct devlink
*devlink
= info
->user_ptr
[0];
664 struct devlink_health_reporter
*reporter
;
666 reporter
= devlink_health_reporter_get_from_info(devlink
, info
);
670 return devlink_health_reporter_recover(reporter
, NULL
, info
->extack
);
673 static int devlink_fmsg_nest_common(struct devlink_fmsg
*fmsg
,
676 struct devlink_fmsg_item
*item
;
678 item
= kzalloc(sizeof(*item
), GFP_KERNEL
);
682 item
->attrtype
= attrtype
;
683 list_add_tail(&item
->list
, &fmsg
->item_list
);
688 int devlink_fmsg_obj_nest_start(struct devlink_fmsg
*fmsg
)
690 if (fmsg
->putting_binary
)
693 return devlink_fmsg_nest_common(fmsg
, DEVLINK_ATTR_FMSG_OBJ_NEST_START
);
695 EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start
);
697 static int devlink_fmsg_nest_end(struct devlink_fmsg
*fmsg
)
699 if (fmsg
->putting_binary
)
702 return devlink_fmsg_nest_common(fmsg
, DEVLINK_ATTR_FMSG_NEST_END
);
705 int devlink_fmsg_obj_nest_end(struct devlink_fmsg
*fmsg
)
707 if (fmsg
->putting_binary
)
710 return devlink_fmsg_nest_end(fmsg
);
712 EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end
);
714 #define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
716 static int devlink_fmsg_put_name(struct devlink_fmsg
*fmsg
, const char *name
)
718 struct devlink_fmsg_item
*item
;
720 if (fmsg
->putting_binary
)
723 if (strlen(name
) + 1 > DEVLINK_FMSG_MAX_SIZE
)
726 item
= kzalloc(sizeof(*item
) + strlen(name
) + 1, GFP_KERNEL
);
730 item
->nla_type
= NLA_NUL_STRING
;
731 item
->len
= strlen(name
) + 1;
732 item
->attrtype
= DEVLINK_ATTR_FMSG_OBJ_NAME
;
733 memcpy(&item
->value
, name
, item
->len
);
734 list_add_tail(&item
->list
, &fmsg
->item_list
);
739 int devlink_fmsg_pair_nest_start(struct devlink_fmsg
*fmsg
, const char *name
)
743 if (fmsg
->putting_binary
)
746 err
= devlink_fmsg_nest_common(fmsg
, DEVLINK_ATTR_FMSG_PAIR_NEST_START
);
750 err
= devlink_fmsg_put_name(fmsg
, name
);
756 EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start
);
758 int devlink_fmsg_pair_nest_end(struct devlink_fmsg
*fmsg
)
760 if (fmsg
->putting_binary
)
763 return devlink_fmsg_nest_end(fmsg
);
765 EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end
);
767 int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg
*fmsg
,
772 if (fmsg
->putting_binary
)
775 err
= devlink_fmsg_pair_nest_start(fmsg
, name
);
779 err
= devlink_fmsg_nest_common(fmsg
, DEVLINK_ATTR_FMSG_ARR_NEST_START
);
785 EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start
);
787 int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg
*fmsg
)
791 if (fmsg
->putting_binary
)
794 err
= devlink_fmsg_nest_end(fmsg
);
798 err
= devlink_fmsg_nest_end(fmsg
);
804 EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end
);
806 int devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg
*fmsg
,
811 err
= devlink_fmsg_arr_pair_nest_start(fmsg
, name
);
815 fmsg
->putting_binary
= true;
818 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start
);
820 int devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg
*fmsg
)
822 if (!fmsg
->putting_binary
)
825 fmsg
->putting_binary
= false;
826 return devlink_fmsg_arr_pair_nest_end(fmsg
);
828 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end
);
830 static int devlink_fmsg_put_value(struct devlink_fmsg
*fmsg
,
831 const void *value
, u16 value_len
,
834 struct devlink_fmsg_item
*item
;
836 if (value_len
> DEVLINK_FMSG_MAX_SIZE
)
839 item
= kzalloc(sizeof(*item
) + value_len
, GFP_KERNEL
);
843 item
->nla_type
= value_nla_type
;
844 item
->len
= value_len
;
845 item
->attrtype
= DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA
;
846 memcpy(&item
->value
, value
, item
->len
);
847 list_add_tail(&item
->list
, &fmsg
->item_list
);
852 static int devlink_fmsg_bool_put(struct devlink_fmsg
*fmsg
, bool value
)
854 if (fmsg
->putting_binary
)
857 return devlink_fmsg_put_value(fmsg
, &value
, sizeof(value
), NLA_FLAG
);
860 static int devlink_fmsg_u8_put(struct devlink_fmsg
*fmsg
, u8 value
)
862 if (fmsg
->putting_binary
)
865 return devlink_fmsg_put_value(fmsg
, &value
, sizeof(value
), NLA_U8
);
868 int devlink_fmsg_u32_put(struct devlink_fmsg
*fmsg
, u32 value
)
870 if (fmsg
->putting_binary
)
873 return devlink_fmsg_put_value(fmsg
, &value
, sizeof(value
), NLA_U32
);
875 EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put
);
877 static int devlink_fmsg_u64_put(struct devlink_fmsg
*fmsg
, u64 value
)
879 if (fmsg
->putting_binary
)
882 return devlink_fmsg_put_value(fmsg
, &value
, sizeof(value
), NLA_U64
);
885 int devlink_fmsg_string_put(struct devlink_fmsg
*fmsg
, const char *value
)
887 if (fmsg
->putting_binary
)
890 return devlink_fmsg_put_value(fmsg
, value
, strlen(value
) + 1,
893 EXPORT_SYMBOL_GPL(devlink_fmsg_string_put
);
895 int devlink_fmsg_binary_put(struct devlink_fmsg
*fmsg
, const void *value
,
898 if (!fmsg
->putting_binary
)
901 return devlink_fmsg_put_value(fmsg
, value
, value_len
, NLA_BINARY
);
903 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put
);
905 int devlink_fmsg_bool_pair_put(struct devlink_fmsg
*fmsg
, const char *name
,
910 err
= devlink_fmsg_pair_nest_start(fmsg
, name
);
914 err
= devlink_fmsg_bool_put(fmsg
, value
);
918 err
= devlink_fmsg_pair_nest_end(fmsg
);
924 EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put
);
926 int devlink_fmsg_u8_pair_put(struct devlink_fmsg
*fmsg
, const char *name
,
931 err
= devlink_fmsg_pair_nest_start(fmsg
, name
);
935 err
= devlink_fmsg_u8_put(fmsg
, value
);
939 err
= devlink_fmsg_pair_nest_end(fmsg
);
945 EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put
);
947 int devlink_fmsg_u32_pair_put(struct devlink_fmsg
*fmsg
, const char *name
,
952 err
= devlink_fmsg_pair_nest_start(fmsg
, name
);
956 err
= devlink_fmsg_u32_put(fmsg
, value
);
960 err
= devlink_fmsg_pair_nest_end(fmsg
);
966 EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put
);
968 int devlink_fmsg_u64_pair_put(struct devlink_fmsg
*fmsg
, const char *name
,
973 err
= devlink_fmsg_pair_nest_start(fmsg
, name
);
977 err
= devlink_fmsg_u64_put(fmsg
, value
);
981 err
= devlink_fmsg_pair_nest_end(fmsg
);
987 EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put
);
989 int devlink_fmsg_string_pair_put(struct devlink_fmsg
*fmsg
, const char *name
,
994 err
= devlink_fmsg_pair_nest_start(fmsg
, name
);
998 err
= devlink_fmsg_string_put(fmsg
, value
);
1002 err
= devlink_fmsg_pair_nest_end(fmsg
);
1008 EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put
);
1010 int devlink_fmsg_binary_pair_put(struct devlink_fmsg
*fmsg
, const char *name
,
1011 const void *value
, u32 value_len
)
1018 err
= devlink_fmsg_binary_pair_nest_start(fmsg
, name
);
1022 for (offset
= 0; offset
< value_len
; offset
+= data_size
) {
1023 data_size
= value_len
- offset
;
1024 if (data_size
> DEVLINK_FMSG_MAX_SIZE
)
1025 data_size
= DEVLINK_FMSG_MAX_SIZE
;
1026 err
= devlink_fmsg_binary_put(fmsg
, value
+ offset
, data_size
);
1029 /* Exit from loop with a break (instead of
1030 * return) to make sure putting_binary is turned off in
1031 * devlink_fmsg_binary_pair_nest_end
1035 end_err
= devlink_fmsg_binary_pair_nest_end(fmsg
);
1041 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put
);
1044 devlink_fmsg_item_fill_type(struct devlink_fmsg_item
*msg
, struct sk_buff
*skb
)
1046 switch (msg
->nla_type
) {
1051 case NLA_NUL_STRING
:
1053 return nla_put_u8(skb
, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE
,
1061 devlink_fmsg_item_fill_data(struct devlink_fmsg_item
*msg
, struct sk_buff
*skb
)
1063 int attrtype
= DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA
;
1066 switch (msg
->nla_type
) {
1068 /* Always provide flag data, regardless of its value */
1069 tmp
= *(bool *)msg
->value
;
1071 return nla_put_u8(skb
, attrtype
, tmp
);
1073 return nla_put_u8(skb
, attrtype
, *(u8
*)msg
->value
);
1075 return nla_put_u32(skb
, attrtype
, *(u32
*)msg
->value
);
1077 return nla_put_u64_64bit(skb
, attrtype
, *(u64
*)msg
->value
,
1079 case NLA_NUL_STRING
:
1080 return nla_put_string(skb
, attrtype
, (char *)&msg
->value
);
1082 return nla_put(skb
, attrtype
, msg
->len
, (void *)&msg
->value
);
1089 devlink_fmsg_prepare_skb(struct devlink_fmsg
*fmsg
, struct sk_buff
*skb
,
1092 struct devlink_fmsg_item
*item
;
1093 struct nlattr
*fmsg_nlattr
;
1097 fmsg_nlattr
= nla_nest_start_noflag(skb
, DEVLINK_ATTR_FMSG
);
1101 list_for_each_entry(item
, &fmsg
->item_list
, list
) {
1107 switch (item
->attrtype
) {
1108 case DEVLINK_ATTR_FMSG_OBJ_NEST_START
:
1109 case DEVLINK_ATTR_FMSG_PAIR_NEST_START
:
1110 case DEVLINK_ATTR_FMSG_ARR_NEST_START
:
1111 case DEVLINK_ATTR_FMSG_NEST_END
:
1112 err
= nla_put_flag(skb
, item
->attrtype
);
1114 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA
:
1115 err
= devlink_fmsg_item_fill_type(item
, skb
);
1118 err
= devlink_fmsg_item_fill_data(item
, skb
);
1120 case DEVLINK_ATTR_FMSG_OBJ_NAME
:
1121 err
= nla_put_string(skb
, item
->attrtype
,
1122 (char *)&item
->value
);
1134 nla_nest_end(skb
, fmsg_nlattr
);
1138 static int devlink_fmsg_snd(struct devlink_fmsg
*fmsg
,
1139 struct genl_info
*info
,
1140 enum devlink_command cmd
, int flags
)
1142 struct nlmsghdr
*nlh
;
1143 struct sk_buff
*skb
;
1150 int tmp_index
= index
;
1152 skb
= genlmsg_new(GENLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
1156 hdr
= genlmsg_put(skb
, info
->snd_portid
, info
->snd_seq
,
1157 &devlink_nl_family
, flags
| NLM_F_MULTI
, cmd
);
1160 goto nla_put_failure
;
1163 err
= devlink_fmsg_prepare_skb(fmsg
, skb
, &index
);
1166 else if (err
!= -EMSGSIZE
|| tmp_index
== index
)
1167 goto nla_put_failure
;
1169 genlmsg_end(skb
, hdr
);
1170 err
= genlmsg_reply(skb
, info
);
1175 skb
= genlmsg_new(GENLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
1178 nlh
= nlmsg_put(skb
, info
->snd_portid
, info
->snd_seq
,
1179 NLMSG_DONE
, 0, flags
| NLM_F_MULTI
);
1182 goto nla_put_failure
;
1185 return genlmsg_reply(skb
, info
);
1192 static int devlink_fmsg_dumpit(struct devlink_fmsg
*fmsg
, struct sk_buff
*skb
,
1193 struct netlink_callback
*cb
,
1194 enum devlink_command cmd
)
1196 struct devlink_nl_dump_state
*state
= devlink_dump_state(cb
);
1197 int index
= state
->idx
;
1198 int tmp_index
= index
;
1202 hdr
= genlmsg_put(skb
, NETLINK_CB(cb
->skb
).portid
, cb
->nlh
->nlmsg_seq
,
1203 &devlink_nl_family
, NLM_F_ACK
| NLM_F_MULTI
, cmd
);
1206 goto nla_put_failure
;
1209 err
= devlink_fmsg_prepare_skb(fmsg
, skb
, &index
);
1210 if ((err
&& err
!= -EMSGSIZE
) || tmp_index
== index
)
1211 goto nla_put_failure
;
1214 genlmsg_end(skb
, hdr
);
1218 genlmsg_cancel(skb
, hdr
);
1222 int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff
*skb
,
1223 struct genl_info
*info
)
1225 struct devlink
*devlink
= info
->user_ptr
[0];
1226 struct devlink_health_reporter
*reporter
;
1227 struct devlink_fmsg
*fmsg
;
1230 reporter
= devlink_health_reporter_get_from_info(devlink
, info
);
1234 if (!reporter
->ops
->diagnose
)
1237 fmsg
= devlink_fmsg_alloc();
1241 err
= devlink_fmsg_obj_nest_start(fmsg
);
1245 err
= reporter
->ops
->diagnose(reporter
, fmsg
, info
->extack
);
1249 err
= devlink_fmsg_obj_nest_end(fmsg
);
1253 err
= devlink_fmsg_snd(fmsg
, info
,
1254 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE
, 0);
1257 devlink_fmsg_free(fmsg
);
1261 static struct devlink_health_reporter
*
1262 devlink_health_reporter_get_from_cb_lock(struct netlink_callback
*cb
)
1264 const struct genl_info
*info
= genl_info_dump(cb
);
1265 struct devlink_health_reporter
*reporter
;
1266 struct nlattr
**attrs
= info
->attrs
;
1267 struct devlink
*devlink
;
1269 devlink
= devlink_get_from_attrs_lock(sock_net(cb
->skb
->sk
), attrs
);
1270 if (IS_ERR(devlink
))
1273 reporter
= devlink_health_reporter_get_from_attrs(devlink
, attrs
);
1275 devl_unlock(devlink
);
1276 devlink_put(devlink
);
1281 int devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff
*skb
,
1282 struct netlink_callback
*cb
)
1284 struct devlink_nl_dump_state
*state
= devlink_dump_state(cb
);
1285 struct devlink_health_reporter
*reporter
;
1286 struct devlink
*devlink
;
1289 reporter
= devlink_health_reporter_get_from_cb_lock(cb
);
1293 devlink
= reporter
->devlink
;
1294 if (!reporter
->ops
->dump
) {
1295 devl_unlock(devlink
);
1296 devlink_put(devlink
);
1301 err
= devlink_health_do_dump(reporter
, NULL
, cb
->extack
);
1304 state
->dump_ts
= reporter
->dump_ts
;
1306 if (!reporter
->dump_fmsg
|| state
->dump_ts
!= reporter
->dump_ts
) {
1307 NL_SET_ERR_MSG(cb
->extack
, "Dump trampled, please retry");
1312 err
= devlink_fmsg_dumpit(reporter
->dump_fmsg
, skb
, cb
,
1313 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET
);
1315 devl_unlock(devlink
);
1316 devlink_put(devlink
);
1320 int devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff
*skb
,
1321 struct genl_info
*info
)
1323 struct devlink
*devlink
= info
->user_ptr
[0];
1324 struct devlink_health_reporter
*reporter
;
1326 reporter
= devlink_health_reporter_get_from_info(devlink
, info
);
1330 if (!reporter
->ops
->dump
)
1333 devlink_health_dump_clear(reporter
);
1337 int devlink_nl_cmd_health_reporter_test_doit(struct sk_buff
*skb
,
1338 struct genl_info
*info
)
1340 struct devlink
*devlink
= info
->user_ptr
[0];
1341 struct devlink_health_reporter
*reporter
;
1343 reporter
= devlink_health_reporter_get_from_info(devlink
, info
);
1347 if (!reporter
->ops
->test
)
1350 return reporter
->ops
->test(reporter
, info
->extack
);