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 (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
291 reporter->error_count, DEVLINK_ATTR_PAD))
292 goto reporter_nest_cancel;
293 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
294 reporter->recovery_count, DEVLINK_ATTR_PAD))
295 goto reporter_nest_cancel;
296 if (reporter->ops->recover &&
297 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
298 reporter->graceful_period,
300 goto reporter_nest_cancel;
301 if (reporter->ops->recover &&
302 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
303 reporter->auto_recover))
304 goto reporter_nest_cancel;
305 if (reporter->dump_fmsg &&
306 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
307 jiffies_to_msecs(reporter->dump_ts),
309 goto reporter_nest_cancel;
310 if (reporter->dump_fmsg &&
311 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS,
312 reporter->dump_real_ts, DEVLINK_ATTR_PAD))
313 goto reporter_nest_cancel;
314 if (reporter->ops->dump &&
315 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
316 reporter->auto_dump))
317 goto reporter_nest_cancel;
319 nla_nest_end(msg, reporter_attr);
320 genlmsg_end(msg, hdr);
323 reporter_nest_cancel:
324 nla_nest_cancel(msg, reporter_attr);
326 genlmsg_cancel(msg, hdr);
330 static struct devlink_health_reporter *
331 devlink_health_reporter_get_from_attrs(struct devlink *devlink,
332 struct nlattr **attrs)
334 struct devlink_port *devlink_port;
337 if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
340 reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
341 devlink_port = devlink_port_get_from_attrs(devlink, attrs);
342 if (IS_ERR(devlink_port))
343 return devlink_health_reporter_find_by_name(devlink,
346 return devlink_port_health_reporter_find_by_name(devlink_port,
350 static struct devlink_health_reporter *
351 devlink_health_reporter_get_from_info(struct devlink *devlink,
352 struct genl_info *info)
354 return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
357 int devlink_nl_health_reporter_get_doit(struct sk_buff *skb,
358 struct genl_info *info)
360 struct devlink *devlink = info->user_ptr[0];
361 struct devlink_health_reporter *reporter;
365 reporter = devlink_health_reporter_get_from_info(devlink, info);
369 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
373 err = devlink_nl_health_reporter_fill(msg, reporter,
374 DEVLINK_CMD_HEALTH_REPORTER_GET,
375 info->snd_portid, info->snd_seq,
382 return genlmsg_reply(msg, info);
385 static int devlink_nl_health_reporter_get_dump_one(struct sk_buff *msg,
386 struct devlink *devlink,
387 struct netlink_callback *cb,
390 struct devlink_nl_dump_state *state = devlink_dump_state(cb);
391 const struct genl_info *info = genl_info_dump(cb);
392 struct devlink_health_reporter *reporter;
393 unsigned long port_index_end = ULONG_MAX;
394 struct nlattr **attrs = info->attrs;
395 unsigned long port_index_start = 0;
396 struct devlink_port *port;
397 unsigned long port_index;
401 if (attrs && attrs[DEVLINK_ATTR_PORT_INDEX]) {
402 port_index_start = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
403 port_index_end = port_index_start;
404 flags |= NLM_F_DUMP_FILTERED;
408 list_for_each_entry(reporter, &devlink->reporter_list, list) {
409 if (idx < state->idx) {
413 err = devlink_nl_health_reporter_fill(msg, reporter,
414 DEVLINK_CMD_HEALTH_REPORTER_GET,
415 NETLINK_CB(cb->skb).portid,
425 xa_for_each_range(&devlink->ports, port_index, port,
426 port_index_start, port_index_end) {
427 list_for_each_entry(reporter, &port->reporter_list, list) {
428 if (idx < state->idx) {
432 err = devlink_nl_health_reporter_fill(msg, reporter,
433 DEVLINK_CMD_HEALTH_REPORTER_GET,
434 NETLINK_CB(cb->skb).portid,
448 int devlink_nl_health_reporter_get_dumpit(struct sk_buff *skb,
449 struct netlink_callback *cb)
451 return devlink_nl_dumpit(skb, cb,
452 devlink_nl_health_reporter_get_dump_one);
455 int devlink_nl_health_reporter_set_doit(struct sk_buff *skb,
456 struct genl_info *info)
458 struct devlink *devlink = info->user_ptr[0];
459 struct devlink_health_reporter *reporter;
461 reporter = devlink_health_reporter_get_from_info(devlink, info);
465 if (!reporter->ops->recover &&
466 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
467 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]))
470 if (!reporter->ops->dump &&
471 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
474 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
475 reporter->graceful_period =
476 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
478 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
479 reporter->auto_recover =
480 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
482 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
483 reporter->auto_dump =
484 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]);
489 static void devlink_recover_notify(struct devlink_health_reporter *reporter,
490 enum devlink_command cmd)
492 struct devlink *devlink = reporter->devlink;
493 struct devlink_obj_desc desc;
497 WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
498 ASSERT_DEVLINK_REGISTERED(devlink);
500 if (!devlink_nl_notify_need(devlink))
503 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
507 err = devlink_nl_health_reporter_fill(msg, reporter, cmd, 0, 0, 0);
513 devlink_nl_obj_desc_init(&desc, devlink);
514 if (reporter->devlink_port)
515 devlink_nl_obj_desc_port_set(&desc, reporter->devlink_port);
516 devlink_nl_notify_send_desc(devlink, msg, &desc);
520 devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter)
522 reporter->recovery_count++;
523 reporter->last_recovery_ts = jiffies;
525 EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done);
528 devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
529 void *priv_ctx, struct netlink_ext_ack *extack)
533 if (reporter->health_state == DEVLINK_HEALTH_REPORTER_STATE_HEALTHY)
536 if (!reporter->ops->recover)
539 err = reporter->ops->recover(reporter, priv_ctx, extack);
543 devlink_health_reporter_recovery_done(reporter);
544 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
545 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
551 devlink_health_dump_clear(struct devlink_health_reporter *reporter)
553 if (!reporter->dump_fmsg)
555 devlink_fmsg_free(reporter->dump_fmsg);
556 reporter->dump_fmsg = NULL;
559 static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
561 struct netlink_ext_ack *extack)
565 if (!reporter->ops->dump)
568 if (reporter->dump_fmsg)
571 reporter->dump_fmsg = devlink_fmsg_alloc();
572 if (!reporter->dump_fmsg)
575 devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
577 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
582 devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
583 err = reporter->dump_fmsg->err;
587 reporter->dump_ts = jiffies;
588 reporter->dump_real_ts = ktime_get_real_ns();
593 devlink_health_dump_clear(reporter);
597 int devlink_health_report(struct devlink_health_reporter *reporter,
598 const char *msg, void *priv_ctx)
600 enum devlink_health_reporter_state prev_health_state;
601 struct devlink *devlink = reporter->devlink;
602 unsigned long recover_ts_threshold;
605 /* write a log message of the current error */
607 trace_devlink_health_report(devlink, reporter->ops->name, msg);
608 reporter->error_count++;
609 prev_health_state = reporter->health_state;
610 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
611 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
613 /* abort if the previous error wasn't recovered */
614 recover_ts_threshold = reporter->last_recovery_ts +
615 msecs_to_jiffies(reporter->graceful_period);
616 if (reporter->auto_recover &&
617 (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
618 (reporter->last_recovery_ts && reporter->recovery_count &&
619 time_is_after_jiffies(recover_ts_threshold)))) {
620 trace_devlink_health_recover_aborted(devlink,
622 reporter->health_state,
624 reporter->last_recovery_ts);
628 if (reporter->auto_dump) {
630 /* store current dump of current error, for later analysis */
631 devlink_health_do_dump(reporter, priv_ctx, NULL);
632 devl_unlock(devlink);
635 if (!reporter->auto_recover)
639 ret = devlink_health_reporter_recover(reporter, priv_ctx, NULL);
640 devl_unlock(devlink);
644 EXPORT_SYMBOL_GPL(devlink_health_report);
647 devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
648 enum devlink_health_reporter_state state)
650 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
651 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
654 if (reporter->health_state == state)
657 reporter->health_state = state;
658 trace_devlink_health_reporter_state_update(reporter->devlink,
659 reporter->ops->name, state);
660 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
662 EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
664 int devlink_nl_health_reporter_recover_doit(struct sk_buff *skb,
665 struct genl_info *info)
667 struct devlink *devlink = info->user_ptr[0];
668 struct devlink_health_reporter *reporter;
670 reporter = devlink_health_reporter_get_from_info(devlink, info);
674 return devlink_health_reporter_recover(reporter, NULL, info->extack);
677 static void devlink_fmsg_err_if_binary(struct devlink_fmsg *fmsg)
679 if (!fmsg->err && fmsg->putting_binary)
683 static void devlink_fmsg_nest_common(struct devlink_fmsg *fmsg, int attrtype)
685 struct devlink_fmsg_item *item;
690 item = kzalloc(sizeof(*item), GFP_KERNEL);
696 item->attrtype = attrtype;
697 list_add_tail(&item->list, &fmsg->item_list);
700 void devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
702 devlink_fmsg_err_if_binary(fmsg);
703 devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
705 EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
707 static void devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
709 devlink_fmsg_err_if_binary(fmsg);
710 devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
713 void devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
715 devlink_fmsg_nest_end(fmsg);
717 EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
719 #define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
721 static void devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
723 struct devlink_fmsg_item *item;
725 devlink_fmsg_err_if_binary(fmsg);
729 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE) {
730 fmsg->err = -EMSGSIZE;
734 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
740 item->nla_type = NLA_NUL_STRING;
741 item->len = strlen(name) + 1;
742 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
743 memcpy(&item->value, name, item->len);
744 list_add_tail(&item->list, &fmsg->item_list);
747 void devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
749 devlink_fmsg_err_if_binary(fmsg);
750 devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
751 devlink_fmsg_put_name(fmsg, name);
753 EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
755 void devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
757 devlink_fmsg_nest_end(fmsg);
759 EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
761 void devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
764 devlink_fmsg_pair_nest_start(fmsg, name);
765 devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
767 EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
769 void devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
771 devlink_fmsg_nest_end(fmsg);
772 devlink_fmsg_nest_end(fmsg);
774 EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
776 void devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg,
779 devlink_fmsg_arr_pair_nest_start(fmsg, name);
780 fmsg->putting_binary = true;
782 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start);
784 void devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg)
789 if (!fmsg->putting_binary)
792 fmsg->putting_binary = false;
793 devlink_fmsg_arr_pair_nest_end(fmsg);
795 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end);
797 static void devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
798 const void *value, u16 value_len,
801 struct devlink_fmsg_item *item;
806 if (value_len > DEVLINK_FMSG_MAX_SIZE) {
807 fmsg->err = -EMSGSIZE;
811 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
817 item->nla_type = value_nla_type;
818 item->len = value_len;
819 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
820 memcpy(&item->value, value, item->len);
821 list_add_tail(&item->list, &fmsg->item_list);
824 static void devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
826 devlink_fmsg_err_if_binary(fmsg);
827 devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
830 static void devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
832 devlink_fmsg_err_if_binary(fmsg);
833 devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
836 void devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
838 devlink_fmsg_err_if_binary(fmsg);
839 devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
841 EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
843 static void devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
845 devlink_fmsg_err_if_binary(fmsg);
846 devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
849 void devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
851 devlink_fmsg_err_if_binary(fmsg);
852 devlink_fmsg_put_value(fmsg, value, strlen(value) + 1, NLA_NUL_STRING);
854 EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
856 void devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
859 if (!fmsg->err && !fmsg->putting_binary)
862 devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
864 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
866 void devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
869 devlink_fmsg_pair_nest_start(fmsg, name);
870 devlink_fmsg_bool_put(fmsg, value);
871 devlink_fmsg_pair_nest_end(fmsg);
873 EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
875 void devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
878 devlink_fmsg_pair_nest_start(fmsg, name);
879 devlink_fmsg_u8_put(fmsg, value);
880 devlink_fmsg_pair_nest_end(fmsg);
882 EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
884 void devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
887 devlink_fmsg_pair_nest_start(fmsg, name);
888 devlink_fmsg_u32_put(fmsg, value);
889 devlink_fmsg_pair_nest_end(fmsg);
891 EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
893 void devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
896 devlink_fmsg_pair_nest_start(fmsg, name);
897 devlink_fmsg_u64_put(fmsg, value);
898 devlink_fmsg_pair_nest_end(fmsg);
900 EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
902 void devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
905 devlink_fmsg_pair_nest_start(fmsg, name);
906 devlink_fmsg_string_put(fmsg, value);
907 devlink_fmsg_pair_nest_end(fmsg);
909 EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
911 void devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
912 const void *value, u32 value_len)
917 devlink_fmsg_binary_pair_nest_start(fmsg, name);
919 for (offset = 0; offset < value_len; offset += data_size) {
920 data_size = value_len - offset;
921 if (data_size > DEVLINK_FMSG_MAX_SIZE)
922 data_size = DEVLINK_FMSG_MAX_SIZE;
924 devlink_fmsg_binary_put(fmsg, value + offset, data_size);
927 devlink_fmsg_binary_pair_nest_end(fmsg);
928 fmsg->putting_binary = false;
930 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
933 devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
935 switch (msg->nla_type) {
942 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
950 devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
952 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
955 switch (msg->nla_type) {
957 /* Always provide flag data, regardless of its value */
958 tmp = *(bool *)msg->value;
960 return nla_put_u8(skb, attrtype, tmp);
962 return nla_put_u8(skb, attrtype, *(u8 *)msg->value);
964 return nla_put_u32(skb, attrtype, *(u32 *)msg->value);
966 return nla_put_u64_64bit(skb, attrtype, *(u64 *)msg->value,
969 return nla_put_string(skb, attrtype, (char *)&msg->value);
971 return nla_put(skb, attrtype, msg->len, (void *)&msg->value);
978 devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
981 struct devlink_fmsg_item *item;
982 struct nlattr *fmsg_nlattr;
986 fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
990 list_for_each_entry(item, &fmsg->item_list, list) {
996 switch (item->attrtype) {
997 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
998 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
999 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
1000 case DEVLINK_ATTR_FMSG_NEST_END:
1001 err = nla_put_flag(skb, item->attrtype);
1003 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
1004 err = devlink_fmsg_item_fill_type(item, skb);
1007 err = devlink_fmsg_item_fill_data(item, skb);
1009 case DEVLINK_ATTR_FMSG_OBJ_NAME:
1010 err = nla_put_string(skb, item->attrtype,
1011 (char *)&item->value);
1023 nla_nest_end(skb, fmsg_nlattr);
1027 static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
1028 struct genl_info *info,
1029 enum devlink_command cmd, int flags)
1031 struct nlmsghdr *nlh;
1032 struct sk_buff *skb;
1042 int tmp_index = index;
1044 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
1048 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
1049 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
1052 goto nla_put_failure;
1055 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
1058 else if (err != -EMSGSIZE || tmp_index == index)
1059 goto nla_put_failure;
1061 genlmsg_end(skb, hdr);
1062 err = genlmsg_reply(skb, info);
1067 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
1070 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
1071 NLMSG_DONE, 0, flags | NLM_F_MULTI);
1074 goto nla_put_failure;
1077 return genlmsg_reply(skb, info);
1084 static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
1085 struct netlink_callback *cb,
1086 enum devlink_command cmd)
1088 struct devlink_nl_dump_state *state = devlink_dump_state(cb);
1089 int index = state->idx;
1090 int tmp_index = index;
1097 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
1098 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
1101 goto nla_put_failure;
1104 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
1105 if ((err && err != -EMSGSIZE) || tmp_index == index)
1106 goto nla_put_failure;
1109 genlmsg_end(skb, hdr);
1113 genlmsg_cancel(skb, hdr);
1117 int devlink_nl_health_reporter_diagnose_doit(struct sk_buff *skb,
1118 struct genl_info *info)
1120 struct devlink *devlink = info->user_ptr[0];
1121 struct devlink_health_reporter *reporter;
1122 struct devlink_fmsg *fmsg;
1125 reporter = devlink_health_reporter_get_from_info(devlink, info);
1129 if (!reporter->ops->diagnose)
1132 fmsg = devlink_fmsg_alloc();
1136 devlink_fmsg_obj_nest_start(fmsg);
1138 err = reporter->ops->diagnose(reporter, fmsg, info->extack);
1142 devlink_fmsg_obj_nest_end(fmsg);
1144 err = devlink_fmsg_snd(fmsg, info,
1145 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
1148 devlink_fmsg_free(fmsg);
1152 static struct devlink_health_reporter *
1153 devlink_health_reporter_get_from_cb_lock(struct netlink_callback *cb)
1155 const struct genl_info *info = genl_info_dump(cb);
1156 struct devlink_health_reporter *reporter;
1157 struct nlattr **attrs = info->attrs;
1158 struct devlink *devlink;
1160 devlink = devlink_get_from_attrs_lock(sock_net(cb->skb->sk), attrs,
1162 if (IS_ERR(devlink))
1165 reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
1167 devl_unlock(devlink);
1168 devlink_put(devlink);
1173 int devlink_nl_health_reporter_dump_get_dumpit(struct sk_buff *skb,
1174 struct netlink_callback *cb)
1176 struct devlink_nl_dump_state *state = devlink_dump_state(cb);
1177 struct devlink_health_reporter *reporter;
1178 struct devlink *devlink;
1181 reporter = devlink_health_reporter_get_from_cb_lock(cb);
1185 devlink = reporter->devlink;
1186 if (!reporter->ops->dump) {
1187 devl_unlock(devlink);
1188 devlink_put(devlink);
1193 err = devlink_health_do_dump(reporter, NULL, cb->extack);
1196 state->dump_ts = reporter->dump_ts;
1198 if (!reporter->dump_fmsg || state->dump_ts != reporter->dump_ts) {
1199 NL_SET_ERR_MSG(cb->extack, "Dump trampled, please retry");
1204 err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
1205 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
1207 devl_unlock(devlink);
1208 devlink_put(devlink);
1212 int devlink_nl_health_reporter_dump_clear_doit(struct sk_buff *skb,
1213 struct genl_info *info)
1215 struct devlink *devlink = info->user_ptr[0];
1216 struct devlink_health_reporter *reporter;
1218 reporter = devlink_health_reporter_get_from_info(devlink, info);
1222 if (!reporter->ops->dump)
1225 devlink_health_dump_clear(reporter);
1229 int devlink_nl_health_reporter_test_doit(struct sk_buff *skb,
1230 struct genl_info *info)
1232 struct devlink *devlink = info->user_ptr[0];
1233 struct devlink_health_reporter *reporter;
1235 reporter = devlink_health_reporter_get_from_info(devlink, info);
1239 if (!reporter->ops->test)
1242 return reporter->ops->test(reporter, info->extack);