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