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