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