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 <jiri@mellanox.com> 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 bool putting_binary; /* This flag forces enclosing of binary data 23 * in an array brackets. It forces using 24 * of designated API: 25 * devlink_fmsg_binary_pair_nest_start() 26 * devlink_fmsg_binary_pair_nest_end() 27 */ 28 }; 29 30 static struct devlink_fmsg *devlink_fmsg_alloc(void) 31 { 32 struct devlink_fmsg *fmsg; 33 34 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL); 35 if (!fmsg) 36 return NULL; 37 38 INIT_LIST_HEAD(&fmsg->item_list); 39 40 return fmsg; 41 } 42 43 static void devlink_fmsg_free(struct devlink_fmsg *fmsg) 44 { 45 struct devlink_fmsg_item *item, *tmp; 46 47 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) { 48 list_del(&item->list); 49 kfree(item); 50 } 51 kfree(fmsg); 52 } 53 54 struct devlink_health_reporter { 55 struct list_head list; 56 void *priv; 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 */ 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 * 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 * 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 * 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 * 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 * 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 mutex_init(&reporter->dump_lock); 129 return reporter; 130 } 131 132 /** 133 * devl_port_health_reporter_create() - create devlink health reporter for 134 * specified port instance 135 * 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 140 */ 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) 145 { 146 struct devlink_health_reporter *reporter; 147 148 devl_assert_locked(port->devlink); 149 150 if (__devlink_health_reporter_find_by_name(&port->reporter_list, 151 ops->name)) 152 return ERR_PTR(-EEXIST); 153 154 reporter = __devlink_health_reporter_create(port->devlink, ops, 155 graceful_period, priv); 156 if (IS_ERR(reporter)) 157 return reporter; 158 159 reporter->devlink_port = port; 160 list_add_tail(&reporter->list, &port->reporter_list); 161 return reporter; 162 } 163 EXPORT_SYMBOL_GPL(devl_port_health_reporter_create); 164 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) 169 { 170 struct devlink_health_reporter *reporter; 171 struct devlink *devlink = port->devlink; 172 173 devl_lock(devlink); 174 reporter = devl_port_health_reporter_create(port, ops, 175 graceful_period, priv); 176 devl_unlock(devlink); 177 return reporter; 178 } 179 EXPORT_SYMBOL_GPL(devlink_port_health_reporter_create); 180 181 /** 182 * devl_health_reporter_create - create devlink health reporter 183 * 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 188 */ 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) 193 { 194 struct devlink_health_reporter *reporter; 195 196 devl_assert_locked(devlink); 197 198 if (devlink_health_reporter_find_by_name(devlink, ops->name)) 199 return ERR_PTR(-EEXIST); 200 201 reporter = __devlink_health_reporter_create(devlink, ops, 202 graceful_period, priv); 203 if (IS_ERR(reporter)) 204 return reporter; 205 206 list_add_tail(&reporter->list, &devlink->reporter_list); 207 return reporter; 208 } 209 EXPORT_SYMBOL_GPL(devl_health_reporter_create); 210 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) 215 { 216 struct devlink_health_reporter *reporter; 217 218 devl_lock(devlink); 219 reporter = devl_health_reporter_create(devlink, ops, 220 graceful_period, priv); 221 devl_unlock(devlink); 222 return reporter; 223 } 224 EXPORT_SYMBOL_GPL(devlink_health_reporter_create); 225 226 static void 227 devlink_health_reporter_free(struct devlink_health_reporter *reporter) 228 { 229 mutex_destroy(&reporter->dump_lock); 230 if (reporter->dump_fmsg) 231 devlink_fmsg_free(reporter->dump_fmsg); 232 kfree(reporter); 233 } 234 235 /** 236 * devl_health_reporter_destroy() - destroy devlink health reporter 237 * 238 * @reporter: devlink health reporter to destroy 239 */ 240 void 241 devl_health_reporter_destroy(struct devlink_health_reporter *reporter) 242 { 243 devl_assert_locked(reporter->devlink); 244 245 list_del(&reporter->list); 246 devlink_health_reporter_free(reporter); 247 } 248 EXPORT_SYMBOL_GPL(devl_health_reporter_destroy); 249 250 void 251 devlink_health_reporter_destroy(struct devlink_health_reporter *reporter) 252 { 253 struct devlink *devlink = reporter->devlink; 254 255 devl_lock(devlink); 256 devl_health_reporter_destroy(reporter); 257 devl_unlock(devlink); 258 } 259 EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy); 260 261 static int 262 devlink_nl_health_reporter_fill(struct sk_buff *msg, 263 struct devlink_health_reporter *reporter, 264 enum devlink_command cmd, u32 portid, 265 u32 seq, int flags) 266 { 267 struct devlink *devlink = reporter->devlink; 268 struct nlattr *reporter_attr; 269 void *hdr; 270 271 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 272 if (!hdr) 273 return -EMSGSIZE; 274 275 if (devlink_nl_put_handle(msg, devlink)) 276 goto genlmsg_cancel; 277 278 if (reporter->devlink_port) { 279 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, reporter->devlink_port->index)) 280 goto genlmsg_cancel; 281 } 282 reporter_attr = nla_nest_start_noflag(msg, 283 DEVLINK_ATTR_HEALTH_REPORTER); 284 if (!reporter_attr) 285 goto genlmsg_cancel; 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, 301 DEVLINK_ATTR_PAD)) 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), 310 DEVLINK_ATTR_PAD)) 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; 320 321 nla_nest_end(msg, reporter_attr); 322 genlmsg_end(msg, hdr); 323 return 0; 324 325 reporter_nest_cancel: 326 nla_nest_cancel(msg, reporter_attr); 327 genlmsg_cancel: 328 genlmsg_cancel(msg, hdr); 329 return -EMSGSIZE; 330 } 331 332 static struct devlink_health_reporter * 333 devlink_health_reporter_get_from_attrs(struct devlink *devlink, 334 struct nlattr **attrs) 335 { 336 struct devlink_port *devlink_port; 337 char *reporter_name; 338 339 if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]) 340 return NULL; 341 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, 346 reporter_name); 347 else 348 return devlink_port_health_reporter_find_by_name(devlink_port, 349 reporter_name); 350 } 351 352 static struct devlink_health_reporter * 353 devlink_health_reporter_get_from_info(struct devlink *devlink, 354 struct genl_info *info) 355 { 356 return devlink_health_reporter_get_from_attrs(devlink, info->attrs); 357 } 358 359 int devlink_nl_health_reporter_get_doit(struct sk_buff *skb, 360 struct genl_info *info) 361 { 362 struct devlink *devlink = info->user_ptr[0]; 363 struct devlink_health_reporter *reporter; 364 struct sk_buff *msg; 365 int err; 366 367 reporter = devlink_health_reporter_get_from_info(devlink, info); 368 if (!reporter) 369 return -EINVAL; 370 371 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 372 if (!msg) 373 return -ENOMEM; 374 375 err = devlink_nl_health_reporter_fill(msg, reporter, 376 DEVLINK_CMD_HEALTH_REPORTER_GET, 377 info->snd_portid, info->snd_seq, 378 0); 379 if (err) { 380 nlmsg_free(msg); 381 return err; 382 } 383 384 return genlmsg_reply(msg, info); 385 } 386 387 static int devlink_nl_health_reporter_get_dump_one(struct sk_buff *msg, 388 struct devlink *devlink, 389 struct netlink_callback *cb, 390 int flags) 391 { 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; 396 int idx = 0; 397 int err; 398 399 list_for_each_entry(reporter, &devlink->reporter_list, list) { 400 if (idx < state->idx) { 401 idx++; 402 continue; 403 } 404 err = devlink_nl_health_reporter_fill(msg, reporter, 405 DEVLINK_CMD_HEALTH_REPORTER_GET, 406 NETLINK_CB(cb->skb).portid, 407 cb->nlh->nlmsg_seq, 408 flags); 409 if (err) { 410 state->idx = idx; 411 return err; 412 } 413 idx++; 414 } 415 xa_for_each(&devlink->ports, port_index, port) { 416 list_for_each_entry(reporter, &port->reporter_list, list) { 417 if (idx < state->idx) { 418 idx++; 419 continue; 420 } 421 err = devlink_nl_health_reporter_fill(msg, reporter, 422 DEVLINK_CMD_HEALTH_REPORTER_GET, 423 NETLINK_CB(cb->skb).portid, 424 cb->nlh->nlmsg_seq, 425 flags); 426 if (err) { 427 state->idx = idx; 428 return err; 429 } 430 idx++; 431 } 432 } 433 434 return 0; 435 } 436 437 int devlink_nl_health_reporter_get_dumpit(struct sk_buff *skb, 438 struct netlink_callback *cb) 439 { 440 return devlink_nl_dumpit(skb, cb, 441 devlink_nl_health_reporter_get_dump_one); 442 } 443 444 int devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb, 445 struct genl_info *info) 446 { 447 struct devlink *devlink = info->user_ptr[0]; 448 struct devlink_health_reporter *reporter; 449 450 reporter = devlink_health_reporter_get_from_info(devlink, info); 451 if (!reporter) 452 return -EINVAL; 453 454 if (!reporter->ops->recover && 455 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] || 456 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) 457 return -EOPNOTSUPP; 458 459 if (!reporter->ops->dump && 460 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]) 461 return -EOPNOTSUPP; 462 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]); 466 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]); 470 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]); 474 475 return 0; 476 } 477 478 static void devlink_recover_notify(struct devlink_health_reporter *reporter, 479 enum devlink_command cmd) 480 { 481 struct devlink *devlink = reporter->devlink; 482 struct sk_buff *msg; 483 int err; 484 485 WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER); 486 ASSERT_DEVLINK_REGISTERED(devlink); 487 488 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 489 if (!msg) 490 return; 491 492 err = devlink_nl_health_reporter_fill(msg, reporter, cmd, 0, 0, 0); 493 if (err) { 494 nlmsg_free(msg); 495 return; 496 } 497 498 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), msg, 499 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 500 } 501 502 void 503 devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter) 504 { 505 reporter->recovery_count++; 506 reporter->last_recovery_ts = jiffies; 507 } 508 EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done); 509 510 static int 511 devlink_health_reporter_recover(struct devlink_health_reporter *reporter, 512 void *priv_ctx, struct netlink_ext_ack *extack) 513 { 514 int err; 515 516 if (reporter->health_state == DEVLINK_HEALTH_REPORTER_STATE_HEALTHY) 517 return 0; 518 519 if (!reporter->ops->recover) 520 return -EOPNOTSUPP; 521 522 err = reporter->ops->recover(reporter, priv_ctx, extack); 523 if (err) 524 return err; 525 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); 529 530 return 0; 531 } 532 533 static void 534 devlink_health_dump_clear(struct devlink_health_reporter *reporter) 535 { 536 if (!reporter->dump_fmsg) 537 return; 538 devlink_fmsg_free(reporter->dump_fmsg); 539 reporter->dump_fmsg = NULL; 540 } 541 542 static int devlink_health_do_dump(struct devlink_health_reporter *reporter, 543 void *priv_ctx, 544 struct netlink_ext_ack *extack) 545 { 546 int err; 547 548 if (!reporter->ops->dump) 549 return 0; 550 551 if (reporter->dump_fmsg) 552 return 0; 553 554 reporter->dump_fmsg = devlink_fmsg_alloc(); 555 if (!reporter->dump_fmsg) { 556 err = -ENOMEM; 557 return err; 558 } 559 560 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg); 561 if (err) 562 goto dump_err; 563 564 err = reporter->ops->dump(reporter, reporter->dump_fmsg, 565 priv_ctx, extack); 566 if (err) 567 goto dump_err; 568 569 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg); 570 if (err) 571 goto dump_err; 572 573 reporter->dump_ts = jiffies; 574 reporter->dump_real_ts = ktime_get_real_ns(); 575 576 return 0; 577 578 dump_err: 579 devlink_health_dump_clear(reporter); 580 return err; 581 } 582 583 int devlink_health_report(struct devlink_health_reporter *reporter, 584 const char *msg, void *priv_ctx) 585 { 586 enum devlink_health_reporter_state prev_health_state; 587 struct devlink *devlink = reporter->devlink; 588 unsigned long recover_ts_threshold; 589 int ret; 590 591 /* write a log message of the current error */ 592 WARN_ON(!msg); 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); 598 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, 607 reporter->ops->name, 608 reporter->health_state, 609 jiffies - 610 reporter->last_recovery_ts); 611 return -ECANCELED; 612 } 613 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); 619 } 620 621 if (!reporter->auto_recover) 622 return 0; 623 624 devl_lock(devlink); 625 ret = devlink_health_reporter_recover(reporter, priv_ctx, NULL); 626 devl_unlock(devlink); 627 628 return ret; 629 } 630 EXPORT_SYMBOL_GPL(devlink_health_report); 631 632 void 633 devlink_health_reporter_state_update(struct devlink_health_reporter *reporter, 634 enum devlink_health_reporter_state state) 635 { 636 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY && 637 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR)) 638 return; 639 640 if (reporter->health_state == state) 641 return; 642 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); 647 } 648 EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update); 649 650 int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb, 651 struct genl_info *info) 652 { 653 struct devlink *devlink = info->user_ptr[0]; 654 struct devlink_health_reporter *reporter; 655 656 reporter = devlink_health_reporter_get_from_info(devlink, info); 657 if (!reporter) 658 return -EINVAL; 659 660 return devlink_health_reporter_recover(reporter, NULL, info->extack); 661 } 662 663 static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg, 664 int attrtype) 665 { 666 struct devlink_fmsg_item *item; 667 668 item = kzalloc(sizeof(*item), GFP_KERNEL); 669 if (!item) 670 return -ENOMEM; 671 672 item->attrtype = attrtype; 673 list_add_tail(&item->list, &fmsg->item_list); 674 675 return 0; 676 } 677 678 int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg) 679 { 680 if (fmsg->putting_binary) 681 return -EINVAL; 682 683 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START); 684 } 685 EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start); 686 687 static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg) 688 { 689 if (fmsg->putting_binary) 690 return -EINVAL; 691 692 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END); 693 } 694 695 int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg) 696 { 697 if (fmsg->putting_binary) 698 return -EINVAL; 699 700 return devlink_fmsg_nest_end(fmsg); 701 } 702 EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end); 703 704 #define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN) 705 706 static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name) 707 { 708 struct devlink_fmsg_item *item; 709 710 if (fmsg->putting_binary) 711 return -EINVAL; 712 713 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE) 714 return -EMSGSIZE; 715 716 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL); 717 if (!item) 718 return -ENOMEM; 719 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); 725 726 return 0; 727 } 728 729 int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name) 730 { 731 int err; 732 733 if (fmsg->putting_binary) 734 return -EINVAL; 735 736 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START); 737 if (err) 738 return err; 739 740 err = devlink_fmsg_put_name(fmsg, name); 741 if (err) 742 return err; 743 744 return 0; 745 } 746 EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start); 747 748 int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg) 749 { 750 if (fmsg->putting_binary) 751 return -EINVAL; 752 753 return devlink_fmsg_nest_end(fmsg); 754 } 755 EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end); 756 757 int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg, 758 const char *name) 759 { 760 int err; 761 762 if (fmsg->putting_binary) 763 return -EINVAL; 764 765 err = devlink_fmsg_pair_nest_start(fmsg, name); 766 if (err) 767 return err; 768 769 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START); 770 if (err) 771 return err; 772 773 return 0; 774 } 775 EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start); 776 777 int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg) 778 { 779 int err; 780 781 if (fmsg->putting_binary) 782 return -EINVAL; 783 784 err = devlink_fmsg_nest_end(fmsg); 785 if (err) 786 return err; 787 788 err = devlink_fmsg_nest_end(fmsg); 789 if (err) 790 return err; 791 792 return 0; 793 } 794 EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end); 795 796 int devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg, 797 const char *name) 798 { 799 int err; 800 801 err = devlink_fmsg_arr_pair_nest_start(fmsg, name); 802 if (err) 803 return err; 804 805 fmsg->putting_binary = true; 806 return err; 807 } 808 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start); 809 810 int devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg) 811 { 812 if (!fmsg->putting_binary) 813 return -EINVAL; 814 815 fmsg->putting_binary = false; 816 return devlink_fmsg_arr_pair_nest_end(fmsg); 817 } 818 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end); 819 820 static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg, 821 const void *value, u16 value_len, 822 u8 value_nla_type) 823 { 824 struct devlink_fmsg_item *item; 825 826 if (value_len > DEVLINK_FMSG_MAX_SIZE) 827 return -EMSGSIZE; 828 829 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL); 830 if (!item) 831 return -ENOMEM; 832 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); 838 839 return 0; 840 } 841 842 static int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value) 843 { 844 if (fmsg->putting_binary) 845 return -EINVAL; 846 847 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG); 848 } 849 850 static int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value) 851 { 852 if (fmsg->putting_binary) 853 return -EINVAL; 854 855 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8); 856 } 857 858 int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value) 859 { 860 if (fmsg->putting_binary) 861 return -EINVAL; 862 863 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32); 864 } 865 EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put); 866 867 static int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value) 868 { 869 if (fmsg->putting_binary) 870 return -EINVAL; 871 872 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64); 873 } 874 875 int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value) 876 { 877 if (fmsg->putting_binary) 878 return -EINVAL; 879 880 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1, 881 NLA_NUL_STRING); 882 } 883 EXPORT_SYMBOL_GPL(devlink_fmsg_string_put); 884 885 int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value, 886 u16 value_len) 887 { 888 if (!fmsg->putting_binary) 889 return -EINVAL; 890 891 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY); 892 } 893 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put); 894 895 int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name, 896 bool value) 897 { 898 int err; 899 900 err = devlink_fmsg_pair_nest_start(fmsg, name); 901 if (err) 902 return err; 903 904 err = devlink_fmsg_bool_put(fmsg, value); 905 if (err) 906 return err; 907 908 err = devlink_fmsg_pair_nest_end(fmsg); 909 if (err) 910 return err; 911 912 return 0; 913 } 914 EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put); 915 916 int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name, 917 u8 value) 918 { 919 int err; 920 921 err = devlink_fmsg_pair_nest_start(fmsg, name); 922 if (err) 923 return err; 924 925 err = devlink_fmsg_u8_put(fmsg, value); 926 if (err) 927 return err; 928 929 err = devlink_fmsg_pair_nest_end(fmsg); 930 if (err) 931 return err; 932 933 return 0; 934 } 935 EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put); 936 937 int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name, 938 u32 value) 939 { 940 int err; 941 942 err = devlink_fmsg_pair_nest_start(fmsg, name); 943 if (err) 944 return err; 945 946 err = devlink_fmsg_u32_put(fmsg, value); 947 if (err) 948 return err; 949 950 err = devlink_fmsg_pair_nest_end(fmsg); 951 if (err) 952 return err; 953 954 return 0; 955 } 956 EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put); 957 958 int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name, 959 u64 value) 960 { 961 int err; 962 963 err = devlink_fmsg_pair_nest_start(fmsg, name); 964 if (err) 965 return err; 966 967 err = devlink_fmsg_u64_put(fmsg, value); 968 if (err) 969 return err; 970 971 err = devlink_fmsg_pair_nest_end(fmsg); 972 if (err) 973 return err; 974 975 return 0; 976 } 977 EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put); 978 979 int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name, 980 const char *value) 981 { 982 int err; 983 984 err = devlink_fmsg_pair_nest_start(fmsg, name); 985 if (err) 986 return err; 987 988 err = devlink_fmsg_string_put(fmsg, value); 989 if (err) 990 return err; 991 992 err = devlink_fmsg_pair_nest_end(fmsg); 993 if (err) 994 return err; 995 996 return 0; 997 } 998 EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put); 999 1000 int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name, 1001 const void *value, u32 value_len) 1002 { 1003 u32 data_size; 1004 int end_err; 1005 u32 offset; 1006 int err; 1007 1008 err = devlink_fmsg_binary_pair_nest_start(fmsg, name); 1009 if (err) 1010 return err; 1011 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); 1017 if (err) 1018 break; 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 1022 */ 1023 } 1024 1025 end_err = devlink_fmsg_binary_pair_nest_end(fmsg); 1026 if (end_err) 1027 err = end_err; 1028 1029 return err; 1030 } 1031 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put); 1032 1033 static int 1034 devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb) 1035 { 1036 switch (msg->nla_type) { 1037 case NLA_FLAG: 1038 case NLA_U8: 1039 case NLA_U32: 1040 case NLA_U64: 1041 case NLA_NUL_STRING: 1042 case NLA_BINARY: 1043 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE, 1044 msg->nla_type); 1045 default: 1046 return -EINVAL; 1047 } 1048 } 1049 1050 static int 1051 devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb) 1052 { 1053 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA; 1054 u8 tmp; 1055 1056 switch (msg->nla_type) { 1057 case NLA_FLAG: 1058 /* Always provide flag data, regardless of its value */ 1059 tmp = *(bool *)msg->value; 1060 1061 return nla_put_u8(skb, attrtype, tmp); 1062 case NLA_U8: 1063 return nla_put_u8(skb, attrtype, *(u8 *)msg->value); 1064 case NLA_U32: 1065 return nla_put_u32(skb, attrtype, *(u32 *)msg->value); 1066 case NLA_U64: 1067 return nla_put_u64_64bit(skb, attrtype, *(u64 *)msg->value, 1068 DEVLINK_ATTR_PAD); 1069 case NLA_NUL_STRING: 1070 return nla_put_string(skb, attrtype, (char *)&msg->value); 1071 case NLA_BINARY: 1072 return nla_put(skb, attrtype, msg->len, (void *)&msg->value); 1073 default: 1074 return -EINVAL; 1075 } 1076 } 1077 1078 static int 1079 devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb, 1080 int *start) 1081 { 1082 struct devlink_fmsg_item *item; 1083 struct nlattr *fmsg_nlattr; 1084 int err = 0; 1085 int i = 0; 1086 1087 fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG); 1088 if (!fmsg_nlattr) 1089 return -EMSGSIZE; 1090 1091 list_for_each_entry(item, &fmsg->item_list, list) { 1092 if (i < *start) { 1093 i++; 1094 continue; 1095 } 1096 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); 1103 break; 1104 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA: 1105 err = devlink_fmsg_item_fill_type(item, skb); 1106 if (err) 1107 break; 1108 err = devlink_fmsg_item_fill_data(item, skb); 1109 break; 1110 case DEVLINK_ATTR_FMSG_OBJ_NAME: 1111 err = nla_put_string(skb, item->attrtype, 1112 (char *)&item->value); 1113 break; 1114 default: 1115 err = -EINVAL; 1116 break; 1117 } 1118 if (!err) 1119 *start = ++i; 1120 else 1121 break; 1122 } 1123 1124 nla_nest_end(skb, fmsg_nlattr); 1125 return err; 1126 } 1127 1128 static int devlink_fmsg_snd(struct devlink_fmsg *fmsg, 1129 struct genl_info *info, 1130 enum devlink_command cmd, int flags) 1131 { 1132 struct nlmsghdr *nlh; 1133 struct sk_buff *skb; 1134 bool last = false; 1135 int index = 0; 1136 void *hdr; 1137 int err; 1138 1139 while (!last) { 1140 int tmp_index = index; 1141 1142 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 1143 if (!skb) 1144 return -ENOMEM; 1145 1146 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq, 1147 &devlink_nl_family, flags | NLM_F_MULTI, cmd); 1148 if (!hdr) { 1149 err = -EMSGSIZE; 1150 goto nla_put_failure; 1151 } 1152 1153 err = devlink_fmsg_prepare_skb(fmsg, skb, &index); 1154 if (!err) 1155 last = true; 1156 else if (err != -EMSGSIZE || tmp_index == index) 1157 goto nla_put_failure; 1158 1159 genlmsg_end(skb, hdr); 1160 err = genlmsg_reply(skb, info); 1161 if (err) 1162 return err; 1163 } 1164 1165 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 1166 if (!skb) 1167 return -ENOMEM; 1168 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq, 1169 NLMSG_DONE, 0, flags | NLM_F_MULTI); 1170 if (!nlh) { 1171 err = -EMSGSIZE; 1172 goto nla_put_failure; 1173 } 1174 1175 return genlmsg_reply(skb, info); 1176 1177 nla_put_failure: 1178 nlmsg_free(skb); 1179 return err; 1180 } 1181 1182 static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb, 1183 struct netlink_callback *cb, 1184 enum devlink_command cmd) 1185 { 1186 struct devlink_nl_dump_state *state = devlink_dump_state(cb); 1187 int index = state->idx; 1188 int tmp_index = index; 1189 void *hdr; 1190 int err; 1191 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); 1194 if (!hdr) { 1195 err = -EMSGSIZE; 1196 goto nla_put_failure; 1197 } 1198 1199 err = devlink_fmsg_prepare_skb(fmsg, skb, &index); 1200 if ((err && err != -EMSGSIZE) || tmp_index == index) 1201 goto nla_put_failure; 1202 1203 state->idx = index; 1204 genlmsg_end(skb, hdr); 1205 return skb->len; 1206 1207 nla_put_failure: 1208 genlmsg_cancel(skb, hdr); 1209 return err; 1210 } 1211 1212 int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb, 1213 struct genl_info *info) 1214 { 1215 struct devlink *devlink = info->user_ptr[0]; 1216 struct devlink_health_reporter *reporter; 1217 struct devlink_fmsg *fmsg; 1218 int err; 1219 1220 reporter = devlink_health_reporter_get_from_info(devlink, info); 1221 if (!reporter) 1222 return -EINVAL; 1223 1224 if (!reporter->ops->diagnose) 1225 return -EOPNOTSUPP; 1226 1227 fmsg = devlink_fmsg_alloc(); 1228 if (!fmsg) 1229 return -ENOMEM; 1230 1231 err = devlink_fmsg_obj_nest_start(fmsg); 1232 if (err) 1233 goto out; 1234 1235 err = reporter->ops->diagnose(reporter, fmsg, info->extack); 1236 if (err) 1237 goto out; 1238 1239 err = devlink_fmsg_obj_nest_end(fmsg); 1240 if (err) 1241 goto out; 1242 1243 err = devlink_fmsg_snd(fmsg, info, 1244 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0); 1245 1246 out: 1247 devlink_fmsg_free(fmsg); 1248 return err; 1249 } 1250 1251 static struct devlink_health_reporter * 1252 devlink_health_reporter_get_from_cb(struct netlink_callback *cb) 1253 { 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; 1258 1259 devlink = devlink_get_from_attrs_lock(sock_net(cb->skb->sk), attrs); 1260 if (IS_ERR(devlink)) 1261 return NULL; 1262 devl_unlock(devlink); 1263 1264 reporter = devlink_health_reporter_get_from_attrs(devlink, attrs); 1265 devlink_put(devlink); 1266 return reporter; 1267 } 1268 1269 int devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb, 1270 struct netlink_callback *cb) 1271 { 1272 struct devlink_nl_dump_state *state = devlink_dump_state(cb); 1273 struct devlink_health_reporter *reporter; 1274 int err; 1275 1276 reporter = devlink_health_reporter_get_from_cb(cb); 1277 if (!reporter) 1278 return -EINVAL; 1279 1280 if (!reporter->ops->dump) 1281 return -EOPNOTSUPP; 1282 1283 mutex_lock(&reporter->dump_lock); 1284 if (!state->idx) { 1285 err = devlink_health_do_dump(reporter, NULL, cb->extack); 1286 if (err) 1287 goto unlock; 1288 state->dump_ts = reporter->dump_ts; 1289 } 1290 if (!reporter->dump_fmsg || state->dump_ts != reporter->dump_ts) { 1291 NL_SET_ERR_MSG(cb->extack, "Dump trampled, please retry"); 1292 err = -EAGAIN; 1293 goto unlock; 1294 } 1295 1296 err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb, 1297 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET); 1298 unlock: 1299 mutex_unlock(&reporter->dump_lock); 1300 return err; 1301 } 1302 1303 int devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb, 1304 struct genl_info *info) 1305 { 1306 struct devlink *devlink = info->user_ptr[0]; 1307 struct devlink_health_reporter *reporter; 1308 1309 reporter = devlink_health_reporter_get_from_info(devlink, info); 1310 if (!reporter) 1311 return -EINVAL; 1312 1313 if (!reporter->ops->dump) 1314 return -EOPNOTSUPP; 1315 1316 mutex_lock(&reporter->dump_lock); 1317 devlink_health_dump_clear(reporter); 1318 mutex_unlock(&reporter->dump_lock); 1319 return 0; 1320 } 1321 1322 int devlink_nl_cmd_health_reporter_test_doit(struct sk_buff *skb, 1323 struct genl_info *info) 1324 { 1325 struct devlink *devlink = info->user_ptr[0]; 1326 struct devlink_health_reporter *reporter; 1327 1328 reporter = devlink_health_reporter_get_from_info(devlink, info); 1329 if (!reporter) 1330 return -EINVAL; 1331 1332 if (!reporter->ops->test) 1333 return -EOPNOTSUPP; 1334 1335 return reporter->ops->test(reporter, info->extack); 1336 } 1337