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