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_cmd_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 388 devlink_nl_cmd_health_reporter_get_dump_one(struct sk_buff *msg, 389 struct devlink *devlink, 390 struct netlink_callback *cb) 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 NLM_F_MULTI); 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 NLM_F_MULTI); 426 if (err) { 427 state->idx = idx; 428 return err; 429 } 430 idx++; 431 } 432 } 433 434 return 0; 435 } 436 437 const struct devlink_cmd devl_cmd_health_reporter_get = { 438 .dump_one = devlink_nl_cmd_health_reporter_get_dump_one, 439 }; 440 441 int devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb, 442 struct genl_info *info) 443 { 444 struct devlink *devlink = info->user_ptr[0]; 445 struct devlink_health_reporter *reporter; 446 447 reporter = devlink_health_reporter_get_from_info(devlink, info); 448 if (!reporter) 449 return -EINVAL; 450 451 if (!reporter->ops->recover && 452 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] || 453 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) 454 return -EOPNOTSUPP; 455 456 if (!reporter->ops->dump && 457 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]) 458 return -EOPNOTSUPP; 459 460 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]) 461 reporter->graceful_period = 462 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]); 463 464 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]) 465 reporter->auto_recover = 466 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]); 467 468 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]) 469 reporter->auto_dump = 470 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]); 471 472 return 0; 473 } 474 475 static void devlink_recover_notify(struct devlink_health_reporter *reporter, 476 enum devlink_command cmd) 477 { 478 struct devlink *devlink = reporter->devlink; 479 struct sk_buff *msg; 480 int err; 481 482 WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER); 483 ASSERT_DEVLINK_REGISTERED(devlink); 484 485 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 486 if (!msg) 487 return; 488 489 err = devlink_nl_health_reporter_fill(msg, reporter, cmd, 0, 0, 0); 490 if (err) { 491 nlmsg_free(msg); 492 return; 493 } 494 495 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), msg, 496 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 497 } 498 499 void 500 devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter) 501 { 502 reporter->recovery_count++; 503 reporter->last_recovery_ts = jiffies; 504 } 505 EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done); 506 507 static int 508 devlink_health_reporter_recover(struct devlink_health_reporter *reporter, 509 void *priv_ctx, struct netlink_ext_ack *extack) 510 { 511 int err; 512 513 if (reporter->health_state == DEVLINK_HEALTH_REPORTER_STATE_HEALTHY) 514 return 0; 515 516 if (!reporter->ops->recover) 517 return -EOPNOTSUPP; 518 519 err = reporter->ops->recover(reporter, priv_ctx, extack); 520 if (err) 521 return err; 522 523 devlink_health_reporter_recovery_done(reporter); 524 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY; 525 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER); 526 527 return 0; 528 } 529 530 static void 531 devlink_health_dump_clear(struct devlink_health_reporter *reporter) 532 { 533 if (!reporter->dump_fmsg) 534 return; 535 devlink_fmsg_free(reporter->dump_fmsg); 536 reporter->dump_fmsg = NULL; 537 } 538 539 static int devlink_health_do_dump(struct devlink_health_reporter *reporter, 540 void *priv_ctx, 541 struct netlink_ext_ack *extack) 542 { 543 int err; 544 545 if (!reporter->ops->dump) 546 return 0; 547 548 if (reporter->dump_fmsg) 549 return 0; 550 551 reporter->dump_fmsg = devlink_fmsg_alloc(); 552 if (!reporter->dump_fmsg) { 553 err = -ENOMEM; 554 return err; 555 } 556 557 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg); 558 if (err) 559 goto dump_err; 560 561 err = reporter->ops->dump(reporter, reporter->dump_fmsg, 562 priv_ctx, extack); 563 if (err) 564 goto dump_err; 565 566 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg); 567 if (err) 568 goto dump_err; 569 570 reporter->dump_ts = jiffies; 571 reporter->dump_real_ts = ktime_get_real_ns(); 572 573 return 0; 574 575 dump_err: 576 devlink_health_dump_clear(reporter); 577 return err; 578 } 579 580 int devlink_health_report(struct devlink_health_reporter *reporter, 581 const char *msg, void *priv_ctx) 582 { 583 enum devlink_health_reporter_state prev_health_state; 584 struct devlink *devlink = reporter->devlink; 585 unsigned long recover_ts_threshold; 586 int ret; 587 588 /* write a log message of the current error */ 589 WARN_ON(!msg); 590 trace_devlink_health_report(devlink, reporter->ops->name, msg); 591 reporter->error_count++; 592 prev_health_state = reporter->health_state; 593 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR; 594 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER); 595 596 /* abort if the previous error wasn't recovered */ 597 recover_ts_threshold = reporter->last_recovery_ts + 598 msecs_to_jiffies(reporter->graceful_period); 599 if (reporter->auto_recover && 600 (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY || 601 (reporter->last_recovery_ts && reporter->recovery_count && 602 time_is_after_jiffies(recover_ts_threshold)))) { 603 trace_devlink_health_recover_aborted(devlink, 604 reporter->ops->name, 605 reporter->health_state, 606 jiffies - 607 reporter->last_recovery_ts); 608 return -ECANCELED; 609 } 610 611 if (reporter->auto_dump) { 612 mutex_lock(&reporter->dump_lock); 613 /* store current dump of current error, for later analysis */ 614 devlink_health_do_dump(reporter, priv_ctx, NULL); 615 mutex_unlock(&reporter->dump_lock); 616 } 617 618 if (!reporter->auto_recover) 619 return 0; 620 621 devl_lock(devlink); 622 ret = devlink_health_reporter_recover(reporter, priv_ctx, NULL); 623 devl_unlock(devlink); 624 625 return ret; 626 } 627 EXPORT_SYMBOL_GPL(devlink_health_report); 628 629 void 630 devlink_health_reporter_state_update(struct devlink_health_reporter *reporter, 631 enum devlink_health_reporter_state state) 632 { 633 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY && 634 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR)) 635 return; 636 637 if (reporter->health_state == state) 638 return; 639 640 reporter->health_state = state; 641 trace_devlink_health_reporter_state_update(reporter->devlink, 642 reporter->ops->name, state); 643 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER); 644 } 645 EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update); 646 647 int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb, 648 struct genl_info *info) 649 { 650 struct devlink *devlink = info->user_ptr[0]; 651 struct devlink_health_reporter *reporter; 652 653 reporter = devlink_health_reporter_get_from_info(devlink, info); 654 if (!reporter) 655 return -EINVAL; 656 657 return devlink_health_reporter_recover(reporter, NULL, info->extack); 658 } 659 660 static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg, 661 int attrtype) 662 { 663 struct devlink_fmsg_item *item; 664 665 item = kzalloc(sizeof(*item), GFP_KERNEL); 666 if (!item) 667 return -ENOMEM; 668 669 item->attrtype = attrtype; 670 list_add_tail(&item->list, &fmsg->item_list); 671 672 return 0; 673 } 674 675 int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg) 676 { 677 if (fmsg->putting_binary) 678 return -EINVAL; 679 680 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START); 681 } 682 EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start); 683 684 static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg) 685 { 686 if (fmsg->putting_binary) 687 return -EINVAL; 688 689 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END); 690 } 691 692 int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg) 693 { 694 if (fmsg->putting_binary) 695 return -EINVAL; 696 697 return devlink_fmsg_nest_end(fmsg); 698 } 699 EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end); 700 701 #define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN) 702 703 static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name) 704 { 705 struct devlink_fmsg_item *item; 706 707 if (fmsg->putting_binary) 708 return -EINVAL; 709 710 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE) 711 return -EMSGSIZE; 712 713 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL); 714 if (!item) 715 return -ENOMEM; 716 717 item->nla_type = NLA_NUL_STRING; 718 item->len = strlen(name) + 1; 719 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME; 720 memcpy(&item->value, name, item->len); 721 list_add_tail(&item->list, &fmsg->item_list); 722 723 return 0; 724 } 725 726 int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name) 727 { 728 int err; 729 730 if (fmsg->putting_binary) 731 return -EINVAL; 732 733 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START); 734 if (err) 735 return err; 736 737 err = devlink_fmsg_put_name(fmsg, name); 738 if (err) 739 return err; 740 741 return 0; 742 } 743 EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start); 744 745 int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg) 746 { 747 if (fmsg->putting_binary) 748 return -EINVAL; 749 750 return devlink_fmsg_nest_end(fmsg); 751 } 752 EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end); 753 754 int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg, 755 const char *name) 756 { 757 int err; 758 759 if (fmsg->putting_binary) 760 return -EINVAL; 761 762 err = devlink_fmsg_pair_nest_start(fmsg, name); 763 if (err) 764 return err; 765 766 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START); 767 if (err) 768 return err; 769 770 return 0; 771 } 772 EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start); 773 774 int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg) 775 { 776 int err; 777 778 if (fmsg->putting_binary) 779 return -EINVAL; 780 781 err = devlink_fmsg_nest_end(fmsg); 782 if (err) 783 return err; 784 785 err = devlink_fmsg_nest_end(fmsg); 786 if (err) 787 return err; 788 789 return 0; 790 } 791 EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end); 792 793 int devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg, 794 const char *name) 795 { 796 int err; 797 798 err = devlink_fmsg_arr_pair_nest_start(fmsg, name); 799 if (err) 800 return err; 801 802 fmsg->putting_binary = true; 803 return err; 804 } 805 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start); 806 807 int devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg) 808 { 809 if (!fmsg->putting_binary) 810 return -EINVAL; 811 812 fmsg->putting_binary = false; 813 return devlink_fmsg_arr_pair_nest_end(fmsg); 814 } 815 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end); 816 817 static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg, 818 const void *value, u16 value_len, 819 u8 value_nla_type) 820 { 821 struct devlink_fmsg_item *item; 822 823 if (value_len > DEVLINK_FMSG_MAX_SIZE) 824 return -EMSGSIZE; 825 826 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL); 827 if (!item) 828 return -ENOMEM; 829 830 item->nla_type = value_nla_type; 831 item->len = value_len; 832 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA; 833 memcpy(&item->value, value, item->len); 834 list_add_tail(&item->list, &fmsg->item_list); 835 836 return 0; 837 } 838 839 static int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value) 840 { 841 if (fmsg->putting_binary) 842 return -EINVAL; 843 844 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG); 845 } 846 847 static int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value) 848 { 849 if (fmsg->putting_binary) 850 return -EINVAL; 851 852 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8); 853 } 854 855 int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value) 856 { 857 if (fmsg->putting_binary) 858 return -EINVAL; 859 860 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32); 861 } 862 EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put); 863 864 static int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value) 865 { 866 if (fmsg->putting_binary) 867 return -EINVAL; 868 869 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64); 870 } 871 872 int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value) 873 { 874 if (fmsg->putting_binary) 875 return -EINVAL; 876 877 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1, 878 NLA_NUL_STRING); 879 } 880 EXPORT_SYMBOL_GPL(devlink_fmsg_string_put); 881 882 int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value, 883 u16 value_len) 884 { 885 if (!fmsg->putting_binary) 886 return -EINVAL; 887 888 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY); 889 } 890 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put); 891 892 int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name, 893 bool value) 894 { 895 int err; 896 897 err = devlink_fmsg_pair_nest_start(fmsg, name); 898 if (err) 899 return err; 900 901 err = devlink_fmsg_bool_put(fmsg, value); 902 if (err) 903 return err; 904 905 err = devlink_fmsg_pair_nest_end(fmsg); 906 if (err) 907 return err; 908 909 return 0; 910 } 911 EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put); 912 913 int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name, 914 u8 value) 915 { 916 int err; 917 918 err = devlink_fmsg_pair_nest_start(fmsg, name); 919 if (err) 920 return err; 921 922 err = devlink_fmsg_u8_put(fmsg, value); 923 if (err) 924 return err; 925 926 err = devlink_fmsg_pair_nest_end(fmsg); 927 if (err) 928 return err; 929 930 return 0; 931 } 932 EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put); 933 934 int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name, 935 u32 value) 936 { 937 int err; 938 939 err = devlink_fmsg_pair_nest_start(fmsg, name); 940 if (err) 941 return err; 942 943 err = devlink_fmsg_u32_put(fmsg, value); 944 if (err) 945 return err; 946 947 err = devlink_fmsg_pair_nest_end(fmsg); 948 if (err) 949 return err; 950 951 return 0; 952 } 953 EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put); 954 955 int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name, 956 u64 value) 957 { 958 int err; 959 960 err = devlink_fmsg_pair_nest_start(fmsg, name); 961 if (err) 962 return err; 963 964 err = devlink_fmsg_u64_put(fmsg, value); 965 if (err) 966 return err; 967 968 err = devlink_fmsg_pair_nest_end(fmsg); 969 if (err) 970 return err; 971 972 return 0; 973 } 974 EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put); 975 976 int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name, 977 const char *value) 978 { 979 int err; 980 981 err = devlink_fmsg_pair_nest_start(fmsg, name); 982 if (err) 983 return err; 984 985 err = devlink_fmsg_string_put(fmsg, value); 986 if (err) 987 return err; 988 989 err = devlink_fmsg_pair_nest_end(fmsg); 990 if (err) 991 return err; 992 993 return 0; 994 } 995 EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put); 996 997 int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name, 998 const void *value, u32 value_len) 999 { 1000 u32 data_size; 1001 int end_err; 1002 u32 offset; 1003 int err; 1004 1005 err = devlink_fmsg_binary_pair_nest_start(fmsg, name); 1006 if (err) 1007 return err; 1008 1009 for (offset = 0; offset < value_len; offset += data_size) { 1010 data_size = value_len - offset; 1011 if (data_size > DEVLINK_FMSG_MAX_SIZE) 1012 data_size = DEVLINK_FMSG_MAX_SIZE; 1013 err = devlink_fmsg_binary_put(fmsg, value + offset, data_size); 1014 if (err) 1015 break; 1016 /* Exit from loop with a break (instead of 1017 * return) to make sure putting_binary is turned off in 1018 * devlink_fmsg_binary_pair_nest_end 1019 */ 1020 } 1021 1022 end_err = devlink_fmsg_binary_pair_nest_end(fmsg); 1023 if (end_err) 1024 err = end_err; 1025 1026 return err; 1027 } 1028 EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put); 1029 1030 static int 1031 devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb) 1032 { 1033 switch (msg->nla_type) { 1034 case NLA_FLAG: 1035 case NLA_U8: 1036 case NLA_U32: 1037 case NLA_U64: 1038 case NLA_NUL_STRING: 1039 case NLA_BINARY: 1040 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE, 1041 msg->nla_type); 1042 default: 1043 return -EINVAL; 1044 } 1045 } 1046 1047 static int 1048 devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb) 1049 { 1050 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA; 1051 u8 tmp; 1052 1053 switch (msg->nla_type) { 1054 case NLA_FLAG: 1055 /* Always provide flag data, regardless of its value */ 1056 tmp = *(bool *)msg->value; 1057 1058 return nla_put_u8(skb, attrtype, tmp); 1059 case NLA_U8: 1060 return nla_put_u8(skb, attrtype, *(u8 *)msg->value); 1061 case NLA_U32: 1062 return nla_put_u32(skb, attrtype, *(u32 *)msg->value); 1063 case NLA_U64: 1064 return nla_put_u64_64bit(skb, attrtype, *(u64 *)msg->value, 1065 DEVLINK_ATTR_PAD); 1066 case NLA_NUL_STRING: 1067 return nla_put_string(skb, attrtype, (char *)&msg->value); 1068 case NLA_BINARY: 1069 return nla_put(skb, attrtype, msg->len, (void *)&msg->value); 1070 default: 1071 return -EINVAL; 1072 } 1073 } 1074 1075 static int 1076 devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb, 1077 int *start) 1078 { 1079 struct devlink_fmsg_item *item; 1080 struct nlattr *fmsg_nlattr; 1081 int err = 0; 1082 int i = 0; 1083 1084 fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG); 1085 if (!fmsg_nlattr) 1086 return -EMSGSIZE; 1087 1088 list_for_each_entry(item, &fmsg->item_list, list) { 1089 if (i < *start) { 1090 i++; 1091 continue; 1092 } 1093 1094 switch (item->attrtype) { 1095 case DEVLINK_ATTR_FMSG_OBJ_NEST_START: 1096 case DEVLINK_ATTR_FMSG_PAIR_NEST_START: 1097 case DEVLINK_ATTR_FMSG_ARR_NEST_START: 1098 case DEVLINK_ATTR_FMSG_NEST_END: 1099 err = nla_put_flag(skb, item->attrtype); 1100 break; 1101 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA: 1102 err = devlink_fmsg_item_fill_type(item, skb); 1103 if (err) 1104 break; 1105 err = devlink_fmsg_item_fill_data(item, skb); 1106 break; 1107 case DEVLINK_ATTR_FMSG_OBJ_NAME: 1108 err = nla_put_string(skb, item->attrtype, 1109 (char *)&item->value); 1110 break; 1111 default: 1112 err = -EINVAL; 1113 break; 1114 } 1115 if (!err) 1116 *start = ++i; 1117 else 1118 break; 1119 } 1120 1121 nla_nest_end(skb, fmsg_nlattr); 1122 return err; 1123 } 1124 1125 static int devlink_fmsg_snd(struct devlink_fmsg *fmsg, 1126 struct genl_info *info, 1127 enum devlink_command cmd, int flags) 1128 { 1129 struct nlmsghdr *nlh; 1130 struct sk_buff *skb; 1131 bool last = false; 1132 int index = 0; 1133 void *hdr; 1134 int err; 1135 1136 while (!last) { 1137 int tmp_index = index; 1138 1139 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 1140 if (!skb) 1141 return -ENOMEM; 1142 1143 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq, 1144 &devlink_nl_family, flags | NLM_F_MULTI, cmd); 1145 if (!hdr) { 1146 err = -EMSGSIZE; 1147 goto nla_put_failure; 1148 } 1149 1150 err = devlink_fmsg_prepare_skb(fmsg, skb, &index); 1151 if (!err) 1152 last = true; 1153 else if (err != -EMSGSIZE || tmp_index == index) 1154 goto nla_put_failure; 1155 1156 genlmsg_end(skb, hdr); 1157 err = genlmsg_reply(skb, info); 1158 if (err) 1159 return err; 1160 } 1161 1162 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 1163 if (!skb) 1164 return -ENOMEM; 1165 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq, 1166 NLMSG_DONE, 0, flags | NLM_F_MULTI); 1167 if (!nlh) { 1168 err = -EMSGSIZE; 1169 goto nla_put_failure; 1170 } 1171 1172 return genlmsg_reply(skb, info); 1173 1174 nla_put_failure: 1175 nlmsg_free(skb); 1176 return err; 1177 } 1178 1179 static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb, 1180 struct netlink_callback *cb, 1181 enum devlink_command cmd) 1182 { 1183 struct devlink_nl_dump_state *state = devlink_dump_state(cb); 1184 int index = state->idx; 1185 int tmp_index = index; 1186 void *hdr; 1187 int err; 1188 1189 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 1190 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd); 1191 if (!hdr) { 1192 err = -EMSGSIZE; 1193 goto nla_put_failure; 1194 } 1195 1196 err = devlink_fmsg_prepare_skb(fmsg, skb, &index); 1197 if ((err && err != -EMSGSIZE) || tmp_index == index) 1198 goto nla_put_failure; 1199 1200 state->idx = index; 1201 genlmsg_end(skb, hdr); 1202 return skb->len; 1203 1204 nla_put_failure: 1205 genlmsg_cancel(skb, hdr); 1206 return err; 1207 } 1208 1209 int devlink_nl_cmd_health_reporter_diagnose_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 struct devlink_fmsg *fmsg; 1215 int err; 1216 1217 reporter = devlink_health_reporter_get_from_info(devlink, info); 1218 if (!reporter) 1219 return -EINVAL; 1220 1221 if (!reporter->ops->diagnose) 1222 return -EOPNOTSUPP; 1223 1224 fmsg = devlink_fmsg_alloc(); 1225 if (!fmsg) 1226 return -ENOMEM; 1227 1228 err = devlink_fmsg_obj_nest_start(fmsg); 1229 if (err) 1230 goto out; 1231 1232 err = reporter->ops->diagnose(reporter, fmsg, info->extack); 1233 if (err) 1234 goto out; 1235 1236 err = devlink_fmsg_obj_nest_end(fmsg); 1237 if (err) 1238 goto out; 1239 1240 err = devlink_fmsg_snd(fmsg, info, 1241 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0); 1242 1243 out: 1244 devlink_fmsg_free(fmsg); 1245 return err; 1246 } 1247 1248 static struct devlink_health_reporter * 1249 devlink_health_reporter_get_from_cb(struct netlink_callback *cb) 1250 { 1251 const struct genl_dumpit_info *info = genl_dumpit_info(cb); 1252 struct devlink_health_reporter *reporter; 1253 struct nlattr **attrs = info->attrs; 1254 struct devlink *devlink; 1255 1256 devlink = devlink_get_from_attrs_lock(sock_net(cb->skb->sk), attrs); 1257 if (IS_ERR(devlink)) 1258 return NULL; 1259 devl_unlock(devlink); 1260 1261 reporter = devlink_health_reporter_get_from_attrs(devlink, attrs); 1262 devlink_put(devlink); 1263 return reporter; 1264 } 1265 1266 int devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb, 1267 struct netlink_callback *cb) 1268 { 1269 struct devlink_nl_dump_state *state = devlink_dump_state(cb); 1270 struct devlink_health_reporter *reporter; 1271 int err; 1272 1273 reporter = devlink_health_reporter_get_from_cb(cb); 1274 if (!reporter) 1275 return -EINVAL; 1276 1277 if (!reporter->ops->dump) 1278 return -EOPNOTSUPP; 1279 1280 mutex_lock(&reporter->dump_lock); 1281 if (!state->idx) { 1282 err = devlink_health_do_dump(reporter, NULL, cb->extack); 1283 if (err) 1284 goto unlock; 1285 state->dump_ts = reporter->dump_ts; 1286 } 1287 if (!reporter->dump_fmsg || state->dump_ts != reporter->dump_ts) { 1288 NL_SET_ERR_MSG(cb->extack, "Dump trampled, please retry"); 1289 err = -EAGAIN; 1290 goto unlock; 1291 } 1292 1293 err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb, 1294 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET); 1295 unlock: 1296 mutex_unlock(&reporter->dump_lock); 1297 return err; 1298 } 1299 1300 int devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb, 1301 struct genl_info *info) 1302 { 1303 struct devlink *devlink = info->user_ptr[0]; 1304 struct devlink_health_reporter *reporter; 1305 1306 reporter = devlink_health_reporter_get_from_info(devlink, info); 1307 if (!reporter) 1308 return -EINVAL; 1309 1310 if (!reporter->ops->dump) 1311 return -EOPNOTSUPP; 1312 1313 mutex_lock(&reporter->dump_lock); 1314 devlink_health_dump_clear(reporter); 1315 mutex_unlock(&reporter->dump_lock); 1316 return 0; 1317 } 1318 1319 int devlink_nl_cmd_health_reporter_test_doit(struct sk_buff *skb, 1320 struct genl_info *info) 1321 { 1322 struct devlink *devlink = info->user_ptr[0]; 1323 struct devlink_health_reporter *reporter; 1324 1325 reporter = devlink_health_reporter_get_from_info(devlink, info); 1326 if (!reporter) 1327 return -EINVAL; 1328 1329 if (!reporter->ops->test) 1330 return -EOPNOTSUPP; 1331 1332 return reporter->ops->test(reporter, info->extack); 1333 } 1334