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;
61 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
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;
128 mutex_init(&reporter->dump_lock);
133 * devl_port_health_reporter_create() - create devlink health reporter for
134 * specified port instance
136 * @port: devlink_port to which health reports will relate
137 * @ops: devlink health reporter ops
138 * @graceful_period: min time (in msec) between recovery attempts
139 * @priv: driver priv pointer
141 struct devlink_health_reporter *
142 devl_port_health_reporter_create(struct devlink_port *port,
143 const struct devlink_health_reporter_ops *ops,
144 u64 graceful_period, void *priv)
146 struct devlink_health_reporter *reporter;
148 devl_assert_locked(port->devlink);
150 if (__devlink_health_reporter_find_by_name(&port->reporter_list,
152 return ERR_PTR(-EEXIST);
154 reporter = __devlink_health_reporter_create(port->devlink, ops,
155 graceful_period, priv);
156 if (IS_ERR(reporter))
159 reporter->devlink_port = port;
160 list_add_tail(&reporter->list, &port->reporter_list);
163 EXPORT_SYMBOL_GPL(devl_port_health_reporter_create);
165 struct devlink_health_reporter *
166 devlink_port_health_reporter_create(struct devlink_port *port,
167 const struct devlink_health_reporter_ops *ops,
168 u64 graceful_period, void *priv)
170 struct devlink_health_reporter *reporter;
171 struct devlink *devlink = port->devlink;
174 reporter = devl_port_health_reporter_create(port, ops,
175 graceful_period, priv);
176 devl_unlock(devlink);
179 EXPORT_SYMBOL_GPL(devlink_port_health_reporter_create);
182 * devl_health_reporter_create - create devlink health reporter
184 * @devlink: devlink instance which the health reports will relate
185 * @ops: devlink health reporter ops
186 * @graceful_period: min time (in msec) between recovery attempts
187 * @priv: driver priv pointer
189 struct devlink_health_reporter *
190 devl_health_reporter_create(struct devlink *devlink,
191 const struct devlink_health_reporter_ops *ops,
192 u64 graceful_period, void *priv)
194 struct devlink_health_reporter *reporter;
196 devl_assert_locked(devlink);
198 if (devlink_health_reporter_find_by_name(devlink, ops->name))
199 return ERR_PTR(-EEXIST);
201 reporter = __devlink_health_reporter_create(devlink, ops,
202 graceful_period, priv);
203 if (IS_ERR(reporter))
206 list_add_tail(&reporter->list, &devlink->reporter_list);
209 EXPORT_SYMBOL_GPL(devl_health_reporter_create);
211 struct devlink_health_reporter *
212 devlink_health_reporter_create(struct devlink *devlink,
213 const struct devlink_health_reporter_ops *ops,
214 u64 graceful_period, void *priv)
216 struct devlink_health_reporter *reporter;
219 reporter = devl_health_reporter_create(devlink, ops,
220 graceful_period, priv);
221 devl_unlock(devlink);
224 EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
227 devlink_health_reporter_free(struct devlink_health_reporter *reporter)
229 mutex_destroy(&reporter->dump_lock);
230 if (reporter->dump_fmsg)
231 devlink_fmsg_free(reporter->dump_fmsg);
236 * devl_health_reporter_destroy() - destroy devlink health reporter
238 * @reporter: devlink health reporter to destroy
241 devl_health_reporter_destroy(struct devlink_health_reporter *reporter)
243 devl_assert_locked(reporter->devlink);
245 list_del(&reporter->list);
246 devlink_health_reporter_free(reporter);
248 EXPORT_SYMBOL_GPL(devl_health_reporter_destroy);
251 devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
253 struct devlink *devlink = reporter->devlink;
256 devl_health_reporter_destroy(reporter);
257 devl_unlock(devlink);
259 EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
262 devlink_nl_health_reporter_fill(struct sk_buff *msg,
263 struct devlink_health_reporter *reporter,
264 enum devlink_command cmd, u32 portid,
267 struct devlink *devlink = reporter->devlink;
268 struct nlattr *reporter_attr;
271 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
275 if (devlink_nl_put_handle(msg, devlink))
278 if (reporter->devlink_port) {
279 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, reporter->devlink_port->index))
282 reporter_attr = nla_nest_start_noflag(msg,
283 DEVLINK_ATTR_HEALTH_REPORTER);
286 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
287 reporter->ops->name))
288 goto reporter_nest_cancel;
289 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
290 reporter->health_state))
291 goto reporter_nest_cancel;
292 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
293 reporter->error_count, DEVLINK_ATTR_PAD))
294 goto reporter_nest_cancel;
295 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
296 reporter->recovery_count, DEVLINK_ATTR_PAD))
297 goto reporter_nest_cancel;
298 if (reporter->ops->recover &&
299 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
300 reporter->graceful_period,
302 goto reporter_nest_cancel;
303 if (reporter->ops->recover &&
304 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
305 reporter->auto_recover))
306 goto reporter_nest_cancel;
307 if (reporter->dump_fmsg &&
308 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
309 jiffies_to_msecs(reporter->dump_ts),
311 goto reporter_nest_cancel;
312 if (reporter->dump_fmsg &&
313 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS,
314 reporter->dump_real_ts, DEVLINK_ATTR_PAD))
315 goto reporter_nest_cancel;
316 if (reporter->ops->dump &&
317 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
318 reporter->auto_dump))
319 goto reporter_nest_cancel;
321 nla_nest_end(msg, reporter_attr);
322 genlmsg_end(msg, hdr);
325 reporter_nest_cancel:
326 nla_nest_cancel(msg, reporter_attr);
328 genlmsg_cancel(msg, hdr);
332 static struct devlink_health_reporter *
333 devlink_health_reporter_get_from_attrs(struct devlink *devlink,
334 struct nlattr **attrs)
336 struct devlink_port *devlink_port;
339 if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
342 reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
343 devlink_port = devlink_port_get_from_attrs(devlink, attrs);
344 if (IS_ERR(devlink_port))
345 return devlink_health_reporter_find_by_name(devlink,
348 return devlink_port_health_reporter_find_by_name(devlink_port,
352 static struct devlink_health_reporter *
353 devlink_health_reporter_get_from_info(struct devlink *devlink,
354 struct genl_info *info)
356 return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
359 int devlink_nl_health_reporter_get_doit(struct sk_buff *skb,
360 struct genl_info *info)
362 struct devlink *devlink = info->user_ptr[0];
363 struct devlink_health_reporter *reporter;
367 reporter = devlink_health_reporter_get_from_info(devlink, info);
371 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
375 err = devlink_nl_health_reporter_fill(msg, reporter,
376 DEVLINK_CMD_HEALTH_REPORTER_GET,
377 info->snd_portid, info->snd_seq,
384 return genlmsg_reply(msg, info);
387 static int devlink_nl_health_reporter_get_dump_one(struct sk_buff *msg,
388 struct devlink *devlink,
389 struct netlink_callback *cb,
392 struct devlink_nl_dump_state *state = devlink_dump_state(cb);
393 struct devlink_health_reporter *reporter;
394 struct devlink_port *port;
395 unsigned long port_index;
399 list_for_each_entry(reporter, &devlink->reporter_list, list) {
400 if (idx < state->idx) {
404 err = devlink_nl_health_reporter_fill(msg, reporter,
405 DEVLINK_CMD_HEALTH_REPORTER_GET,
406 NETLINK_CB(cb->skb).portid,
415 xa_for_each(&devlink->ports, port_index, port) {
416 list_for_each_entry(reporter, &port->reporter_list, list) {
417 if (idx < state->idx) {
421 err = devlink_nl_health_reporter_fill(msg, reporter,
422 DEVLINK_CMD_HEALTH_REPORTER_GET,
423 NETLINK_CB(cb->skb).portid,
437 int devlink_nl_health_reporter_get_dumpit(struct sk_buff *skb,
438 struct netlink_callback *cb)
440 return devlink_nl_dumpit(skb, cb,
441 devlink_nl_health_reporter_get_dump_one);
444 int devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
445 struct genl_info *info)
447 struct devlink *devlink = info->user_ptr[0];
448 struct devlink_health_reporter *reporter;
450 reporter = devlink_health_reporter_get_from_info(devlink, info);
454 if (!reporter->ops->recover &&
455 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
456 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]))
459 if (!reporter->ops->dump &&
460 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
463 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
464 reporter->graceful_period =
465 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
467 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
468 reporter->auto_recover =
469 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
471 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
472 reporter->auto_dump =
473 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]);
478 static void devlink_recover_notify(struct devlink_health_reporter *reporter,
479 enum devlink_command cmd)
481 struct devlink *devlink = reporter->devlink;
485 WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
486 ASSERT_DEVLINK_REGISTERED(devlink);
488 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
492 err = devlink_nl_health_reporter_fill(msg, reporter, cmd, 0, 0, 0);
498 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), msg,
499 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
503 devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter)
505 reporter->recovery_count++;
506 reporter->last_recovery_ts = jiffies;
508 EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done);
511 devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
512 void *priv_ctx, struct netlink_ext_ack *extack)
516 if (reporter->health_state == DEVLINK_HEALTH_REPORTER_STATE_HEALTHY)
519 if (!reporter->ops->recover)
522 err = reporter->ops->recover(reporter, priv_ctx, extack);
526 devlink_health_reporter_recovery_done(reporter);
527 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
528 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
534 devlink_health_dump_clear(struct devlink_health_reporter *reporter)
536 if (!reporter->dump_fmsg)
538 devlink_fmsg_free(reporter->dump_fmsg);
539 reporter->dump_fmsg = NULL;
542 static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
544 struct netlink_ext_ack *extack)
548 if (!reporter->ops->dump)
551 if (reporter->dump_fmsg)
554 reporter->dump_fmsg = devlink_fmsg_alloc();
555 if (!reporter->dump_fmsg) {
560 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
564 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
569 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
573 reporter->dump_ts = jiffies;
574 reporter->dump_real_ts = ktime_get_real_ns();
579 devlink_health_dump_clear(reporter);
583 int devlink_health_report(struct devlink_health_reporter *reporter,
584 const char *msg, void *priv_ctx)
586 enum devlink_health_reporter_state prev_health_state;
587 struct devlink *devlink = reporter->devlink;
588 unsigned long recover_ts_threshold;
591 /* write a log message of the current error */
593 trace_devlink_health_report(devlink, reporter->ops->name, msg);
594 reporter->error_count++;
595 prev_health_state = reporter->health_state;
596 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
597 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
599 /* abort if the previous error wasn't recovered */
600 recover_ts_threshold = reporter->last_recovery_ts +
601 msecs_to_jiffies(reporter->graceful_period);
602 if (reporter->auto_recover &&
603 (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
604 (reporter->last_recovery_ts && reporter->recovery_count &&
605 time_is_after_jiffies(recover_ts_threshold)))) {
606 trace_devlink_health_recover_aborted(devlink,
608 reporter->health_state,
610 reporter->last_recovery_ts);
614 if (reporter->auto_dump) {
615 mutex_lock(&reporter->dump_lock);
616 /* store current dump of current error, for later analysis */
617 devlink_health_do_dump(reporter, priv_ctx, NULL);
618 mutex_unlock(&reporter->dump_lock);
621 if (!reporter->auto_recover)
625 ret = devlink_health_reporter_recover(reporter, priv_ctx, NULL);
626 devl_unlock(devlink);
630 EXPORT_SYMBOL_GPL(devlink_health_report);
633 devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
634 enum devlink_health_reporter_state state)
636 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
637 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
640 if (reporter->health_state == state)
643 reporter->health_state = state;
644 trace_devlink_health_reporter_state_update(reporter->devlink,
645 reporter->ops->name, state);
646 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
648 EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
650 int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
651 struct genl_info *info)
653 struct devlink *devlink = info->user_ptr[0];
654 struct devlink_health_reporter *reporter;
656 reporter = devlink_health_reporter_get_from_info(devlink, info);
660 return devlink_health_reporter_recover(reporter, NULL, info->extack);
663 static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
666 struct devlink_fmsg_item *item;
668 item = kzalloc(sizeof(*item), GFP_KERNEL);
672 item->attrtype = attrtype;
673 list_add_tail(&item->list, &fmsg->item_list);
678 int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
680 if (fmsg->putting_binary)
683 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
685 EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
687 static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
689 if (fmsg->putting_binary)
692 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
695 int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
697 if (fmsg->putting_binary)
700 return devlink_fmsg_nest_end(fmsg);
702 EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
704 #define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
706 static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
708 struct devlink_fmsg_item *item;
710 if (fmsg->putting_binary)
713 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
716 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
720 item->nla_type = NLA_NUL_STRING;
721 item->len = strlen(name) + 1;
722 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
723 memcpy(&item->value, name, item->len);
724 list_add_tail(&item->list, &fmsg->item_list);
729 int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
733 if (fmsg->putting_binary)
736 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
740 err = devlink_fmsg_put_name(fmsg, name);
746 EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
748 int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
750 if (fmsg->putting_binary)
753 return devlink_fmsg_nest_end(fmsg);
755 EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
757 int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
762 if (fmsg->putting_binary)
765 err = devlink_fmsg_pair_nest_start(fmsg, name);
769 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
775 EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
777 int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
781 if (fmsg->putting_binary)
784 err = devlink_fmsg_nest_end(fmsg);
788 err = devlink_fmsg_nest_end(fmsg);
794 EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
796 int devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg,
801 err = devlink_fmsg_arr_pair_nest_start(fmsg, name);
805 fmsg->putting_binary = true;
808 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start);
810 int devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg)
812 if (!fmsg->putting_binary)
815 fmsg->putting_binary = false;
816 return devlink_fmsg_arr_pair_nest_end(fmsg);
818 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end);
820 static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
821 const void *value, u16 value_len,
824 struct devlink_fmsg_item *item;
826 if (value_len > DEVLINK_FMSG_MAX_SIZE)
829 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
833 item->nla_type = value_nla_type;
834 item->len = value_len;
835 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
836 memcpy(&item->value, value, item->len);
837 list_add_tail(&item->list, &fmsg->item_list);
842 static int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
844 if (fmsg->putting_binary)
847 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
850 static int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
852 if (fmsg->putting_binary)
855 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
858 int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
860 if (fmsg->putting_binary)
863 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
865 EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
867 static int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
869 if (fmsg->putting_binary)
872 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
875 int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
877 if (fmsg->putting_binary)
880 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
883 EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
885 int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
888 if (!fmsg->putting_binary)
891 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
893 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
895 int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
900 err = devlink_fmsg_pair_nest_start(fmsg, name);
904 err = devlink_fmsg_bool_put(fmsg, value);
908 err = devlink_fmsg_pair_nest_end(fmsg);
914 EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
916 int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
921 err = devlink_fmsg_pair_nest_start(fmsg, name);
925 err = devlink_fmsg_u8_put(fmsg, value);
929 err = devlink_fmsg_pair_nest_end(fmsg);
935 EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
937 int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
942 err = devlink_fmsg_pair_nest_start(fmsg, name);
946 err = devlink_fmsg_u32_put(fmsg, value);
950 err = devlink_fmsg_pair_nest_end(fmsg);
956 EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
958 int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
963 err = devlink_fmsg_pair_nest_start(fmsg, name);
967 err = devlink_fmsg_u64_put(fmsg, value);
971 err = devlink_fmsg_pair_nest_end(fmsg);
977 EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
979 int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
984 err = devlink_fmsg_pair_nest_start(fmsg, name);
988 err = devlink_fmsg_string_put(fmsg, value);
992 err = devlink_fmsg_pair_nest_end(fmsg);
998 EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
1000 int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
1001 const void *value, u32 value_len)
1008 err = devlink_fmsg_binary_pair_nest_start(fmsg, name);
1012 for (offset = 0; offset < value_len; offset += data_size) {
1013 data_size = value_len - offset;
1014 if (data_size > DEVLINK_FMSG_MAX_SIZE)
1015 data_size = DEVLINK_FMSG_MAX_SIZE;
1016 err = devlink_fmsg_binary_put(fmsg, value + offset, data_size);
1019 /* Exit from loop with a break (instead of
1020 * return) to make sure putting_binary is turned off in
1021 * devlink_fmsg_binary_pair_nest_end
1025 end_err = devlink_fmsg_binary_pair_nest_end(fmsg);
1031 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
1034 devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
1036 switch (msg->nla_type) {
1041 case NLA_NUL_STRING:
1043 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
1051 devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
1053 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
1056 switch (msg->nla_type) {
1058 /* Always provide flag data, regardless of its value */
1059 tmp = *(bool *)msg->value;
1061 return nla_put_u8(skb, attrtype, tmp);
1063 return nla_put_u8(skb, attrtype, *(u8 *)msg->value);
1065 return nla_put_u32(skb, attrtype, *(u32 *)msg->value);
1067 return nla_put_u64_64bit(skb, attrtype, *(u64 *)msg->value,
1069 case NLA_NUL_STRING:
1070 return nla_put_string(skb, attrtype, (char *)&msg->value);
1072 return nla_put(skb, attrtype, msg->len, (void *)&msg->value);
1079 devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
1082 struct devlink_fmsg_item *item;
1083 struct nlattr *fmsg_nlattr;
1087 fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
1091 list_for_each_entry(item, &fmsg->item_list, list) {
1097 switch (item->attrtype) {
1098 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
1099 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
1100 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
1101 case DEVLINK_ATTR_FMSG_NEST_END:
1102 err = nla_put_flag(skb, item->attrtype);
1104 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
1105 err = devlink_fmsg_item_fill_type(item, skb);
1108 err = devlink_fmsg_item_fill_data(item, skb);
1110 case DEVLINK_ATTR_FMSG_OBJ_NAME:
1111 err = nla_put_string(skb, item->attrtype,
1112 (char *)&item->value);
1124 nla_nest_end(skb, fmsg_nlattr);
1128 static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
1129 struct genl_info *info,
1130 enum devlink_command cmd, int flags)
1132 struct nlmsghdr *nlh;
1133 struct sk_buff *skb;
1140 int tmp_index = index;
1142 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
1146 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
1147 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
1150 goto nla_put_failure;
1153 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
1156 else if (err != -EMSGSIZE || tmp_index == index)
1157 goto nla_put_failure;
1159 genlmsg_end(skb, hdr);
1160 err = genlmsg_reply(skb, info);
1165 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
1168 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
1169 NLMSG_DONE, 0, flags | NLM_F_MULTI);
1172 goto nla_put_failure;
1175 return genlmsg_reply(skb, info);
1182 static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
1183 struct netlink_callback *cb,
1184 enum devlink_command cmd)
1186 struct devlink_nl_dump_state *state = devlink_dump_state(cb);
1187 int index = state->idx;
1188 int tmp_index = index;
1192 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
1193 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
1196 goto nla_put_failure;
1199 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
1200 if ((err && err != -EMSGSIZE) || tmp_index == index)
1201 goto nla_put_failure;
1204 genlmsg_end(skb, hdr);
1208 genlmsg_cancel(skb, hdr);
1212 int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
1213 struct genl_info *info)
1215 struct devlink *devlink = info->user_ptr[0];
1216 struct devlink_health_reporter *reporter;
1217 struct devlink_fmsg *fmsg;
1220 reporter = devlink_health_reporter_get_from_info(devlink, info);
1224 if (!reporter->ops->diagnose)
1227 fmsg = devlink_fmsg_alloc();
1231 err = devlink_fmsg_obj_nest_start(fmsg);
1235 err = reporter->ops->diagnose(reporter, fmsg, info->extack);
1239 err = devlink_fmsg_obj_nest_end(fmsg);
1243 err = devlink_fmsg_snd(fmsg, info,
1244 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
1247 devlink_fmsg_free(fmsg);
1251 static struct devlink_health_reporter *
1252 devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
1254 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
1255 struct devlink_health_reporter *reporter;
1256 struct nlattr **attrs = info->attrs;
1257 struct devlink *devlink;
1259 devlink = devlink_get_from_attrs_lock(sock_net(cb->skb->sk), attrs);
1260 if (IS_ERR(devlink))
1262 devl_unlock(devlink);
1264 reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
1265 devlink_put(devlink);
1269 int devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
1270 struct netlink_callback *cb)
1272 struct devlink_nl_dump_state *state = devlink_dump_state(cb);
1273 struct devlink_health_reporter *reporter;
1276 reporter = devlink_health_reporter_get_from_cb(cb);
1280 if (!reporter->ops->dump)
1283 mutex_lock(&reporter->dump_lock);
1285 err = devlink_health_do_dump(reporter, NULL, cb->extack);
1288 state->dump_ts = reporter->dump_ts;
1290 if (!reporter->dump_fmsg || state->dump_ts != reporter->dump_ts) {
1291 NL_SET_ERR_MSG(cb->extack, "Dump trampled, please retry");
1296 err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
1297 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
1299 mutex_unlock(&reporter->dump_lock);
1303 int devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
1304 struct genl_info *info)
1306 struct devlink *devlink = info->user_ptr[0];
1307 struct devlink_health_reporter *reporter;
1309 reporter = devlink_health_reporter_get_from_info(devlink, info);
1313 if (!reporter->ops->dump)
1316 mutex_lock(&reporter->dump_lock);
1317 devlink_health_dump_clear(reporter);
1318 mutex_unlock(&reporter->dump_lock);
1322 int devlink_nl_cmd_health_reporter_test_doit(struct sk_buff *skb,
1323 struct genl_info *info)
1325 struct devlink *devlink = info->user_ptr[0];
1326 struct devlink_health_reporter *reporter;
1328 reporter = devlink_health_reporter_get_from_info(devlink, info);
1332 if (!reporter->ops->test)
1335 return reporter->ops->test(reporter, info->extack);