hc
2024-01-05 071106ecf68c401173c58808b1cf5f68cc50d390
kernel/net/core/devlink.c
....@@ -1,14 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * net/core/devlink.c - Network physical/parent device Netlink interface
34 *
45 * Heavily inspired by net/wireless/
56 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
67 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
7
- *
8
- * This program is free software; you can redistribute it and/or modify
9
- * it under the terms of the GNU General Public License as published by
10
- * the Free Software Foundation; either version 2 of the License, or
11
- * (at your option) any later version.
128 */
139
1410 #include <linux/kernel.h>
....@@ -19,6 +15,11 @@
1915 #include <linux/device.h>
2016 #include <linux/list.h>
2117 #include <linux/netdevice.h>
18
+#include <linux/spinlock.h>
19
+#include <linux/refcount.h>
20
+#include <linux/workqueue.h>
21
+#include <linux/u64_stats_sync.h>
22
+#include <linux/timekeeping.h>
2223 #include <rdma/ib_verbs.h>
2324 #include <net/netlink.h>
2425 #include <net/genetlink.h>
....@@ -81,6 +82,12 @@
8182 EXPORT_SYMBOL(devlink_dpipe_header_ipv6);
8283
8384 EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg);
85
+EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwerr);
86
+EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_trap_report);
87
+
88
+static const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = {
89
+ [DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] = { .type = NLA_BINARY },
90
+};
8491
8592 static LIST_HEAD(devlink_list);
8693
....@@ -92,15 +99,24 @@
9299 */
93100 static DEFINE_MUTEX(devlink_mutex);
94101
95
-static struct net *devlink_net(const struct devlink *devlink)
102
+struct net *devlink_net(const struct devlink *devlink)
96103 {
97104 return read_pnet(&devlink->_net);
98105 }
106
+EXPORT_SYMBOL_GPL(devlink_net);
99107
100
-static void devlink_net_set(struct devlink *devlink, struct net *net)
108
+static void __devlink_net_set(struct devlink *devlink, struct net *net)
101109 {
102110 write_pnet(&devlink->_net, net);
103111 }
112
+
113
+void devlink_net_set(struct devlink *devlink, struct net *net)
114
+{
115
+ if (WARN_ON(devlink->registered))
116
+ return;
117
+ __devlink_net_set(devlink, net);
118
+}
119
+EXPORT_SYMBOL_GPL(devlink_net_set);
104120
105121 static struct devlink *devlink_get_from_attrs(struct net *net,
106122 struct nlattr **attrs)
....@@ -114,6 +130,8 @@
114130
115131 busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
116132 devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
133
+
134
+ lockdep_assert_held(&devlink_mutex);
117135
118136 list_for_each_entry(devlink, &devlink_list, list) {
119137 if (strcmp(devlink->dev->bus->name, busname) == 0 &&
....@@ -131,7 +149,7 @@
131149 }
132150
133151 static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
134
- int port_index)
152
+ unsigned int port_index)
135153 {
136154 struct devlink_port *devlink_port;
137155
....@@ -142,7 +160,8 @@
142160 return NULL;
143161 }
144162
145
-static bool devlink_port_index_exists(struct devlink *devlink, int port_index)
163
+static bool devlink_port_index_exists(struct devlink *devlink,
164
+ unsigned int port_index)
146165 {
147166 return devlink_port_get_by_index(devlink, port_index);
148167 }
....@@ -328,8 +347,12 @@
328347
329348 struct devlink_region {
330349 struct devlink *devlink;
350
+ struct devlink_port *port;
331351 struct list_head list;
332
- const char *name;
352
+ union {
353
+ const struct devlink_region_ops *ops;
354
+ const struct devlink_port_region_ops *port_ops;
355
+ };
333356 struct list_head snapshot_list;
334357 u32 max_snapshots;
335358 u32 cur_snapshots;
....@@ -339,8 +362,6 @@
339362 struct devlink_snapshot {
340363 struct list_head list;
341364 struct devlink_region *region;
342
- devlink_snapshot_data_dest_t *data_destructor;
343
- u64 data_len;
344365 u8 *data;
345366 u32 id;
346367 };
....@@ -351,7 +372,20 @@
351372 struct devlink_region *region;
352373
353374 list_for_each_entry(region, &devlink->region_list, list)
354
- if (!strcmp(region->name, region_name))
375
+ if (!strcmp(region->ops->name, region_name))
376
+ return region;
377
+
378
+ return NULL;
379
+}
380
+
381
+static struct devlink_region *
382
+devlink_port_region_get_by_name(struct devlink_port *port,
383
+ const char *region_name)
384
+{
385
+ struct devlink_region *region;
386
+
387
+ list_for_each_entry(region, &port->region_list, list)
388
+ if (!strcmp(region->ops->name, region_name))
355389 return region;
356390
357391 return NULL;
....@@ -369,27 +403,19 @@
369403 return NULL;
370404 }
371405
372
-static void devlink_region_snapshot_del(struct devlink_snapshot *snapshot)
373
-{
374
- snapshot->region->cur_snapshots--;
375
- list_del(&snapshot->list);
376
- (*snapshot->data_destructor)(snapshot->data);
377
- kfree(snapshot);
378
-}
379
-
380
-#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
381
-#define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
382
-#define DEVLINK_NL_FLAG_NEED_SB BIT(2)
406
+#define DEVLINK_NL_FLAG_NEED_PORT BIT(0)
407
+#define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(1)
383408
384409 /* The per devlink instance lock is taken by default in the pre-doit
385410 * operation, yet several commands do not require this. The global
386411 * devlink lock is taken and protects from disruption by user-calls.
387412 */
388
-#define DEVLINK_NL_FLAG_NO_LOCK BIT(3)
413
+#define DEVLINK_NL_FLAG_NO_LOCK BIT(2)
389414
390415 static int devlink_nl_pre_doit(const struct genl_ops *ops,
391416 struct sk_buff *skb, struct genl_info *info)
392417 {
418
+ struct devlink_port *devlink_port;
393419 struct devlink *devlink;
394420 int err;
395421
....@@ -401,27 +427,18 @@
401427 }
402428 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
403429 mutex_lock(&devlink->lock);
404
- if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
405
- info->user_ptr[0] = devlink;
406
- } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
407
- struct devlink_port *devlink_port;
408
-
430
+ info->user_ptr[0] = devlink;
431
+ if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
409432 devlink_port = devlink_port_get_from_info(devlink, info);
410433 if (IS_ERR(devlink_port)) {
411434 err = PTR_ERR(devlink_port);
412435 goto unlock;
413436 }
414
- info->user_ptr[0] = devlink_port;
415
- }
416
- if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) {
417
- struct devlink_sb *devlink_sb;
418
-
419
- devlink_sb = devlink_sb_get_from_info(devlink, info);
420
- if (IS_ERR(devlink_sb)) {
421
- err = PTR_ERR(devlink_sb);
422
- goto unlock;
423
- }
424
- info->user_ptr[1] = devlink_sb;
437
+ info->user_ptr[1] = devlink_port;
438
+ } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
439
+ devlink_port = devlink_port_get_from_info(devlink, info);
440
+ if (!IS_ERR(devlink_port))
441
+ info->user_ptr[1] = devlink_port;
425442 }
426443 return 0;
427444
....@@ -437,7 +454,7 @@
437454 {
438455 struct devlink *devlink;
439456
440
- devlink = devlink_get_from_info(info);
457
+ devlink = info->user_ptr[0];
441458 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
442459 mutex_unlock(&devlink->lock);
443460 mutex_unlock(&devlink_mutex);
....@@ -462,10 +479,132 @@
462479 return 0;
463480 }
464481
482
+struct devlink_reload_combination {
483
+ enum devlink_reload_action action;
484
+ enum devlink_reload_limit limit;
485
+};
486
+
487
+static const struct devlink_reload_combination devlink_reload_invalid_combinations[] = {
488
+ {
489
+ /* can't reinitialize driver with no down time */
490
+ .action = DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
491
+ .limit = DEVLINK_RELOAD_LIMIT_NO_RESET,
492
+ },
493
+};
494
+
495
+static bool
496
+devlink_reload_combination_is_invalid(enum devlink_reload_action action,
497
+ enum devlink_reload_limit limit)
498
+{
499
+ int i;
500
+
501
+ for (i = 0; i < ARRAY_SIZE(devlink_reload_invalid_combinations); i++)
502
+ if (devlink_reload_invalid_combinations[i].action == action &&
503
+ devlink_reload_invalid_combinations[i].limit == limit)
504
+ return true;
505
+ return false;
506
+}
507
+
508
+static bool
509
+devlink_reload_action_is_supported(struct devlink *devlink, enum devlink_reload_action action)
510
+{
511
+ return test_bit(action, &devlink->ops->reload_actions);
512
+}
513
+
514
+static bool
515
+devlink_reload_limit_is_supported(struct devlink *devlink, enum devlink_reload_limit limit)
516
+{
517
+ return test_bit(limit, &devlink->ops->reload_limits);
518
+}
519
+
520
+static int devlink_reload_stat_put(struct sk_buff *msg,
521
+ enum devlink_reload_limit limit, u32 value)
522
+{
523
+ struct nlattr *reload_stats_entry;
524
+
525
+ reload_stats_entry = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_STATS_ENTRY);
526
+ if (!reload_stats_entry)
527
+ return -EMSGSIZE;
528
+
529
+ if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_STATS_LIMIT, limit) ||
530
+ nla_put_u32(msg, DEVLINK_ATTR_RELOAD_STATS_VALUE, value))
531
+ goto nla_put_failure;
532
+ nla_nest_end(msg, reload_stats_entry);
533
+ return 0;
534
+
535
+nla_put_failure:
536
+ nla_nest_cancel(msg, reload_stats_entry);
537
+ return -EMSGSIZE;
538
+}
539
+
540
+static int devlink_reload_stats_put(struct sk_buff *msg, struct devlink *devlink, bool is_remote)
541
+{
542
+ struct nlattr *reload_stats_attr, *act_info, *act_stats;
543
+ int i, j, stat_idx;
544
+ u32 value;
545
+
546
+ if (!is_remote)
547
+ reload_stats_attr = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_STATS);
548
+ else
549
+ reload_stats_attr = nla_nest_start(msg, DEVLINK_ATTR_REMOTE_RELOAD_STATS);
550
+
551
+ if (!reload_stats_attr)
552
+ return -EMSGSIZE;
553
+
554
+ for (i = 0; i <= DEVLINK_RELOAD_ACTION_MAX; i++) {
555
+ if ((!is_remote &&
556
+ !devlink_reload_action_is_supported(devlink, i)) ||
557
+ i == DEVLINK_RELOAD_ACTION_UNSPEC)
558
+ continue;
559
+ act_info = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_ACTION_INFO);
560
+ if (!act_info)
561
+ goto nla_put_failure;
562
+
563
+ if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_ACTION, i))
564
+ goto action_info_nest_cancel;
565
+ act_stats = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_ACTION_STATS);
566
+ if (!act_stats)
567
+ goto action_info_nest_cancel;
568
+
569
+ for (j = 0; j <= DEVLINK_RELOAD_LIMIT_MAX; j++) {
570
+ /* Remote stats are shown even if not locally supported.
571
+ * Stats of actions with unspecified limit are shown
572
+ * though drivers don't need to register unspecified
573
+ * limit.
574
+ */
575
+ if ((!is_remote && j != DEVLINK_RELOAD_LIMIT_UNSPEC &&
576
+ !devlink_reload_limit_is_supported(devlink, j)) ||
577
+ devlink_reload_combination_is_invalid(i, j))
578
+ continue;
579
+
580
+ stat_idx = j * __DEVLINK_RELOAD_ACTION_MAX + i;
581
+ if (!is_remote)
582
+ value = devlink->stats.reload_stats[stat_idx];
583
+ else
584
+ value = devlink->stats.remote_reload_stats[stat_idx];
585
+ if (devlink_reload_stat_put(msg, j, value))
586
+ goto action_stats_nest_cancel;
587
+ }
588
+ nla_nest_end(msg, act_stats);
589
+ nla_nest_end(msg, act_info);
590
+ }
591
+ nla_nest_end(msg, reload_stats_attr);
592
+ return 0;
593
+
594
+action_stats_nest_cancel:
595
+ nla_nest_cancel(msg, act_stats);
596
+action_info_nest_cancel:
597
+ nla_nest_cancel(msg, act_info);
598
+nla_put_failure:
599
+ nla_nest_cancel(msg, reload_stats_attr);
600
+ return -EMSGSIZE;
601
+}
602
+
465603 static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
466604 enum devlink_command cmd, u32 portid,
467605 u32 seq, int flags)
468606 {
607
+ struct nlattr *dev_stats;
469608 void *hdr;
470609
471610 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
....@@ -474,10 +613,24 @@
474613
475614 if (devlink_nl_put_handle(msg, devlink))
476615 goto nla_put_failure;
616
+ if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_FAILED, devlink->reload_failed))
617
+ goto nla_put_failure;
477618
619
+ dev_stats = nla_nest_start(msg, DEVLINK_ATTR_DEV_STATS);
620
+ if (!dev_stats)
621
+ goto nla_put_failure;
622
+
623
+ if (devlink_reload_stats_put(msg, devlink, false))
624
+ goto dev_stats_nest_cancel;
625
+ if (devlink_reload_stats_put(msg, devlink, true))
626
+ goto dev_stats_nest_cancel;
627
+
628
+ nla_nest_end(msg, dev_stats);
478629 genlmsg_end(msg, hdr);
479630 return 0;
480631
632
+dev_stats_nest_cancel:
633
+ nla_nest_cancel(msg, dev_stats);
481634 nla_put_failure:
482635 genlmsg_cancel(msg, hdr);
483636 return -EMSGSIZE;
....@@ -509,26 +662,103 @@
509662 {
510663 struct devlink_port_attrs *attrs = &devlink_port->attrs;
511664
512
- if (!attrs->set)
665
+ if (!devlink_port->attrs_set)
513666 return 0;
667
+ if (attrs->lanes) {
668
+ if (nla_put_u32(msg, DEVLINK_ATTR_PORT_LANES, attrs->lanes))
669
+ return -EMSGSIZE;
670
+ }
671
+ if (nla_put_u8(msg, DEVLINK_ATTR_PORT_SPLITTABLE, attrs->splittable))
672
+ return -EMSGSIZE;
514673 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
515674 return -EMSGSIZE;
516
- if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER, attrs->port_number))
517
- return -EMSGSIZE;
518
- if (!attrs->split)
519
- return 0;
520
- if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP, attrs->port_number))
521
- return -EMSGSIZE;
522
- if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
523
- attrs->split_subport_number))
524
- return -EMSGSIZE;
675
+ switch (devlink_port->attrs.flavour) {
676
+ case DEVLINK_PORT_FLAVOUR_PCI_PF:
677
+ if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER,
678
+ attrs->pci_pf.controller) ||
679
+ nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, attrs->pci_pf.pf))
680
+ return -EMSGSIZE;
681
+ if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_pf.external))
682
+ return -EMSGSIZE;
683
+ break;
684
+ case DEVLINK_PORT_FLAVOUR_PCI_VF:
685
+ if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER,
686
+ attrs->pci_vf.controller) ||
687
+ nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, attrs->pci_vf.pf) ||
688
+ nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_VF_NUMBER, attrs->pci_vf.vf))
689
+ return -EMSGSIZE;
690
+ if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_vf.external))
691
+ return -EMSGSIZE;
692
+ break;
693
+ case DEVLINK_PORT_FLAVOUR_PHYSICAL:
694
+ case DEVLINK_PORT_FLAVOUR_CPU:
695
+ case DEVLINK_PORT_FLAVOUR_DSA:
696
+ if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER,
697
+ attrs->phys.port_number))
698
+ return -EMSGSIZE;
699
+ if (!attrs->split)
700
+ return 0;
701
+ if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP,
702
+ attrs->phys.port_number))
703
+ return -EMSGSIZE;
704
+ if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
705
+ attrs->phys.split_subport_number))
706
+ return -EMSGSIZE;
707
+ break;
708
+ default:
709
+ break;
710
+ }
525711 return 0;
712
+}
713
+
714
+static int
715
+devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *port,
716
+ struct netlink_ext_ack *extack)
717
+{
718
+ struct devlink *devlink = port->devlink;
719
+ const struct devlink_ops *ops;
720
+ struct nlattr *function_attr;
721
+ bool empty_nest = true;
722
+ int err = 0;
723
+
724
+ function_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PORT_FUNCTION);
725
+ if (!function_attr)
726
+ return -EMSGSIZE;
727
+
728
+ ops = devlink->ops;
729
+ if (ops->port_function_hw_addr_get) {
730
+ int hw_addr_len;
731
+ u8 hw_addr[MAX_ADDR_LEN];
732
+
733
+ err = ops->port_function_hw_addr_get(devlink, port, hw_addr, &hw_addr_len, extack);
734
+ if (err == -EOPNOTSUPP) {
735
+ /* Port function attributes are optional for a port. If port doesn't
736
+ * support function attribute, returning -EOPNOTSUPP is not an error.
737
+ */
738
+ err = 0;
739
+ goto out;
740
+ } else if (err) {
741
+ goto out;
742
+ }
743
+ err = nla_put(msg, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, hw_addr_len, hw_addr);
744
+ if (err)
745
+ goto out;
746
+ empty_nest = false;
747
+ }
748
+
749
+out:
750
+ if (err || empty_nest)
751
+ nla_nest_cancel(msg, function_attr);
752
+ else
753
+ nla_nest_end(msg, function_attr);
754
+ return err;
526755 }
527756
528757 static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
529758 struct devlink_port *devlink_port,
530759 enum devlink_command cmd, u32 portid,
531
- u32 seq, int flags)
760
+ u32 seq, int flags,
761
+ struct netlink_ext_ack *extack)
532762 {
533763 void *hdr;
534764
....@@ -540,21 +770,26 @@
540770 goto nla_put_failure;
541771 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
542772 goto nla_put_failure;
773
+
774
+ /* Hold rtnl lock while accessing port's netdev attributes. */
775
+ rtnl_lock();
776
+ spin_lock_bh(&devlink_port->type_lock);
543777 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
544
- goto nla_put_failure;
778
+ goto nla_put_failure_type_locked;
545779 if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
546780 nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
547781 devlink_port->desired_type))
548
- goto nla_put_failure;
782
+ goto nla_put_failure_type_locked;
549783 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
784
+ struct net *net = devlink_net(devlink_port->devlink);
550785 struct net_device *netdev = devlink_port->type_dev;
551786
552
- if (netdev &&
787
+ if (netdev && net_eq(net, dev_net(netdev)) &&
553788 (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
554789 netdev->ifindex) ||
555790 nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
556791 netdev->name)))
557
- goto nla_put_failure;
792
+ goto nla_put_failure_type_locked;
558793 }
559794 if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
560795 struct ib_device *ibdev = devlink_port->type_dev;
....@@ -562,14 +797,21 @@
562797 if (ibdev &&
563798 nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
564799 ibdev->name))
565
- goto nla_put_failure;
800
+ goto nla_put_failure_type_locked;
566801 }
802
+ spin_unlock_bh(&devlink_port->type_lock);
803
+ rtnl_unlock();
567804 if (devlink_nl_port_attrs_put(msg, devlink_port))
805
+ goto nla_put_failure;
806
+ if (devlink_nl_port_function_attrs_put(msg, devlink_port, extack))
568807 goto nla_put_failure;
569808
570809 genlmsg_end(msg, hdr);
571810 return 0;
572811
812
+nla_put_failure_type_locked:
813
+ spin_unlock_bh(&devlink_port->type_lock);
814
+ rtnl_unlock();
573815 nla_put_failure:
574816 genlmsg_cancel(msg, hdr);
575817 return -EMSGSIZE;
....@@ -591,7 +833,8 @@
591833 if (!msg)
592834 return;
593835
594
- err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0);
836
+ err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0,
837
+ NULL);
595838 if (err) {
596839 nlmsg_free(msg);
597840 return;
....@@ -654,7 +897,7 @@
654897 static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
655898 struct genl_info *info)
656899 {
657
- struct devlink_port *devlink_port = info->user_ptr[0];
900
+ struct devlink_port *devlink_port = info->user_ptr[1];
658901 struct devlink *devlink = devlink_port->devlink;
659902 struct sk_buff *msg;
660903 int err;
....@@ -665,7 +908,8 @@
665908
666909 err = devlink_nl_port_fill(msg, devlink, devlink_port,
667910 DEVLINK_CMD_PORT_NEW,
668
- info->snd_portid, info->snd_seq, 0);
911
+ info->snd_portid, info->snd_seq, 0,
912
+ info->extack);
669913 if (err) {
670914 nlmsg_free(msg);
671915 return err;
....@@ -697,7 +941,8 @@
697941 DEVLINK_CMD_NEW,
698942 NETLINK_CB(cb->skb).portid,
699943 cb->nlh->nlmsg_seq,
700
- NLM_F_MULTI);
944
+ NLM_F_MULTI,
945
+ cb->extack);
701946 if (err) {
702947 mutex_unlock(&devlink->lock);
703948 goto out;
....@@ -720,9 +965,7 @@
720965 {
721966 int err;
722967
723
- if (devlink->ops && devlink->ops->port_type_set) {
724
- if (port_type == DEVLINK_PORT_TYPE_NOTSET)
725
- return -EINVAL;
968
+ if (devlink->ops->port_type_set) {
726969 if (port_type == devlink_port->type)
727970 return 0;
728971 err = devlink->ops->port_type_set(devlink_port, port_type);
....@@ -735,10 +978,71 @@
735978 return -EOPNOTSUPP;
736979 }
737980
981
+static int
982
+devlink_port_function_hw_addr_set(struct devlink *devlink, struct devlink_port *port,
983
+ const struct nlattr *attr, struct netlink_ext_ack *extack)
984
+{
985
+ const struct devlink_ops *ops;
986
+ const u8 *hw_addr;
987
+ int hw_addr_len;
988
+ int err;
989
+
990
+ hw_addr = nla_data(attr);
991
+ hw_addr_len = nla_len(attr);
992
+ if (hw_addr_len > MAX_ADDR_LEN) {
993
+ NL_SET_ERR_MSG_MOD(extack, "Port function hardware address too long");
994
+ return -EINVAL;
995
+ }
996
+ if (port->type == DEVLINK_PORT_TYPE_ETH) {
997
+ if (hw_addr_len != ETH_ALEN) {
998
+ NL_SET_ERR_MSG_MOD(extack, "Address must be 6 bytes for Ethernet device");
999
+ return -EINVAL;
1000
+ }
1001
+ if (!is_unicast_ether_addr(hw_addr)) {
1002
+ NL_SET_ERR_MSG_MOD(extack, "Non-unicast hardware address unsupported");
1003
+ return -EINVAL;
1004
+ }
1005
+ }
1006
+
1007
+ ops = devlink->ops;
1008
+ if (!ops->port_function_hw_addr_set) {
1009
+ NL_SET_ERR_MSG_MOD(extack, "Port doesn't support function attributes");
1010
+ return -EOPNOTSUPP;
1011
+ }
1012
+
1013
+ err = ops->port_function_hw_addr_set(devlink, port, hw_addr, hw_addr_len, extack);
1014
+ if (err)
1015
+ return err;
1016
+
1017
+ devlink_port_notify(port, DEVLINK_CMD_PORT_NEW);
1018
+ return 0;
1019
+}
1020
+
1021
+static int
1022
+devlink_port_function_set(struct devlink *devlink, struct devlink_port *port,
1023
+ const struct nlattr *attr, struct netlink_ext_ack *extack)
1024
+{
1025
+ struct nlattr *tb[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1];
1026
+ int err;
1027
+
1028
+ err = nla_parse_nested(tb, DEVLINK_PORT_FUNCTION_ATTR_MAX, attr,
1029
+ devlink_function_nl_policy, extack);
1030
+ if (err < 0) {
1031
+ NL_SET_ERR_MSG_MOD(extack, "Fail to parse port function attributes");
1032
+ return err;
1033
+ }
1034
+
1035
+ attr = tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR];
1036
+ if (attr)
1037
+ err = devlink_port_function_hw_addr_set(devlink, port, attr, extack);
1038
+
1039
+ return err;
1040
+}
1041
+
7381042 static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
7391043 struct genl_info *info)
7401044 {
741
- struct devlink_port *devlink_port = info->user_ptr[0];
1045
+ struct devlink_port *devlink_port = info->user_ptr[1];
7421046 struct devlink *devlink = devlink_port->devlink;
7431047 int err;
7441048
....@@ -750,6 +1054,16 @@
7501054 if (err)
7511055 return err;
7521056 }
1057
+
1058
+ if (info->attrs[DEVLINK_ATTR_PORT_FUNCTION]) {
1059
+ struct nlattr *attr = info->attrs[DEVLINK_ATTR_PORT_FUNCTION];
1060
+ struct netlink_ext_ack *extack = info->extack;
1061
+
1062
+ err = devlink_port_function_set(devlink, devlink_port, attr, extack);
1063
+ if (err)
1064
+ return err;
1065
+ }
1066
+
7531067 return 0;
7541068 }
7551069
....@@ -757,7 +1071,7 @@
7571071 u32 count, struct netlink_ext_ack *extack)
7581072
7591073 {
760
- if (devlink->ops && devlink->ops->port_split)
1074
+ if (devlink->ops->port_split)
7611075 return devlink->ops->port_split(devlink, port_index, count,
7621076 extack);
7631077 return -EOPNOTSUPP;
....@@ -767,6 +1081,7 @@
7671081 struct genl_info *info)
7681082 {
7691083 struct devlink *devlink = info->user_ptr[0];
1084
+ struct devlink_port *devlink_port;
7701085 u32 port_index;
7711086 u32 count;
7721087
....@@ -774,8 +1089,27 @@
7741089 !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
7751090 return -EINVAL;
7761091
1092
+ devlink_port = devlink_port_get_from_info(devlink, info);
7771093 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
7781094 count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
1095
+
1096
+ if (IS_ERR(devlink_port))
1097
+ return -EINVAL;
1098
+
1099
+ if (!devlink_port->attrs.splittable) {
1100
+ /* Split ports cannot be split. */
1101
+ if (devlink_port->attrs.split)
1102
+ NL_SET_ERR_MSG_MOD(info->extack, "Port cannot be split further");
1103
+ else
1104
+ NL_SET_ERR_MSG_MOD(info->extack, "Port cannot be split");
1105
+ return -EINVAL;
1106
+ }
1107
+
1108
+ if (count < 2 || !is_power_of_2(count) || count > devlink_port->attrs.lanes) {
1109
+ NL_SET_ERR_MSG_MOD(info->extack, "Invalid split count");
1110
+ return -EINVAL;
1111
+ }
1112
+
7791113 return devlink_port_split(devlink, port_index, count, info->extack);
7801114 }
7811115
....@@ -783,7 +1117,7 @@
7831117 struct netlink_ext_ack *extack)
7841118
7851119 {
786
- if (devlink->ops && devlink->ops->port_unsplit)
1120
+ if (devlink->ops->port_unsplit)
7871121 return devlink->ops->port_unsplit(devlink, port_index, extack);
7881122 return -EOPNOTSUPP;
7891123 }
....@@ -843,9 +1177,13 @@
8431177 struct genl_info *info)
8441178 {
8451179 struct devlink *devlink = info->user_ptr[0];
846
- struct devlink_sb *devlink_sb = info->user_ptr[1];
1180
+ struct devlink_sb *devlink_sb;
8471181 struct sk_buff *msg;
8481182 int err;
1183
+
1184
+ devlink_sb = devlink_sb_get_from_info(devlink, info);
1185
+ if (IS_ERR(devlink_sb))
1186
+ return PTR_ERR(devlink_sb);
8491187
8501188 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
8511189 if (!msg)
....@@ -932,6 +1270,9 @@
9321270 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
9331271 pool_info.threshold_type))
9341272 goto nla_put_failure;
1273
+ if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
1274
+ pool_info.cell_size))
1275
+ goto nla_put_failure;
9351276
9361277 genlmsg_end(msg, hdr);
9371278 return 0;
....@@ -945,17 +1286,21 @@
9451286 struct genl_info *info)
9461287 {
9471288 struct devlink *devlink = info->user_ptr[0];
948
- struct devlink_sb *devlink_sb = info->user_ptr[1];
1289
+ struct devlink_sb *devlink_sb;
9491290 struct sk_buff *msg;
9501291 u16 pool_index;
9511292 int err;
1293
+
1294
+ devlink_sb = devlink_sb_get_from_info(devlink, info);
1295
+ if (IS_ERR(devlink_sb))
1296
+ return PTR_ERR(devlink_sb);
9521297
9531298 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
9541299 &pool_index);
9551300 if (err)
9561301 return err;
9571302
958
- if (!devlink->ops || !devlink->ops->sb_pool_get)
1303
+ if (!devlink->ops->sb_pool_get)
9591304 return -EOPNOTSUPP;
9601305
9611306 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
....@@ -1006,12 +1351,12 @@
10061351 struct devlink_sb *devlink_sb;
10071352 int start = cb->args[0];
10081353 int idx = 0;
1009
- int err;
1354
+ int err = 0;
10101355
10111356 mutex_lock(&devlink_mutex);
10121357 list_for_each_entry(devlink, &devlink_list, list) {
10131358 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
1014
- !devlink->ops || !devlink->ops->sb_pool_get)
1359
+ !devlink->ops->sb_pool_get)
10151360 continue;
10161361 mutex_lock(&devlink->lock);
10171362 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
....@@ -1019,7 +1364,9 @@
10191364 devlink_sb,
10201365 NETLINK_CB(cb->skb).portid,
10211366 cb->nlh->nlmsg_seq);
1022
- if (err && err != -EOPNOTSUPP) {
1367
+ if (err == -EOPNOTSUPP) {
1368
+ err = 0;
1369
+ } else if (err) {
10231370 mutex_unlock(&devlink->lock);
10241371 goto out;
10251372 }
....@@ -1029,20 +1376,24 @@
10291376 out:
10301377 mutex_unlock(&devlink_mutex);
10311378
1379
+ if (err != -EMSGSIZE)
1380
+ return err;
1381
+
10321382 cb->args[0] = idx;
10331383 return msg->len;
10341384 }
10351385
10361386 static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
10371387 u16 pool_index, u32 size,
1038
- enum devlink_sb_threshold_type threshold_type)
1388
+ enum devlink_sb_threshold_type threshold_type,
1389
+ struct netlink_ext_ack *extack)
10391390
10401391 {
10411392 const struct devlink_ops *ops = devlink->ops;
10421393
1043
- if (ops && ops->sb_pool_set)
1394
+ if (ops->sb_pool_set)
10441395 return ops->sb_pool_set(devlink, sb_index, pool_index,
1045
- size, threshold_type);
1396
+ size, threshold_type, extack);
10461397 return -EOPNOTSUPP;
10471398 }
10481399
....@@ -1050,11 +1401,15 @@
10501401 struct genl_info *info)
10511402 {
10521403 struct devlink *devlink = info->user_ptr[0];
1053
- struct devlink_sb *devlink_sb = info->user_ptr[1];
10541404 enum devlink_sb_threshold_type threshold_type;
1405
+ struct devlink_sb *devlink_sb;
10551406 u16 pool_index;
10561407 u32 size;
10571408 int err;
1409
+
1410
+ devlink_sb = devlink_sb_get_from_info(devlink, info);
1411
+ if (IS_ERR(devlink_sb))
1412
+ return PTR_ERR(devlink_sb);
10581413
10591414 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
10601415 &pool_index);
....@@ -1070,7 +1425,8 @@
10701425
10711426 size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
10721427 return devlink_sb_pool_set(devlink, devlink_sb->index,
1073
- pool_index, size, threshold_type);
1428
+ pool_index, size, threshold_type,
1429
+ info->extack);
10741430 }
10751431
10761432 static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
....@@ -1135,19 +1491,23 @@
11351491 static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb,
11361492 struct genl_info *info)
11371493 {
1138
- struct devlink_port *devlink_port = info->user_ptr[0];
1494
+ struct devlink_port *devlink_port = info->user_ptr[1];
11391495 struct devlink *devlink = devlink_port->devlink;
1140
- struct devlink_sb *devlink_sb = info->user_ptr[1];
1496
+ struct devlink_sb *devlink_sb;
11411497 struct sk_buff *msg;
11421498 u16 pool_index;
11431499 int err;
1500
+
1501
+ devlink_sb = devlink_sb_get_from_info(devlink, info);
1502
+ if (IS_ERR(devlink_sb))
1503
+ return PTR_ERR(devlink_sb);
11441504
11451505 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
11461506 &pool_index);
11471507 if (err)
11481508 return err;
11491509
1150
- if (!devlink->ops || !devlink->ops->sb_port_pool_get)
1510
+ if (!devlink->ops->sb_port_pool_get)
11511511 return -EOPNOTSUPP;
11521512
11531513 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
....@@ -1204,12 +1564,12 @@
12041564 struct devlink_sb *devlink_sb;
12051565 int start = cb->args[0];
12061566 int idx = 0;
1207
- int err;
1567
+ int err = 0;
12081568
12091569 mutex_lock(&devlink_mutex);
12101570 list_for_each_entry(devlink, &devlink_list, list) {
12111571 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
1212
- !devlink->ops || !devlink->ops->sb_port_pool_get)
1572
+ !devlink->ops->sb_port_pool_get)
12131573 continue;
12141574 mutex_lock(&devlink->lock);
12151575 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
....@@ -1217,7 +1577,9 @@
12171577 devlink, devlink_sb,
12181578 NETLINK_CB(cb->skb).portid,
12191579 cb->nlh->nlmsg_seq);
1220
- if (err && err != -EOPNOTSUPP) {
1580
+ if (err == -EOPNOTSUPP) {
1581
+ err = 0;
1582
+ } else if (err) {
12211583 mutex_unlock(&devlink->lock);
12221584 goto out;
12231585 }
....@@ -1227,31 +1589,40 @@
12271589 out:
12281590 mutex_unlock(&devlink_mutex);
12291591
1592
+ if (err != -EMSGSIZE)
1593
+ return err;
1594
+
12301595 cb->args[0] = idx;
12311596 return msg->len;
12321597 }
12331598
12341599 static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
12351600 unsigned int sb_index, u16 pool_index,
1236
- u32 threshold)
1601
+ u32 threshold,
1602
+ struct netlink_ext_ack *extack)
12371603
12381604 {
12391605 const struct devlink_ops *ops = devlink_port->devlink->ops;
12401606
1241
- if (ops && ops->sb_port_pool_set)
1607
+ if (ops->sb_port_pool_set)
12421608 return ops->sb_port_pool_set(devlink_port, sb_index,
1243
- pool_index, threshold);
1609
+ pool_index, threshold, extack);
12441610 return -EOPNOTSUPP;
12451611 }
12461612
12471613 static int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
12481614 struct genl_info *info)
12491615 {
1250
- struct devlink_port *devlink_port = info->user_ptr[0];
1251
- struct devlink_sb *devlink_sb = info->user_ptr[1];
1616
+ struct devlink_port *devlink_port = info->user_ptr[1];
1617
+ struct devlink *devlink = info->user_ptr[0];
1618
+ struct devlink_sb *devlink_sb;
12521619 u16 pool_index;
12531620 u32 threshold;
12541621 int err;
1622
+
1623
+ devlink_sb = devlink_sb_get_from_info(devlink, info);
1624
+ if (IS_ERR(devlink_sb))
1625
+ return PTR_ERR(devlink_sb);
12551626
12561627 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
12571628 &pool_index);
....@@ -1263,7 +1634,7 @@
12631634
12641635 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
12651636 return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
1266
- pool_index, threshold);
1637
+ pool_index, threshold, info->extack);
12671638 }
12681639
12691640 static int
....@@ -1334,13 +1705,17 @@
13341705 static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
13351706 struct genl_info *info)
13361707 {
1337
- struct devlink_port *devlink_port = info->user_ptr[0];
1708
+ struct devlink_port *devlink_port = info->user_ptr[1];
13381709 struct devlink *devlink = devlink_port->devlink;
1339
- struct devlink_sb *devlink_sb = info->user_ptr[1];
1710
+ struct devlink_sb *devlink_sb;
13401711 struct sk_buff *msg;
13411712 enum devlink_sb_pool_type pool_type;
13421713 u16 tc_index;
13431714 int err;
1715
+
1716
+ devlink_sb = devlink_sb_get_from_info(devlink, info);
1717
+ if (IS_ERR(devlink_sb))
1718
+ return PTR_ERR(devlink_sb);
13441719
13451720 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
13461721 if (err)
....@@ -1351,7 +1726,7 @@
13511726 if (err)
13521727 return err;
13531728
1354
- if (!devlink->ops || !devlink->ops->sb_tc_pool_bind_get)
1729
+ if (!devlink->ops->sb_tc_pool_bind_get)
13551730 return -EOPNOTSUPP;
13561731
13571732 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
....@@ -1430,12 +1805,12 @@
14301805 struct devlink_sb *devlink_sb;
14311806 int start = cb->args[0];
14321807 int idx = 0;
1433
- int err;
1808
+ int err = 0;
14341809
14351810 mutex_lock(&devlink_mutex);
14361811 list_for_each_entry(devlink, &devlink_list, list) {
14371812 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
1438
- !devlink->ops || !devlink->ops->sb_tc_pool_bind_get)
1813
+ !devlink->ops->sb_tc_pool_bind_get)
14391814 continue;
14401815
14411816 mutex_lock(&devlink->lock);
....@@ -1445,7 +1820,9 @@
14451820 devlink_sb,
14461821 NETLINK_CB(cb->skb).portid,
14471822 cb->nlh->nlmsg_seq);
1448
- if (err && err != -EOPNOTSUPP) {
1823
+ if (err == -EOPNOTSUPP) {
1824
+ err = 0;
1825
+ } else if (err) {
14491826 mutex_unlock(&devlink->lock);
14501827 goto out;
14511828 }
....@@ -1455,6 +1832,9 @@
14551832 out:
14561833 mutex_unlock(&devlink_mutex);
14571834
1835
+ if (err != -EMSGSIZE)
1836
+ return err;
1837
+
14581838 cb->args[0] = idx;
14591839 return msg->len;
14601840 }
....@@ -1462,28 +1842,34 @@
14621842 static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
14631843 unsigned int sb_index, u16 tc_index,
14641844 enum devlink_sb_pool_type pool_type,
1465
- u16 pool_index, u32 threshold)
1845
+ u16 pool_index, u32 threshold,
1846
+ struct netlink_ext_ack *extack)
14661847
14671848 {
14681849 const struct devlink_ops *ops = devlink_port->devlink->ops;
14691850
1470
- if (ops && ops->sb_tc_pool_bind_set)
1851
+ if (ops->sb_tc_pool_bind_set)
14711852 return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
14721853 tc_index, pool_type,
1473
- pool_index, threshold);
1854
+ pool_index, threshold, extack);
14741855 return -EOPNOTSUPP;
14751856 }
14761857
14771858 static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
14781859 struct genl_info *info)
14791860 {
1480
- struct devlink_port *devlink_port = info->user_ptr[0];
1481
- struct devlink_sb *devlink_sb = info->user_ptr[1];
1861
+ struct devlink_port *devlink_port = info->user_ptr[1];
1862
+ struct devlink *devlink = info->user_ptr[0];
14821863 enum devlink_sb_pool_type pool_type;
1864
+ struct devlink_sb *devlink_sb;
14831865 u16 tc_index;
14841866 u16 pool_index;
14851867 u32 threshold;
14861868 int err;
1869
+
1870
+ devlink_sb = devlink_sb_get_from_info(devlink, info);
1871
+ if (IS_ERR(devlink_sb))
1872
+ return PTR_ERR(devlink_sb);
14871873
14881874 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
14891875 if (err)
....@@ -1505,17 +1891,21 @@
15051891 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
15061892 return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
15071893 tc_index, pool_type,
1508
- pool_index, threshold);
1894
+ pool_index, threshold, info->extack);
15091895 }
15101896
15111897 static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
15121898 struct genl_info *info)
15131899 {
15141900 struct devlink *devlink = info->user_ptr[0];
1515
- struct devlink_sb *devlink_sb = info->user_ptr[1];
15161901 const struct devlink_ops *ops = devlink->ops;
1902
+ struct devlink_sb *devlink_sb;
15171903
1518
- if (ops && ops->sb_occ_snapshot)
1904
+ devlink_sb = devlink_sb_get_from_info(devlink, info);
1905
+ if (IS_ERR(devlink_sb))
1906
+ return PTR_ERR(devlink_sb);
1907
+
1908
+ if (ops->sb_occ_snapshot)
15191909 return ops->sb_occ_snapshot(devlink, devlink_sb->index);
15201910 return -EOPNOTSUPP;
15211911 }
....@@ -1524,10 +1914,14 @@
15241914 struct genl_info *info)
15251915 {
15261916 struct devlink *devlink = info->user_ptr[0];
1527
- struct devlink_sb *devlink_sb = info->user_ptr[1];
15281917 const struct devlink_ops *ops = devlink->ops;
1918
+ struct devlink_sb *devlink_sb;
15291919
1530
- if (ops && ops->sb_occ_max_clear)
1920
+ devlink_sb = devlink_sb_get_from_info(devlink, info);
1921
+ if (IS_ERR(devlink_sb))
1922
+ return PTR_ERR(devlink_sb);
1923
+
1924
+ if (ops->sb_occ_max_clear)
15311925 return ops->sb_occ_max_clear(devlink, devlink_sb->index);
15321926 return -EOPNOTSUPP;
15331927 }
....@@ -1537,7 +1931,8 @@
15371931 u32 seq, int flags)
15381932 {
15391933 const struct devlink_ops *ops = devlink->ops;
1540
- u8 inline_mode, encap_mode;
1934
+ enum devlink_eswitch_encap_mode encap_mode;
1935
+ u8 inline_mode;
15411936 void *hdr;
15421937 int err = 0;
15431938 u16 mode;
....@@ -1590,12 +1985,8 @@
15901985 struct genl_info *info)
15911986 {
15921987 struct devlink *devlink = info->user_ptr[0];
1593
- const struct devlink_ops *ops = devlink->ops;
15941988 struct sk_buff *msg;
15951989 int err;
1596
-
1597
- if (!ops)
1598
- return -EOPNOTSUPP;
15991990
16001991 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
16011992 if (!msg)
....@@ -1617,18 +2008,16 @@
16172008 {
16182009 struct devlink *devlink = info->user_ptr[0];
16192010 const struct devlink_ops *ops = devlink->ops;
1620
- u8 inline_mode, encap_mode;
2011
+ enum devlink_eswitch_encap_mode encap_mode;
2012
+ u8 inline_mode;
16212013 int err = 0;
16222014 u16 mode;
1623
-
1624
- if (!ops)
1625
- return -EOPNOTSUPP;
16262015
16272016 if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
16282017 if (!ops->eswitch_mode_set)
16292018 return -EOPNOTSUPP;
16302019 mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
1631
- err = ops->eswitch_mode_set(devlink, mode);
2020
+ err = ops->eswitch_mode_set(devlink, mode, info->extack);
16322021 if (err)
16332022 return err;
16342023 }
....@@ -1638,7 +2027,8 @@
16382027 return -EOPNOTSUPP;
16392028 inline_mode = nla_get_u8(
16402029 info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]);
1641
- err = ops->eswitch_inline_mode_set(devlink, inline_mode);
2030
+ err = ops->eswitch_inline_mode_set(devlink, inline_mode,
2031
+ info->extack);
16422032 if (err)
16432033 return err;
16442034 }
....@@ -1647,7 +2037,8 @@
16472037 if (!ops->eswitch_encap_mode_set)
16482038 return -EOPNOTSUPP;
16492039 encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
1650
- err = ops->eswitch_encap_mode_set(devlink, encap_mode);
2040
+ err = ops->eswitch_encap_mode_set(devlink, encap_mode,
2041
+ info->extack);
16512042 if (err)
16522043 return err;
16532044 }
....@@ -1662,7 +2053,7 @@
16622053 struct devlink_dpipe_field *field = &header->fields[match->field_id];
16632054 struct nlattr *match_attr;
16642055
1665
- match_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_MATCH);
2056
+ match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH);
16662057 if (!match_attr)
16672058 return -EMSGSIZE;
16682059
....@@ -1687,7 +2078,8 @@
16872078 {
16882079 struct nlattr *matches_attr;
16892080
1690
- matches_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
2081
+ matches_attr = nla_nest_start_noflag(skb,
2082
+ DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
16912083 if (!matches_attr)
16922084 return -EMSGSIZE;
16932085
....@@ -1709,7 +2101,7 @@
17092101 struct devlink_dpipe_field *field = &header->fields[action->field_id];
17102102 struct nlattr *action_attr;
17112103
1712
- action_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_ACTION);
2104
+ action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION);
17132105 if (!action_attr)
17142106 return -EMSGSIZE;
17152107
....@@ -1734,7 +2126,8 @@
17342126 {
17352127 struct nlattr *actions_attr;
17362128
1737
- actions_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
2129
+ actions_attr = nla_nest_start_noflag(skb,
2130
+ DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
17382131 if (!actions_attr)
17392132 return -EMSGSIZE;
17402133
....@@ -1756,7 +2149,7 @@
17562149 u64 table_size;
17572150
17582151 table_size = table->table_ops->size_get(table->priv);
1759
- table_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLE);
2152
+ table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE);
17602153 if (!table_attr)
17612154 return -EMSGSIZE;
17622155
....@@ -1836,7 +2229,7 @@
18362229
18372230 if (devlink_nl_put_handle(skb, devlink))
18382231 goto nla_put_failure;
1839
- tables_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLES);
2232
+ tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES);
18402233 if (!tables_attr)
18412234 goto nla_put_failure;
18422235
....@@ -1937,8 +2330,8 @@
19372330 int err;
19382331
19392332 for (i = 0; i < values_count; i++) {
1940
- action_attr = nla_nest_start(skb,
1941
- DEVLINK_ATTR_DPIPE_ACTION_VALUE);
2333
+ action_attr = nla_nest_start_noflag(skb,
2334
+ DEVLINK_ATTR_DPIPE_ACTION_VALUE);
19422335 if (!action_attr)
19432336 return -EMSGSIZE;
19442337 err = devlink_dpipe_action_value_put(skb, &values[i]);
....@@ -1974,8 +2367,8 @@
19742367 int err;
19752368
19762369 for (i = 0; i < values_count; i++) {
1977
- match_attr = nla_nest_start(skb,
1978
- DEVLINK_ATTR_DPIPE_MATCH_VALUE);
2370
+ match_attr = nla_nest_start_noflag(skb,
2371
+ DEVLINK_ATTR_DPIPE_MATCH_VALUE);
19792372 if (!match_attr)
19802373 return -EMSGSIZE;
19812374 err = devlink_dpipe_match_value_put(skb, &values[i]);
....@@ -1996,7 +2389,7 @@
19962389 struct nlattr *entry_attr, *matches_attr, *actions_attr;
19972390 int err;
19982391
1999
- entry_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_ENTRY);
2392
+ entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY);
20002393 if (!entry_attr)
20012394 return -EMSGSIZE;
20022395
....@@ -2008,8 +2401,8 @@
20082401 entry->counter, DEVLINK_ATTR_PAD))
20092402 goto nla_put_failure;
20102403
2011
- matches_attr = nla_nest_start(skb,
2012
- DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
2404
+ matches_attr = nla_nest_start_noflag(skb,
2405
+ DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
20132406 if (!matches_attr)
20142407 goto nla_put_failure;
20152408
....@@ -2021,8 +2414,8 @@
20212414 }
20222415 nla_nest_end(skb, matches_attr);
20232416
2024
- actions_attr = nla_nest_start(skb,
2025
- DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
2417
+ actions_attr = nla_nest_start_noflag(skb,
2418
+ DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
20262419 if (!actions_attr)
20272420 goto nla_put_failure;
20282421
....@@ -2047,11 +2440,11 @@
20472440
20482441 static struct devlink_dpipe_table *
20492442 devlink_dpipe_table_find(struct list_head *dpipe_tables,
2050
- const char *table_name)
2443
+ const char *table_name, struct devlink *devlink)
20512444 {
20522445 struct devlink_dpipe_table *table;
2053
-
2054
- list_for_each_entry_rcu(table, dpipe_tables, list) {
2446
+ list_for_each_entry_rcu(table, dpipe_tables, list,
2447
+ lockdep_is_held(&devlink->lock)) {
20552448 if (!strcmp(table->name, table_name))
20562449 return table;
20572450 }
....@@ -2079,8 +2472,8 @@
20792472 devlink = dump_ctx->info->user_ptr[0];
20802473 if (devlink_nl_put_handle(dump_ctx->skb, devlink))
20812474 goto nla_put_failure;
2082
- dump_ctx->nest = nla_nest_start(dump_ctx->skb,
2083
- DEVLINK_ATTR_DPIPE_ENTRIES);
2475
+ dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb,
2476
+ DEVLINK_ATTR_DPIPE_ENTRIES);
20842477 if (!dump_ctx->nest)
20852478 goto nla_put_failure;
20862479 return 0;
....@@ -2170,7 +2563,7 @@
21702563
21712564 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
21722565 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2173
- table_name);
2566
+ table_name, devlink);
21742567 if (!table)
21752568 return -EINVAL;
21762569
....@@ -2190,7 +2583,8 @@
21902583
21912584 for (i = 0; i < header->fields_count; i++) {
21922585 field = &header->fields[i];
2193
- field_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_FIELD);
2586
+ field_attr = nla_nest_start_noflag(skb,
2587
+ DEVLINK_ATTR_DPIPE_FIELD);
21942588 if (!field_attr)
21952589 return -EMSGSIZE;
21962590 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
....@@ -2213,7 +2607,7 @@
22132607 struct nlattr *fields_attr, *header_attr;
22142608 int err;
22152609
2216
- header_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_HEADER);
2610
+ header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER);
22172611 if (!header_attr)
22182612 return -EMSGSIZE;
22192613
....@@ -2222,7 +2616,8 @@
22222616 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
22232617 goto nla_put_failure;
22242618
2225
- fields_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
2619
+ fields_attr = nla_nest_start_noflag(skb,
2620
+ DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
22262621 if (!fields_attr)
22272622 goto nla_put_failure;
22282623
....@@ -2269,7 +2664,7 @@
22692664
22702665 if (devlink_nl_put_handle(skb, devlink))
22712666 goto nla_put_failure;
2272
- headers_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_HEADERS);
2667
+ headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS);
22732668 if (!headers_attr)
22742669 goto nla_put_failure;
22752670
....@@ -2324,7 +2719,7 @@
23242719 struct devlink_dpipe_table *table;
23252720
23262721 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2327
- table_name);
2722
+ table_name, devlink);
23282723 if (!table)
23292724 return -EINVAL;
23302725
....@@ -2493,7 +2888,7 @@
24932888 struct nlattr *child_resource_attr;
24942889 struct nlattr *resource_attr;
24952890
2496
- resource_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE);
2891
+ resource_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE);
24972892 if (!resource_attr)
24982893 return -EMSGSIZE;
24992894
....@@ -2517,7 +2912,8 @@
25172912 resource->size_valid))
25182913 goto nla_put_failure;
25192914
2520
- child_resource_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE_LIST);
2915
+ child_resource_attr = nla_nest_start_noflag(skb,
2916
+ DEVLINK_ATTR_RESOURCE_LIST);
25212917 if (!child_resource_attr)
25222918 goto nla_put_failure;
25232919
....@@ -2568,7 +2964,8 @@
25682964 if (devlink_nl_put_handle(skb, devlink))
25692965 goto nla_put_failure;
25702966
2571
- resources_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE_LIST);
2967
+ resources_attr = nla_nest_start_noflag(skb,
2968
+ DEVLINK_ATTR_RESOURCE_LIST);
25722969 if (!resources_attr)
25732970 goto nla_put_failure;
25742971
....@@ -2640,12 +3037,226 @@
26403037 return err;
26413038 }
26423039
3040
+static struct net *devlink_netns_get(struct sk_buff *skb,
3041
+ struct genl_info *info)
3042
+{
3043
+ struct nlattr *netns_pid_attr = info->attrs[DEVLINK_ATTR_NETNS_PID];
3044
+ struct nlattr *netns_fd_attr = info->attrs[DEVLINK_ATTR_NETNS_FD];
3045
+ struct nlattr *netns_id_attr = info->attrs[DEVLINK_ATTR_NETNS_ID];
3046
+ struct net *net;
3047
+
3048
+ if (!!netns_pid_attr + !!netns_fd_attr + !!netns_id_attr > 1) {
3049
+ NL_SET_ERR_MSG_MOD(info->extack, "multiple netns identifying attributes specified");
3050
+ return ERR_PTR(-EINVAL);
3051
+ }
3052
+
3053
+ if (netns_pid_attr) {
3054
+ net = get_net_ns_by_pid(nla_get_u32(netns_pid_attr));
3055
+ } else if (netns_fd_attr) {
3056
+ net = get_net_ns_by_fd(nla_get_u32(netns_fd_attr));
3057
+ } else if (netns_id_attr) {
3058
+ net = get_net_ns_by_id(sock_net(skb->sk),
3059
+ nla_get_u32(netns_id_attr));
3060
+ if (!net)
3061
+ net = ERR_PTR(-EINVAL);
3062
+ } else {
3063
+ WARN_ON(1);
3064
+ net = ERR_PTR(-EINVAL);
3065
+ }
3066
+ if (IS_ERR(net)) {
3067
+ NL_SET_ERR_MSG_MOD(info->extack, "Unknown network namespace");
3068
+ return ERR_PTR(-EINVAL);
3069
+ }
3070
+ if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
3071
+ put_net(net);
3072
+ return ERR_PTR(-EPERM);
3073
+ }
3074
+ return net;
3075
+}
3076
+
3077
+static void devlink_param_notify(struct devlink *devlink,
3078
+ unsigned int port_index,
3079
+ struct devlink_param_item *param_item,
3080
+ enum devlink_command cmd);
3081
+
3082
+static void devlink_ns_change_notify(struct devlink *devlink,
3083
+ struct net *dest_net, struct net *curr_net,
3084
+ bool new)
3085
+{
3086
+ struct devlink_param_item *param_item;
3087
+ enum devlink_command cmd;
3088
+
3089
+ /* Userspace needs to be notified about devlink objects
3090
+ * removed from original and entering new network namespace.
3091
+ * The rest of the devlink objects are re-created during
3092
+ * reload process so the notifications are generated separatelly.
3093
+ */
3094
+
3095
+ if (!dest_net || net_eq(dest_net, curr_net))
3096
+ return;
3097
+
3098
+ if (new)
3099
+ devlink_notify(devlink, DEVLINK_CMD_NEW);
3100
+
3101
+ cmd = new ? DEVLINK_CMD_PARAM_NEW : DEVLINK_CMD_PARAM_DEL;
3102
+ list_for_each_entry(param_item, &devlink->param_list, list)
3103
+ devlink_param_notify(devlink, 0, param_item, cmd);
3104
+
3105
+ if (!new)
3106
+ devlink_notify(devlink, DEVLINK_CMD_DEL);
3107
+}
3108
+
3109
+static bool devlink_reload_supported(const struct devlink_ops *ops)
3110
+{
3111
+ return ops->reload_down && ops->reload_up;
3112
+}
3113
+
3114
+static void devlink_reload_failed_set(struct devlink *devlink,
3115
+ bool reload_failed)
3116
+{
3117
+ if (devlink->reload_failed == reload_failed)
3118
+ return;
3119
+ devlink->reload_failed = reload_failed;
3120
+ devlink_notify(devlink, DEVLINK_CMD_NEW);
3121
+}
3122
+
3123
+bool devlink_is_reload_failed(const struct devlink *devlink)
3124
+{
3125
+ return devlink->reload_failed;
3126
+}
3127
+EXPORT_SYMBOL_GPL(devlink_is_reload_failed);
3128
+
3129
+static void
3130
+__devlink_reload_stats_update(struct devlink *devlink, u32 *reload_stats,
3131
+ enum devlink_reload_limit limit, u32 actions_performed)
3132
+{
3133
+ unsigned long actions = actions_performed;
3134
+ int stat_idx;
3135
+ int action;
3136
+
3137
+ for_each_set_bit(action, &actions, __DEVLINK_RELOAD_ACTION_MAX) {
3138
+ stat_idx = limit * __DEVLINK_RELOAD_ACTION_MAX + action;
3139
+ reload_stats[stat_idx]++;
3140
+ }
3141
+ devlink_notify(devlink, DEVLINK_CMD_NEW);
3142
+}
3143
+
3144
+static void
3145
+devlink_reload_stats_update(struct devlink *devlink, enum devlink_reload_limit limit,
3146
+ u32 actions_performed)
3147
+{
3148
+ __devlink_reload_stats_update(devlink, devlink->stats.reload_stats, limit,
3149
+ actions_performed);
3150
+}
3151
+
3152
+/**
3153
+ * devlink_remote_reload_actions_performed - Update devlink on reload actions
3154
+ * performed which are not a direct result of devlink reload call.
3155
+ *
3156
+ * This should be called by a driver after performing reload actions in case it was not
3157
+ * a result of devlink reload call. For example fw_activate was performed as a result
3158
+ * of devlink reload triggered fw_activate on another host.
3159
+ * The motivation for this function is to keep data on reload actions performed on this
3160
+ * function whether it was done due to direct devlink reload call or not.
3161
+ *
3162
+ * @devlink: devlink
3163
+ * @limit: reload limit
3164
+ * @actions_performed: bitmask of actions performed
3165
+ */
3166
+void devlink_remote_reload_actions_performed(struct devlink *devlink,
3167
+ enum devlink_reload_limit limit,
3168
+ u32 actions_performed)
3169
+{
3170
+ if (WARN_ON(!actions_performed ||
3171
+ actions_performed & BIT(DEVLINK_RELOAD_ACTION_UNSPEC) ||
3172
+ actions_performed >= BIT(__DEVLINK_RELOAD_ACTION_MAX) ||
3173
+ limit > DEVLINK_RELOAD_LIMIT_MAX))
3174
+ return;
3175
+
3176
+ __devlink_reload_stats_update(devlink, devlink->stats.remote_reload_stats, limit,
3177
+ actions_performed);
3178
+}
3179
+EXPORT_SYMBOL_GPL(devlink_remote_reload_actions_performed);
3180
+
3181
+static int devlink_reload(struct devlink *devlink, struct net *dest_net,
3182
+ enum devlink_reload_action action, enum devlink_reload_limit limit,
3183
+ u32 *actions_performed, struct netlink_ext_ack *extack)
3184
+{
3185
+ u32 remote_reload_stats[DEVLINK_RELOAD_STATS_ARRAY_SIZE];
3186
+ struct net *curr_net;
3187
+ int err;
3188
+
3189
+ if (!devlink->reload_enabled)
3190
+ return -EOPNOTSUPP;
3191
+
3192
+ memcpy(remote_reload_stats, devlink->stats.remote_reload_stats,
3193
+ sizeof(remote_reload_stats));
3194
+
3195
+ curr_net = devlink_net(devlink);
3196
+ devlink_ns_change_notify(devlink, dest_net, curr_net, false);
3197
+ err = devlink->ops->reload_down(devlink, !!dest_net, action, limit, extack);
3198
+ if (err)
3199
+ return err;
3200
+
3201
+ if (dest_net && !net_eq(dest_net, curr_net))
3202
+ __devlink_net_set(devlink, dest_net);
3203
+
3204
+ err = devlink->ops->reload_up(devlink, action, limit, actions_performed, extack);
3205
+ devlink_reload_failed_set(devlink, !!err);
3206
+ if (err)
3207
+ return err;
3208
+
3209
+ devlink_ns_change_notify(devlink, dest_net, curr_net, true);
3210
+ WARN_ON(!(*actions_performed & BIT(action)));
3211
+ /* Catch driver on updating the remote action within devlink reload */
3212
+ WARN_ON(memcmp(remote_reload_stats, devlink->stats.remote_reload_stats,
3213
+ sizeof(remote_reload_stats)));
3214
+ devlink_reload_stats_update(devlink, limit, *actions_performed);
3215
+ return 0;
3216
+}
3217
+
3218
+static int
3219
+devlink_nl_reload_actions_performed_snd(struct devlink *devlink, u32 actions_performed,
3220
+ enum devlink_command cmd, struct genl_info *info)
3221
+{
3222
+ struct sk_buff *msg;
3223
+ void *hdr;
3224
+
3225
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3226
+ if (!msg)
3227
+ return -ENOMEM;
3228
+
3229
+ hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &devlink_nl_family, 0, cmd);
3230
+ if (!hdr)
3231
+ goto free_msg;
3232
+
3233
+ if (devlink_nl_put_handle(msg, devlink))
3234
+ goto nla_put_failure;
3235
+
3236
+ if (nla_put_bitfield32(msg, DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED, actions_performed,
3237
+ actions_performed))
3238
+ goto nla_put_failure;
3239
+ genlmsg_end(msg, hdr);
3240
+
3241
+ return genlmsg_reply(msg, info);
3242
+
3243
+nla_put_failure:
3244
+ genlmsg_cancel(msg, hdr);
3245
+free_msg:
3246
+ nlmsg_free(msg);
3247
+ return -EMSGSIZE;
3248
+}
3249
+
26433250 static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
26443251 {
26453252 struct devlink *devlink = info->user_ptr[0];
3253
+ enum devlink_reload_action action;
3254
+ enum devlink_reload_limit limit;
3255
+ struct net *dest_net = NULL;
3256
+ u32 actions_performed;
26463257 int err;
26473258
2648
- if (!devlink->ops->reload)
3259
+ if (!devlink_reload_supported(devlink->ops))
26493260 return -EOPNOTSUPP;
26503261
26513262 err = devlink_resources_validate(devlink, NULL, info);
....@@ -2653,7 +3264,241 @@
26533264 NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed");
26543265 return err;
26553266 }
2656
- return devlink->ops->reload(devlink, info->extack);
3267
+
3268
+ if (info->attrs[DEVLINK_ATTR_RELOAD_ACTION])
3269
+ action = nla_get_u8(info->attrs[DEVLINK_ATTR_RELOAD_ACTION]);
3270
+ else
3271
+ action = DEVLINK_RELOAD_ACTION_DRIVER_REINIT;
3272
+
3273
+ if (!devlink_reload_action_is_supported(devlink, action)) {
3274
+ NL_SET_ERR_MSG_MOD(info->extack,
3275
+ "Requested reload action is not supported by the driver");
3276
+ return -EOPNOTSUPP;
3277
+ }
3278
+
3279
+ limit = DEVLINK_RELOAD_LIMIT_UNSPEC;
3280
+ if (info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]) {
3281
+ struct nla_bitfield32 limits;
3282
+ u32 limits_selected;
3283
+
3284
+ limits = nla_get_bitfield32(info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]);
3285
+ limits_selected = limits.value & limits.selector;
3286
+ if (!limits_selected) {
3287
+ NL_SET_ERR_MSG_MOD(info->extack, "Invalid limit selected");
3288
+ return -EINVAL;
3289
+ }
3290
+ for (limit = 0 ; limit <= DEVLINK_RELOAD_LIMIT_MAX ; limit++)
3291
+ if (limits_selected & BIT(limit))
3292
+ break;
3293
+ /* UAPI enables multiselection, but currently it is not used */
3294
+ if (limits_selected != BIT(limit)) {
3295
+ NL_SET_ERR_MSG_MOD(info->extack,
3296
+ "Multiselection of limit is not supported");
3297
+ return -EOPNOTSUPP;
3298
+ }
3299
+ if (!devlink_reload_limit_is_supported(devlink, limit)) {
3300
+ NL_SET_ERR_MSG_MOD(info->extack,
3301
+ "Requested limit is not supported by the driver");
3302
+ return -EOPNOTSUPP;
3303
+ }
3304
+ if (devlink_reload_combination_is_invalid(action, limit)) {
3305
+ NL_SET_ERR_MSG_MOD(info->extack,
3306
+ "Requested limit is invalid for this action");
3307
+ return -EINVAL;
3308
+ }
3309
+ }
3310
+ if (info->attrs[DEVLINK_ATTR_NETNS_PID] ||
3311
+ info->attrs[DEVLINK_ATTR_NETNS_FD] ||
3312
+ info->attrs[DEVLINK_ATTR_NETNS_ID]) {
3313
+ dest_net = devlink_netns_get(skb, info);
3314
+ if (IS_ERR(dest_net))
3315
+ return PTR_ERR(dest_net);
3316
+ }
3317
+
3318
+ err = devlink_reload(devlink, dest_net, action, limit, &actions_performed, info->extack);
3319
+
3320
+ if (dest_net)
3321
+ put_net(dest_net);
3322
+
3323
+ if (err)
3324
+ return err;
3325
+ /* For backward compatibility generate reply only if attributes used by user */
3326
+ if (!info->attrs[DEVLINK_ATTR_RELOAD_ACTION] && !info->attrs[DEVLINK_ATTR_RELOAD_LIMITS])
3327
+ return 0;
3328
+
3329
+ return devlink_nl_reload_actions_performed_snd(devlink, actions_performed,
3330
+ DEVLINK_CMD_RELOAD, info);
3331
+}
3332
+
3333
+static int devlink_nl_flash_update_fill(struct sk_buff *msg,
3334
+ struct devlink *devlink,
3335
+ enum devlink_command cmd,
3336
+ struct devlink_flash_notify *params)
3337
+{
3338
+ void *hdr;
3339
+
3340
+ hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
3341
+ if (!hdr)
3342
+ return -EMSGSIZE;
3343
+
3344
+ if (devlink_nl_put_handle(msg, devlink))
3345
+ goto nla_put_failure;
3346
+
3347
+ if (cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS)
3348
+ goto out;
3349
+
3350
+ if (params->status_msg &&
3351
+ nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG,
3352
+ params->status_msg))
3353
+ goto nla_put_failure;
3354
+ if (params->component &&
3355
+ nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,
3356
+ params->component))
3357
+ goto nla_put_failure;
3358
+ if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE,
3359
+ params->done, DEVLINK_ATTR_PAD))
3360
+ goto nla_put_failure;
3361
+ if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL,
3362
+ params->total, DEVLINK_ATTR_PAD))
3363
+ goto nla_put_failure;
3364
+ if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT,
3365
+ params->timeout, DEVLINK_ATTR_PAD))
3366
+ goto nla_put_failure;
3367
+
3368
+out:
3369
+ genlmsg_end(msg, hdr);
3370
+ return 0;
3371
+
3372
+nla_put_failure:
3373
+ genlmsg_cancel(msg, hdr);
3374
+ return -EMSGSIZE;
3375
+}
3376
+
3377
+static void __devlink_flash_update_notify(struct devlink *devlink,
3378
+ enum devlink_command cmd,
3379
+ struct devlink_flash_notify *params)
3380
+{
3381
+ struct sk_buff *msg;
3382
+ int err;
3383
+
3384
+ WARN_ON(cmd != DEVLINK_CMD_FLASH_UPDATE &&
3385
+ cmd != DEVLINK_CMD_FLASH_UPDATE_END &&
3386
+ cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS);
3387
+
3388
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3389
+ if (!msg)
3390
+ return;
3391
+
3392
+ err = devlink_nl_flash_update_fill(msg, devlink, cmd, params);
3393
+ if (err)
3394
+ goto out_free_msg;
3395
+
3396
+ genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3397
+ msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3398
+ return;
3399
+
3400
+out_free_msg:
3401
+ nlmsg_free(msg);
3402
+}
3403
+
3404
+void devlink_flash_update_begin_notify(struct devlink *devlink)
3405
+{
3406
+ struct devlink_flash_notify params = {};
3407
+
3408
+ __devlink_flash_update_notify(devlink,
3409
+ DEVLINK_CMD_FLASH_UPDATE,
3410
+ &params);
3411
+}
3412
+EXPORT_SYMBOL_GPL(devlink_flash_update_begin_notify);
3413
+
3414
+void devlink_flash_update_end_notify(struct devlink *devlink)
3415
+{
3416
+ struct devlink_flash_notify params = {};
3417
+
3418
+ __devlink_flash_update_notify(devlink,
3419
+ DEVLINK_CMD_FLASH_UPDATE_END,
3420
+ &params);
3421
+}
3422
+EXPORT_SYMBOL_GPL(devlink_flash_update_end_notify);
3423
+
3424
+void devlink_flash_update_status_notify(struct devlink *devlink,
3425
+ const char *status_msg,
3426
+ const char *component,
3427
+ unsigned long done,
3428
+ unsigned long total)
3429
+{
3430
+ struct devlink_flash_notify params = {
3431
+ .status_msg = status_msg,
3432
+ .component = component,
3433
+ .done = done,
3434
+ .total = total,
3435
+ };
3436
+
3437
+ __devlink_flash_update_notify(devlink,
3438
+ DEVLINK_CMD_FLASH_UPDATE_STATUS,
3439
+ &params);
3440
+}
3441
+EXPORT_SYMBOL_GPL(devlink_flash_update_status_notify);
3442
+
3443
+void devlink_flash_update_timeout_notify(struct devlink *devlink,
3444
+ const char *status_msg,
3445
+ const char *component,
3446
+ unsigned long timeout)
3447
+{
3448
+ struct devlink_flash_notify params = {
3449
+ .status_msg = status_msg,
3450
+ .component = component,
3451
+ .timeout = timeout,
3452
+ };
3453
+
3454
+ __devlink_flash_update_notify(devlink,
3455
+ DEVLINK_CMD_FLASH_UPDATE_STATUS,
3456
+ &params);
3457
+}
3458
+EXPORT_SYMBOL_GPL(devlink_flash_update_timeout_notify);
3459
+
3460
+static int devlink_nl_cmd_flash_update(struct sk_buff *skb,
3461
+ struct genl_info *info)
3462
+{
3463
+ struct nlattr *nla_component, *nla_overwrite_mask;
3464
+ struct devlink_flash_update_params params = {};
3465
+ struct devlink *devlink = info->user_ptr[0];
3466
+ u32 supported_params;
3467
+
3468
+ if (!devlink->ops->flash_update)
3469
+ return -EOPNOTSUPP;
3470
+
3471
+ if (!info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME])
3472
+ return -EINVAL;
3473
+
3474
+ supported_params = devlink->ops->supported_flash_update_params;
3475
+
3476
+ params.file_name = nla_data(info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME]);
3477
+
3478
+ nla_component = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT];
3479
+ if (nla_component) {
3480
+ if (!(supported_params & DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT)) {
3481
+ NL_SET_ERR_MSG_ATTR(info->extack, nla_component,
3482
+ "component update is not supported by this device");
3483
+ return -EOPNOTSUPP;
3484
+ }
3485
+ params.component = nla_data(nla_component);
3486
+ }
3487
+
3488
+ nla_overwrite_mask = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK];
3489
+ if (nla_overwrite_mask) {
3490
+ struct nla_bitfield32 sections;
3491
+
3492
+ if (!(supported_params & DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK)) {
3493
+ NL_SET_ERR_MSG_ATTR(info->extack, nla_overwrite_mask,
3494
+ "overwrite settings are not supported by this device");
3495
+ return -EOPNOTSUPP;
3496
+ }
3497
+ sections = nla_get_bitfield32(nla_overwrite_mask);
3498
+ params.overwrite_mask = sections.value & sections.selector;
3499
+ }
3500
+
3501
+ return devlink->ops->flash_update(devlink, &params, info->extack);
26573502 }
26583503
26593504 static const struct devlink_param devlink_param_generic[] = {
....@@ -2676,6 +3521,41 @@
26763521 .id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
26773522 .name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
26783523 .type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
3524
+ },
3525
+ {
3526
+ .id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
3527
+ .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
3528
+ .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
3529
+ },
3530
+ {
3531
+ .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
3532
+ .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
3533
+ .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
3534
+ },
3535
+ {
3536
+ .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
3537
+ .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
3538
+ .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
3539
+ },
3540
+ {
3541
+ .id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
3542
+ .name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
3543
+ .type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
3544
+ },
3545
+ {
3546
+ .id = DEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE,
3547
+ .name = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_NAME,
3548
+ .type = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_TYPE,
3549
+ },
3550
+ {
3551
+ .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE,
3552
+ .name = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_NAME,
3553
+ .type = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_TYPE,
3554
+ },
3555
+ {
3556
+ .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_REMOTE_DEV_RESET,
3557
+ .name = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_NAME,
3558
+ .type = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_TYPE,
26793559 },
26803560 };
26813561
....@@ -2781,7 +3661,8 @@
27813661 {
27823662 struct nlattr *param_value_attr;
27833663
2784
- param_value_attr = nla_nest_start(msg, DEVLINK_ATTR_PARAM_VALUE);
3664
+ param_value_attr = nla_nest_start_noflag(msg,
3665
+ DEVLINK_ATTR_PARAM_VALUE);
27853666 if (!param_value_attr)
27863667 goto nla_put_failure;
27873668
....@@ -2823,11 +3704,13 @@
28233704 }
28243705
28253706 static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
3707
+ unsigned int port_index,
28263708 struct devlink_param_item *param_item,
28273709 enum devlink_command cmd,
28283710 u32 portid, u32 seq, int flags)
28293711 {
28303712 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
3713
+ bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
28313714 const struct devlink_param *param = param_item->param;
28323715 struct devlink_param_gset_ctx ctx;
28333716 struct nlattr *param_values_list;
....@@ -2846,12 +3729,15 @@
28463729 return -EOPNOTSUPP;
28473730 param_value[i] = param_item->driverinit_value;
28483731 } else {
3732
+ if (!param_item->published)
3733
+ continue;
28493734 ctx.cmode = i;
28503735 err = devlink_param_get(devlink, param, &ctx);
28513736 if (err)
28523737 return err;
28533738 param_value[i] = ctx.val;
28543739 }
3740
+ param_value_set[i] = true;
28553741 }
28563742
28573743 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
....@@ -2860,7 +3746,14 @@
28603746
28613747 if (devlink_nl_put_handle(msg, devlink))
28623748 goto genlmsg_cancel;
2863
- param_attr = nla_nest_start(msg, DEVLINK_ATTR_PARAM);
3749
+
3750
+ if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
3751
+ cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
3752
+ cmd == DEVLINK_CMD_PORT_PARAM_DEL)
3753
+ if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
3754
+ goto genlmsg_cancel;
3755
+
3756
+ param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
28643757 if (!param_attr)
28653758 goto genlmsg_cancel;
28663759 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
....@@ -2874,12 +3767,13 @@
28743767 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
28753768 goto param_nest_cancel;
28763769
2877
- param_values_list = nla_nest_start(msg, DEVLINK_ATTR_PARAM_VALUES_LIST);
3770
+ param_values_list = nla_nest_start_noflag(msg,
3771
+ DEVLINK_ATTR_PARAM_VALUES_LIST);
28783772 if (!param_values_list)
28793773 goto param_nest_cancel;
28803774
28813775 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
2882
- if (!devlink_param_cmode_is_supported(param, i))
3776
+ if (!param_value_set[i])
28833777 continue;
28843778 err = devlink_nl_param_value_fill_one(msg, param->type,
28853779 i, param_value[i]);
....@@ -2902,18 +3796,22 @@
29023796 }
29033797
29043798 static void devlink_param_notify(struct devlink *devlink,
3799
+ unsigned int port_index,
29053800 struct devlink_param_item *param_item,
29063801 enum devlink_command cmd)
29073802 {
29083803 struct sk_buff *msg;
29093804 int err;
29103805
2911
- WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL);
3806
+ WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
3807
+ cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
3808
+ cmd != DEVLINK_CMD_PORT_PARAM_DEL);
29123809
29133810 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
29143811 if (!msg)
29153812 return;
2916
- err = devlink_nl_param_fill(msg, devlink, param_item, cmd, 0, 0, 0);
3813
+ err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
3814
+ 0, 0, 0);
29173815 if (err) {
29183816 nlmsg_free(msg);
29193817 return;
....@@ -2930,7 +3828,7 @@
29303828 struct devlink *devlink;
29313829 int start = cb->args[0];
29323830 int idx = 0;
2933
- int err;
3831
+ int err = 0;
29343832
29353833 mutex_lock(&devlink_mutex);
29363834 list_for_each_entry(devlink, &devlink_list, list) {
....@@ -2942,12 +3840,14 @@
29423840 idx++;
29433841 continue;
29443842 }
2945
- err = devlink_nl_param_fill(msg, devlink, param_item,
3843
+ err = devlink_nl_param_fill(msg, devlink, 0, param_item,
29463844 DEVLINK_CMD_PARAM_GET,
29473845 NETLINK_CB(cb->skb).portid,
29483846 cb->nlh->nlmsg_seq,
29493847 NLM_F_MULTI);
2950
- if (err) {
3848
+ if (err == -EOPNOTSUPP) {
3849
+ err = 0;
3850
+ } else if (err) {
29513851 mutex_unlock(&devlink->lock);
29523852 goto out;
29533853 }
....@@ -2957,6 +3857,9 @@
29573857 }
29583858 out:
29593859 mutex_unlock(&devlink_mutex);
3860
+
3861
+ if (err != -EMSGSIZE)
3862
+ return err;
29603863
29613864 cb->args[0] = idx;
29623865 return msg->len;
....@@ -3038,7 +3941,7 @@
30383941 }
30393942
30403943 static struct devlink_param_item *
3041
-devlink_param_get_from_info(struct devlink *devlink,
3944
+devlink_param_get_from_info(struct list_head *param_list,
30423945 struct genl_info *info)
30433946 {
30443947 char *param_name;
....@@ -3047,7 +3950,7 @@
30473950 return NULL;
30483951
30493952 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
3050
- return devlink_param_find_by_name(&devlink->param_list, param_name);
3953
+ return devlink_param_find_by_name(param_list, param_name);
30513954 }
30523955
30533956 static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
....@@ -3058,7 +3961,7 @@
30583961 struct sk_buff *msg;
30593962 int err;
30603963
3061
- param_item = devlink_param_get_from_info(devlink, info);
3964
+ param_item = devlink_param_get_from_info(&devlink->param_list, info);
30623965 if (!param_item)
30633966 return -EINVAL;
30643967
....@@ -3066,7 +3969,7 @@
30663969 if (!msg)
30673970 return -ENOMEM;
30683971
3069
- err = devlink_nl_param_fill(msg, devlink, param_item,
3972
+ err = devlink_nl_param_fill(msg, devlink, 0, param_item,
30703973 DEVLINK_CMD_PARAM_GET,
30713974 info->snd_portid, info->snd_seq, 0);
30723975 if (err) {
....@@ -3077,10 +3980,12 @@
30773980 return genlmsg_reply(msg, info);
30783981 }
30793982
3080
-static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
3081
- struct genl_info *info)
3983
+static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
3984
+ unsigned int port_index,
3985
+ struct list_head *param_list,
3986
+ struct genl_info *info,
3987
+ enum devlink_command cmd)
30823988 {
3083
- struct devlink *devlink = info->user_ptr[0];
30843989 enum devlink_param_type param_type;
30853990 struct devlink_param_gset_ctx ctx;
30863991 enum devlink_param_cmode cmode;
....@@ -3089,7 +3994,7 @@
30893994 union devlink_param_value value;
30903995 int err = 0;
30913996
3092
- param_item = devlink_param_get_from_info(devlink, info);
3997
+ param_item = devlink_param_get_from_info(param_list, info);
30933998 if (!param_item)
30943999 return -EINVAL;
30954000 param = param_item->param;
....@@ -3129,17 +4034,28 @@
31294034 return err;
31304035 }
31314036
3132
- devlink_param_notify(devlink, param_item, DEVLINK_CMD_PARAM_NEW);
4037
+ devlink_param_notify(devlink, port_index, param_item, cmd);
31334038 return 0;
31344039 }
31354040
4041
+static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
4042
+ struct genl_info *info)
4043
+{
4044
+ struct devlink *devlink = info->user_ptr[0];
4045
+
4046
+ return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
4047
+ info, DEVLINK_CMD_PARAM_NEW);
4048
+}
4049
+
31364050 static int devlink_param_register_one(struct devlink *devlink,
3137
- const struct devlink_param *param)
4051
+ unsigned int port_index,
4052
+ struct list_head *param_list,
4053
+ const struct devlink_param *param,
4054
+ enum devlink_command cmd)
31384055 {
31394056 struct devlink_param_item *param_item;
31404057
3141
- if (devlink_param_find_by_name(&devlink->param_list,
3142
- param->name))
4058
+ if (devlink_param_find_by_name(param_list, param->name))
31434059 return -EEXIST;
31444060
31454061 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
....@@ -3152,22 +4068,114 @@
31524068 return -ENOMEM;
31534069 param_item->param = param;
31544070
3155
- list_add_tail(&param_item->list, &devlink->param_list);
3156
- devlink_param_notify(devlink, param_item, DEVLINK_CMD_PARAM_NEW);
4071
+ list_add_tail(&param_item->list, param_list);
4072
+ devlink_param_notify(devlink, port_index, param_item, cmd);
31574073 return 0;
31584074 }
31594075
31604076 static void devlink_param_unregister_one(struct devlink *devlink,
3161
- const struct devlink_param *param)
4077
+ unsigned int port_index,
4078
+ struct list_head *param_list,
4079
+ const struct devlink_param *param,
4080
+ enum devlink_command cmd)
31624081 {
31634082 struct devlink_param_item *param_item;
31644083
3165
- param_item = devlink_param_find_by_name(&devlink->param_list,
3166
- param->name);
4084
+ param_item = devlink_param_find_by_name(param_list, param->name);
31674085 WARN_ON(!param_item);
3168
- devlink_param_notify(devlink, param_item, DEVLINK_CMD_PARAM_DEL);
4086
+ devlink_param_notify(devlink, port_index, param_item, cmd);
31694087 list_del(&param_item->list);
31704088 kfree(param_item);
4089
+}
4090
+
4091
+static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
4092
+ struct netlink_callback *cb)
4093
+{
4094
+ struct devlink_param_item *param_item;
4095
+ struct devlink_port *devlink_port;
4096
+ struct devlink *devlink;
4097
+ int start = cb->args[0];
4098
+ int idx = 0;
4099
+ int err = 0;
4100
+
4101
+ mutex_lock(&devlink_mutex);
4102
+ list_for_each_entry(devlink, &devlink_list, list) {
4103
+ if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4104
+ continue;
4105
+ mutex_lock(&devlink->lock);
4106
+ list_for_each_entry(devlink_port, &devlink->port_list, list) {
4107
+ list_for_each_entry(param_item,
4108
+ &devlink_port->param_list, list) {
4109
+ if (idx < start) {
4110
+ idx++;
4111
+ continue;
4112
+ }
4113
+ err = devlink_nl_param_fill(msg,
4114
+ devlink_port->devlink,
4115
+ devlink_port->index, param_item,
4116
+ DEVLINK_CMD_PORT_PARAM_GET,
4117
+ NETLINK_CB(cb->skb).portid,
4118
+ cb->nlh->nlmsg_seq,
4119
+ NLM_F_MULTI);
4120
+ if (err == -EOPNOTSUPP) {
4121
+ err = 0;
4122
+ } else if (err) {
4123
+ mutex_unlock(&devlink->lock);
4124
+ goto out;
4125
+ }
4126
+ idx++;
4127
+ }
4128
+ }
4129
+ mutex_unlock(&devlink->lock);
4130
+ }
4131
+out:
4132
+ mutex_unlock(&devlink_mutex);
4133
+
4134
+ if (err != -EMSGSIZE)
4135
+ return err;
4136
+
4137
+ cb->args[0] = idx;
4138
+ return msg->len;
4139
+}
4140
+
4141
+static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
4142
+ struct genl_info *info)
4143
+{
4144
+ struct devlink_port *devlink_port = info->user_ptr[1];
4145
+ struct devlink_param_item *param_item;
4146
+ struct sk_buff *msg;
4147
+ int err;
4148
+
4149
+ param_item = devlink_param_get_from_info(&devlink_port->param_list,
4150
+ info);
4151
+ if (!param_item)
4152
+ return -EINVAL;
4153
+
4154
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4155
+ if (!msg)
4156
+ return -ENOMEM;
4157
+
4158
+ err = devlink_nl_param_fill(msg, devlink_port->devlink,
4159
+ devlink_port->index, param_item,
4160
+ DEVLINK_CMD_PORT_PARAM_GET,
4161
+ info->snd_portid, info->snd_seq, 0);
4162
+ if (err) {
4163
+ nlmsg_free(msg);
4164
+ return err;
4165
+ }
4166
+
4167
+ return genlmsg_reply(msg, info);
4168
+}
4169
+
4170
+static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
4171
+ struct genl_info *info)
4172
+{
4173
+ struct devlink_port *devlink_port = info->user_ptr[1];
4174
+
4175
+ return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
4176
+ devlink_port->index,
4177
+ &devlink_port->param_list, info,
4178
+ DEVLINK_CMD_PORT_PARAM_NEW);
31714179 }
31724180
31734181 static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
....@@ -3177,7 +4185,7 @@
31774185 struct nlattr *snap_attr;
31784186 int err;
31794187
3180
- snap_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
4188
+ snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
31814189 if (!snap_attr)
31824190 return -EINVAL;
31834191
....@@ -3201,7 +4209,8 @@
32014209 struct nlattr *snapshots_attr;
32024210 int err;
32034211
3204
- snapshots_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_SNAPSHOTS);
4212
+ snapshots_attr = nla_nest_start_noflag(msg,
4213
+ DEVLINK_ATTR_REGION_SNAPSHOTS);
32054214 if (!snapshots_attr)
32064215 return -EINVAL;
32074216
....@@ -3235,7 +4244,14 @@
32354244 if (err)
32364245 goto nla_put_failure;
32374246
3238
- err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->name);
4247
+ if (region->port) {
4248
+ err = nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
4249
+ region->port->index);
4250
+ if (err)
4251
+ goto nla_put_failure;
4252
+ }
4253
+
4254
+ err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->ops->name);
32394255 if (err)
32404256 goto nla_put_failure;
32414257
....@@ -3257,31 +4273,40 @@
32574273 return err;
32584274 }
32594275
3260
-static void devlink_nl_region_notify(struct devlink_region *region,
3261
- struct devlink_snapshot *snapshot,
3262
- enum devlink_command cmd)
4276
+static struct sk_buff *
4277
+devlink_nl_region_notify_build(struct devlink_region *region,
4278
+ struct devlink_snapshot *snapshot,
4279
+ enum devlink_command cmd, u32 portid, u32 seq)
32634280 {
32644281 struct devlink *devlink = region->devlink;
32654282 struct sk_buff *msg;
32664283 void *hdr;
32674284 int err;
32684285
3269
- WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
32704286
32714287 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
32724288 if (!msg)
3273
- return;
4289
+ return ERR_PTR(-ENOMEM);
32744290
3275
- hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
3276
- if (!hdr)
4291
+ hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, 0, cmd);
4292
+ if (!hdr) {
4293
+ err = -EMSGSIZE;
32774294 goto out_free_msg;
4295
+ }
32784296
32794297 err = devlink_nl_put_handle(msg, devlink);
32804298 if (err)
32814299 goto out_cancel_msg;
32824300
4301
+ if (region->port) {
4302
+ err = nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
4303
+ region->port->index);
4304
+ if (err)
4305
+ goto out_cancel_msg;
4306
+ }
4307
+
32834308 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
3284
- region->name);
4309
+ region->ops->name);
32854310 if (err)
32864311 goto out_cancel_msg;
32874312
....@@ -3298,31 +4323,258 @@
32984323 }
32994324 genlmsg_end(msg, hdr);
33004325
3301
- genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3302
- msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3303
-
3304
- return;
4326
+ return msg;
33054327
33064328 out_cancel_msg:
33074329 genlmsg_cancel(msg, hdr);
33084330 out_free_msg:
33094331 nlmsg_free(msg);
4332
+ return ERR_PTR(err);
4333
+}
4334
+
4335
+static void devlink_nl_region_notify(struct devlink_region *region,
4336
+ struct devlink_snapshot *snapshot,
4337
+ enum devlink_command cmd)
4338
+{
4339
+ struct devlink *devlink = region->devlink;
4340
+ struct sk_buff *msg;
4341
+
4342
+ WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
4343
+
4344
+ msg = devlink_nl_region_notify_build(region, snapshot, cmd, 0, 0);
4345
+ if (IS_ERR(msg))
4346
+ return;
4347
+
4348
+ genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
4349
+ msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
4350
+}
4351
+
4352
+/**
4353
+ * __devlink_snapshot_id_increment - Increment number of snapshots using an id
4354
+ * @devlink: devlink instance
4355
+ * @id: the snapshot id
4356
+ *
4357
+ * Track when a new snapshot begins using an id. Load the count for the
4358
+ * given id from the snapshot xarray, increment it, and store it back.
4359
+ *
4360
+ * Called when a new snapshot is created with the given id.
4361
+ *
4362
+ * The id *must* have been previously allocated by
4363
+ * devlink_region_snapshot_id_get().
4364
+ *
4365
+ * Returns 0 on success, or an error on failure.
4366
+ */
4367
+static int __devlink_snapshot_id_increment(struct devlink *devlink, u32 id)
4368
+{
4369
+ unsigned long count;
4370
+ void *p;
4371
+
4372
+ lockdep_assert_held(&devlink->lock);
4373
+
4374
+ p = xa_load(&devlink->snapshot_ids, id);
4375
+ if (WARN_ON(!p))
4376
+ return -EINVAL;
4377
+
4378
+ if (WARN_ON(!xa_is_value(p)))
4379
+ return -EINVAL;
4380
+
4381
+ count = xa_to_value(p);
4382
+ count++;
4383
+
4384
+ return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
4385
+ GFP_KERNEL));
4386
+}
4387
+
4388
+/**
4389
+ * __devlink_snapshot_id_decrement - Decrease number of snapshots using an id
4390
+ * @devlink: devlink instance
4391
+ * @id: the snapshot id
4392
+ *
4393
+ * Track when a snapshot is deleted and stops using an id. Load the count
4394
+ * for the given id from the snapshot xarray, decrement it, and store it
4395
+ * back.
4396
+ *
4397
+ * If the count reaches zero, erase this id from the xarray, freeing it
4398
+ * up for future re-use by devlink_region_snapshot_id_get().
4399
+ *
4400
+ * Called when a snapshot using the given id is deleted, and when the
4401
+ * initial allocator of the id is finished using it.
4402
+ */
4403
+static void __devlink_snapshot_id_decrement(struct devlink *devlink, u32 id)
4404
+{
4405
+ unsigned long count;
4406
+ void *p;
4407
+
4408
+ lockdep_assert_held(&devlink->lock);
4409
+
4410
+ p = xa_load(&devlink->snapshot_ids, id);
4411
+ if (WARN_ON(!p))
4412
+ return;
4413
+
4414
+ if (WARN_ON(!xa_is_value(p)))
4415
+ return;
4416
+
4417
+ count = xa_to_value(p);
4418
+
4419
+ if (count > 1) {
4420
+ count--;
4421
+ xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
4422
+ GFP_KERNEL);
4423
+ } else {
4424
+ /* If this was the last user, we can erase this id */
4425
+ xa_erase(&devlink->snapshot_ids, id);
4426
+ }
4427
+}
4428
+
4429
+/**
4430
+ * __devlink_snapshot_id_insert - Insert a specific snapshot ID
4431
+ * @devlink: devlink instance
4432
+ * @id: the snapshot id
4433
+ *
4434
+ * Mark the given snapshot id as used by inserting a zero value into the
4435
+ * snapshot xarray.
4436
+ *
4437
+ * This must be called while holding the devlink instance lock. Unlike
4438
+ * devlink_snapshot_id_get, the initial reference count is zero, not one.
4439
+ * It is expected that the id will immediately be used before
4440
+ * releasing the devlink instance lock.
4441
+ *
4442
+ * Returns zero on success, or an error code if the snapshot id could not
4443
+ * be inserted.
4444
+ */
4445
+static int __devlink_snapshot_id_insert(struct devlink *devlink, u32 id)
4446
+{
4447
+ lockdep_assert_held(&devlink->lock);
4448
+
4449
+ if (xa_load(&devlink->snapshot_ids, id))
4450
+ return -EEXIST;
4451
+
4452
+ return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(0),
4453
+ GFP_KERNEL));
4454
+}
4455
+
4456
+/**
4457
+ * __devlink_region_snapshot_id_get - get snapshot ID
4458
+ * @devlink: devlink instance
4459
+ * @id: storage to return snapshot id
4460
+ *
4461
+ * Allocates a new snapshot id. Returns zero on success, or a negative
4462
+ * error on failure. Must be called while holding the devlink instance
4463
+ * lock.
4464
+ *
4465
+ * Snapshot IDs are tracked using an xarray which stores the number of
4466
+ * users of the snapshot id.
4467
+ *
4468
+ * Note that the caller of this function counts as a 'user', in order to
4469
+ * avoid race conditions. The caller must release its hold on the
4470
+ * snapshot by using devlink_region_snapshot_id_put.
4471
+ */
4472
+static int __devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
4473
+{
4474
+ lockdep_assert_held(&devlink->lock);
4475
+
4476
+ return xa_alloc(&devlink->snapshot_ids, id, xa_mk_value(1),
4477
+ xa_limit_32b, GFP_KERNEL);
4478
+}
4479
+
4480
+/**
4481
+ * __devlink_region_snapshot_create - create a new snapshot
4482
+ * This will add a new snapshot of a region. The snapshot
4483
+ * will be stored on the region struct and can be accessed
4484
+ * from devlink. This is useful for future analyses of snapshots.
4485
+ * Multiple snapshots can be created on a region.
4486
+ * The @snapshot_id should be obtained using the getter function.
4487
+ *
4488
+ * Must be called only while holding the devlink instance lock.
4489
+ *
4490
+ * @region: devlink region of the snapshot
4491
+ * @data: snapshot data
4492
+ * @snapshot_id: snapshot id to be created
4493
+ */
4494
+static int
4495
+__devlink_region_snapshot_create(struct devlink_region *region,
4496
+ u8 *data, u32 snapshot_id)
4497
+{
4498
+ struct devlink *devlink = region->devlink;
4499
+ struct devlink_snapshot *snapshot;
4500
+ int err;
4501
+
4502
+ lockdep_assert_held(&devlink->lock);
4503
+
4504
+ /* check if region can hold one more snapshot */
4505
+ if (region->cur_snapshots == region->max_snapshots)
4506
+ return -ENOSPC;
4507
+
4508
+ if (devlink_region_snapshot_get_by_id(region, snapshot_id))
4509
+ return -EEXIST;
4510
+
4511
+ snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
4512
+ if (!snapshot)
4513
+ return -ENOMEM;
4514
+
4515
+ err = __devlink_snapshot_id_increment(devlink, snapshot_id);
4516
+ if (err)
4517
+ goto err_snapshot_id_increment;
4518
+
4519
+ snapshot->id = snapshot_id;
4520
+ snapshot->region = region;
4521
+ snapshot->data = data;
4522
+
4523
+ list_add_tail(&snapshot->list, &region->snapshot_list);
4524
+
4525
+ region->cur_snapshots++;
4526
+
4527
+ devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
4528
+ return 0;
4529
+
4530
+err_snapshot_id_increment:
4531
+ kfree(snapshot);
4532
+ return err;
4533
+}
4534
+
4535
+static void devlink_region_snapshot_del(struct devlink_region *region,
4536
+ struct devlink_snapshot *snapshot)
4537
+{
4538
+ struct devlink *devlink = region->devlink;
4539
+
4540
+ lockdep_assert_held(&devlink->lock);
4541
+
4542
+ devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
4543
+ region->cur_snapshots--;
4544
+ list_del(&snapshot->list);
4545
+ region->ops->destructor(snapshot->data);
4546
+ __devlink_snapshot_id_decrement(devlink, snapshot->id);
4547
+ kfree(snapshot);
33104548 }
33114549
33124550 static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
33134551 struct genl_info *info)
33144552 {
33154553 struct devlink *devlink = info->user_ptr[0];
4554
+ struct devlink_port *port = NULL;
33164555 struct devlink_region *region;
33174556 const char *region_name;
33184557 struct sk_buff *msg;
4558
+ unsigned int index;
33194559 int err;
33204560
33214561 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
33224562 return -EINVAL;
33234563
4564
+ if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
4565
+ index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
4566
+
4567
+ port = devlink_port_get_by_index(devlink, index);
4568
+ if (!port)
4569
+ return -ENODEV;
4570
+ }
4571
+
33244572 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3325
- region = devlink_region_get_by_name(devlink, region_name);
4573
+ if (port)
4574
+ region = devlink_port_region_get_by_name(port, region_name);
4575
+ else
4576
+ region = devlink_region_get_by_name(devlink, region_name);
4577
+
33264578 if (!region)
33274579 return -EINVAL;
33284580
....@@ -3341,10 +4593,75 @@
33414593 return genlmsg_reply(msg, info);
33424594 }
33434595
4596
+static int devlink_nl_cmd_region_get_port_dumpit(struct sk_buff *msg,
4597
+ struct netlink_callback *cb,
4598
+ struct devlink_port *port,
4599
+ int *idx,
4600
+ int start)
4601
+{
4602
+ struct devlink_region *region;
4603
+ int err = 0;
4604
+
4605
+ list_for_each_entry(region, &port->region_list, list) {
4606
+ if (*idx < start) {
4607
+ (*idx)++;
4608
+ continue;
4609
+ }
4610
+ err = devlink_nl_region_fill(msg, port->devlink,
4611
+ DEVLINK_CMD_REGION_GET,
4612
+ NETLINK_CB(cb->skb).portid,
4613
+ cb->nlh->nlmsg_seq,
4614
+ NLM_F_MULTI, region);
4615
+ if (err)
4616
+ goto out;
4617
+ (*idx)++;
4618
+ }
4619
+
4620
+out:
4621
+ return err;
4622
+}
4623
+
4624
+static int devlink_nl_cmd_region_get_devlink_dumpit(struct sk_buff *msg,
4625
+ struct netlink_callback *cb,
4626
+ struct devlink *devlink,
4627
+ int *idx,
4628
+ int start)
4629
+{
4630
+ struct devlink_region *region;
4631
+ struct devlink_port *port;
4632
+ int err = 0;
4633
+
4634
+ mutex_lock(&devlink->lock);
4635
+ list_for_each_entry(region, &devlink->region_list, list) {
4636
+ if (*idx < start) {
4637
+ (*idx)++;
4638
+ continue;
4639
+ }
4640
+ err = devlink_nl_region_fill(msg, devlink,
4641
+ DEVLINK_CMD_REGION_GET,
4642
+ NETLINK_CB(cb->skb).portid,
4643
+ cb->nlh->nlmsg_seq,
4644
+ NLM_F_MULTI, region);
4645
+ if (err)
4646
+ goto out;
4647
+ (*idx)++;
4648
+ }
4649
+
4650
+ list_for_each_entry(port, &devlink->port_list, list) {
4651
+ err = devlink_nl_cmd_region_get_port_dumpit(msg, cb, port, idx,
4652
+ start);
4653
+ if (err)
4654
+ goto out;
4655
+ }
4656
+
4657
+out:
4658
+ mutex_unlock(&devlink->lock);
4659
+ return err;
4660
+}
4661
+
33444662 static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
33454663 struct netlink_callback *cb)
33464664 {
3347
- struct devlink_region *region;
33484665 struct devlink *devlink;
33494666 int start = cb->args[0];
33504667 int idx = 0;
....@@ -3354,25 +4671,10 @@
33544671 list_for_each_entry(devlink, &devlink_list, list) {
33554672 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
33564673 continue;
3357
-
3358
- mutex_lock(&devlink->lock);
3359
- list_for_each_entry(region, &devlink->region_list, list) {
3360
- if (idx < start) {
3361
- idx++;
3362
- continue;
3363
- }
3364
- err = devlink_nl_region_fill(msg, devlink,
3365
- DEVLINK_CMD_REGION_GET,
3366
- NETLINK_CB(cb->skb).portid,
3367
- cb->nlh->nlmsg_seq,
3368
- NLM_F_MULTI, region);
3369
- if (err) {
3370
- mutex_unlock(&devlink->lock);
3371
- goto out;
3372
- }
3373
- idx++;
3374
- }
3375
- mutex_unlock(&devlink->lock);
4674
+ err = devlink_nl_cmd_region_get_devlink_dumpit(msg, cb, devlink,
4675
+ &idx, start);
4676
+ if (err)
4677
+ goto out;
33764678 }
33774679 out:
33784680 mutex_unlock(&devlink_mutex);
....@@ -3385,8 +4687,10 @@
33854687 {
33864688 struct devlink *devlink = info->user_ptr[0];
33874689 struct devlink_snapshot *snapshot;
4690
+ struct devlink_port *port = NULL;
33884691 struct devlink_region *region;
33894692 const char *region_name;
4693
+ unsigned int index;
33904694 u32 snapshot_id;
33914695
33924696 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
....@@ -3396,7 +4700,19 @@
33964700 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
33974701 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
33984702
3399
- region = devlink_region_get_by_name(devlink, region_name);
4703
+ if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
4704
+ index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
4705
+
4706
+ port = devlink_port_get_by_index(devlink, index);
4707
+ if (!port)
4708
+ return -ENODEV;
4709
+ }
4710
+
4711
+ if (port)
4712
+ region = devlink_port_region_get_by_name(port, region_name);
4713
+ else
4714
+ region = devlink_region_get_by_name(devlink, region_name);
4715
+
34004716 if (!region)
34014717 return -EINVAL;
34024718
....@@ -3404,9 +4720,124 @@
34044720 if (!snapshot)
34054721 return -EINVAL;
34064722
3407
- devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
3408
- devlink_region_snapshot_del(snapshot);
4723
+ devlink_region_snapshot_del(region, snapshot);
34094724 return 0;
4725
+}
4726
+
4727
+static int
4728
+devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
4729
+{
4730
+ struct devlink *devlink = info->user_ptr[0];
4731
+ struct devlink_snapshot *snapshot;
4732
+ struct devlink_port *port = NULL;
4733
+ struct nlattr *snapshot_id_attr;
4734
+ struct devlink_region *region;
4735
+ const char *region_name;
4736
+ unsigned int index;
4737
+ u32 snapshot_id;
4738
+ u8 *data;
4739
+ int err;
4740
+
4741
+ if (!info->attrs[DEVLINK_ATTR_REGION_NAME]) {
4742
+ NL_SET_ERR_MSG_MOD(info->extack, "No region name provided");
4743
+ return -EINVAL;
4744
+ }
4745
+
4746
+ region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
4747
+
4748
+ if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
4749
+ index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
4750
+
4751
+ port = devlink_port_get_by_index(devlink, index);
4752
+ if (!port)
4753
+ return -ENODEV;
4754
+ }
4755
+
4756
+ if (port)
4757
+ region = devlink_port_region_get_by_name(port, region_name);
4758
+ else
4759
+ region = devlink_region_get_by_name(devlink, region_name);
4760
+
4761
+ if (!region) {
4762
+ NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not exist");
4763
+ return -EINVAL;
4764
+ }
4765
+
4766
+ if (!region->ops->snapshot) {
4767
+ NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not support taking an immediate snapshot");
4768
+ return -EOPNOTSUPP;
4769
+ }
4770
+
4771
+ if (region->cur_snapshots == region->max_snapshots) {
4772
+ NL_SET_ERR_MSG_MOD(info->extack, "The region has reached the maximum number of stored snapshots");
4773
+ return -ENOSPC;
4774
+ }
4775
+
4776
+ snapshot_id_attr = info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID];
4777
+ if (snapshot_id_attr) {
4778
+ snapshot_id = nla_get_u32(snapshot_id_attr);
4779
+
4780
+ if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
4781
+ NL_SET_ERR_MSG_MOD(info->extack, "The requested snapshot id is already in use");
4782
+ return -EEXIST;
4783
+ }
4784
+
4785
+ err = __devlink_snapshot_id_insert(devlink, snapshot_id);
4786
+ if (err)
4787
+ return err;
4788
+ } else {
4789
+ err = __devlink_region_snapshot_id_get(devlink, &snapshot_id);
4790
+ if (err) {
4791
+ NL_SET_ERR_MSG_MOD(info->extack, "Failed to allocate a new snapshot id");
4792
+ return err;
4793
+ }
4794
+ }
4795
+
4796
+ if (port)
4797
+ err = region->port_ops->snapshot(port, region->port_ops,
4798
+ info->extack, &data);
4799
+ else
4800
+ err = region->ops->snapshot(devlink, region->ops,
4801
+ info->extack, &data);
4802
+ if (err)
4803
+ goto err_snapshot_capture;
4804
+
4805
+ err = __devlink_region_snapshot_create(region, data, snapshot_id);
4806
+ if (err)
4807
+ goto err_snapshot_create;
4808
+
4809
+ if (!snapshot_id_attr) {
4810
+ struct sk_buff *msg;
4811
+
4812
+ snapshot = devlink_region_snapshot_get_by_id(region,
4813
+ snapshot_id);
4814
+ if (WARN_ON(!snapshot))
4815
+ return -EINVAL;
4816
+
4817
+ msg = devlink_nl_region_notify_build(region, snapshot,
4818
+ DEVLINK_CMD_REGION_NEW,
4819
+ info->snd_portid,
4820
+ info->snd_seq);
4821
+ err = PTR_ERR_OR_ZERO(msg);
4822
+ if (err)
4823
+ goto err_notify;
4824
+
4825
+ err = genlmsg_reply(msg, info);
4826
+ if (err)
4827
+ goto err_notify;
4828
+ }
4829
+
4830
+ return 0;
4831
+
4832
+err_snapshot_create:
4833
+ region->ops->destructor(data);
4834
+err_snapshot_capture:
4835
+ __devlink_snapshot_id_decrement(devlink, snapshot_id);
4836
+ return err;
4837
+
4838
+err_notify:
4839
+ devlink_region_snapshot_del(region, snapshot);
4840
+ return err;
34104841 }
34114842
34124843 static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
....@@ -3417,7 +4848,7 @@
34174848 struct nlattr *chunk_attr;
34184849 int err;
34194850
3420
- chunk_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_CHUNK);
4851
+ chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK);
34214852 if (!chunk_attr)
34224853 return -EINVAL;
34234854
....@@ -3446,7 +4877,6 @@
34464877 struct nlattr **attrs,
34474878 u64 start_offset,
34484879 u64 end_offset,
3449
- bool dump,
34504880 u64 *new_offset)
34514881 {
34524882 struct devlink_snapshot *snapshot;
....@@ -3460,9 +4890,6 @@
34604890 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
34614891 if (!snapshot)
34624892 return -EINVAL;
3463
-
3464
- if (end_offset > snapshot->data_len || dump)
3465
- end_offset = snapshot->data_len;
34664893
34674894 while (curr_offset < end_offset) {
34684895 u32 data_size;
....@@ -3490,57 +4917,56 @@
34904917 static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
34914918 struct netlink_callback *cb)
34924919 {
3493
- u64 ret_offset, start_offset, end_offset = 0;
3494
- struct nlattr *attrs[DEVLINK_ATTR_MAX + 1];
3495
- const struct genl_ops *ops = cb->data;
4920
+ const struct genl_dumpit_info *info = genl_dumpit_info(cb);
4921
+ u64 ret_offset, start_offset, end_offset = U64_MAX;
4922
+ struct nlattr **attrs = info->attrs;
4923
+ struct devlink_port *port = NULL;
34964924 struct devlink_region *region;
34974925 struct nlattr *chunks_attr;
34984926 const char *region_name;
34994927 struct devlink *devlink;
3500
- bool dump = true;
4928
+ unsigned int index;
35014929 void *hdr;
35024930 int err;
35034931
35044932 start_offset = *((u64 *)&cb->args[0]);
35054933
3506
- err = nlmsg_parse(cb->nlh, GENL_HDRLEN + devlink_nl_family.hdrsize,
3507
- attrs, DEVLINK_ATTR_MAX, ops->policy, NULL);
3508
- if (err)
3509
- goto out;
3510
-
3511
- devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
3512
- if (IS_ERR(devlink))
3513
- goto out;
3514
-
35154934 mutex_lock(&devlink_mutex);
4935
+ devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
4936
+ if (IS_ERR(devlink)) {
4937
+ err = PTR_ERR(devlink);
4938
+ goto out_dev;
4939
+ }
4940
+
35164941 mutex_lock(&devlink->lock);
35174942
35184943 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
3519
- !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
4944
+ !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
4945
+ err = -EINVAL;
35204946 goto out_unlock;
4947
+ }
4948
+
4949
+ if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
4950
+ index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
4951
+
4952
+ port = devlink_port_get_by_index(devlink, index);
4953
+ if (!port) {
4954
+ err = -ENODEV;
4955
+ goto out_unlock;
4956
+ }
4957
+ }
35214958
35224959 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
3523
- region = devlink_region_get_by_name(devlink, region_name);
3524
- if (!region)
4960
+
4961
+ if (port)
4962
+ region = devlink_port_region_get_by_name(port, region_name);
4963
+ else
4964
+ region = devlink_region_get_by_name(devlink, region_name);
4965
+
4966
+ if (!region) {
4967
+ err = -EINVAL;
35254968 goto out_unlock;
3526
-
3527
- hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
3528
- &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
3529
- DEVLINK_CMD_REGION_READ);
3530
- if (!hdr)
3531
- goto out_unlock;
3532
-
3533
- err = devlink_nl_put_handle(skb, devlink);
3534
- if (err)
3535
- goto nla_put_failure;
3536
-
3537
- err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
3538
- if (err)
3539
- goto nla_put_failure;
3540
-
3541
- chunks_attr = nla_nest_start(skb, DEVLINK_ATTR_REGION_CHUNKS);
3542
- if (!chunks_attr)
3543
- goto nla_put_failure;
4969
+ }
35444970
35454971 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
35464972 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
....@@ -3550,21 +4976,59 @@
35504976
35514977 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
35524978 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
3553
- dump = false;
4979
+ }
4980
+
4981
+ if (end_offset > region->size)
4982
+ end_offset = region->size;
4983
+
4984
+ /* return 0 if there is no further data to read */
4985
+ if (start_offset == end_offset) {
4986
+ err = 0;
4987
+ goto out_unlock;
4988
+ }
4989
+
4990
+ hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
4991
+ &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
4992
+ DEVLINK_CMD_REGION_READ);
4993
+ if (!hdr) {
4994
+ err = -EMSGSIZE;
4995
+ goto out_unlock;
4996
+ }
4997
+
4998
+ err = devlink_nl_put_handle(skb, devlink);
4999
+ if (err)
5000
+ goto nla_put_failure;
5001
+
5002
+ if (region->port) {
5003
+ err = nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX,
5004
+ region->port->index);
5005
+ if (err)
5006
+ goto nla_put_failure;
5007
+ }
5008
+
5009
+ err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
5010
+ if (err)
5011
+ goto nla_put_failure;
5012
+
5013
+ chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS);
5014
+ if (!chunks_attr) {
5015
+ err = -EMSGSIZE;
5016
+ goto nla_put_failure;
35545017 }
35555018
35565019 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
35575020 region, attrs,
35585021 start_offset,
3559
- end_offset, dump,
3560
- &ret_offset);
5022
+ end_offset, &ret_offset);
35615023
35625024 if (err && err != -EMSGSIZE)
35635025 goto nla_put_failure;
35645026
35655027 /* Check if there was any progress done to prevent infinite loop */
3566
- if (ret_offset == start_offset)
5028
+ if (ret_offset == start_offset) {
5029
+ err = -EINVAL;
35675030 goto nla_put_failure;
5031
+ }
35685032
35695033 *((u64 *)&cb->args[0]) = ret_offset;
35705034
....@@ -3579,16 +5043,2513 @@
35795043 genlmsg_cancel(skb, hdr);
35805044 out_unlock:
35815045 mutex_unlock(&devlink->lock);
5046
+out_dev:
35825047 mutex_unlock(&devlink_mutex);
3583
-out:
5048
+ return err;
5049
+}
5050
+
5051
+struct devlink_info_req {
5052
+ struct sk_buff *msg;
5053
+};
5054
+
5055
+int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
5056
+{
5057
+ return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
5058
+}
5059
+EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
5060
+
5061
+int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
5062
+{
5063
+ return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
5064
+}
5065
+EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
5066
+
5067
+int devlink_info_board_serial_number_put(struct devlink_info_req *req,
5068
+ const char *bsn)
5069
+{
5070
+ return nla_put_string(req->msg, DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER,
5071
+ bsn);
5072
+}
5073
+EXPORT_SYMBOL_GPL(devlink_info_board_serial_number_put);
5074
+
5075
+static int devlink_info_version_put(struct devlink_info_req *req, int attr,
5076
+ const char *version_name,
5077
+ const char *version_value)
5078
+{
5079
+ struct nlattr *nest;
5080
+ int err;
5081
+
5082
+ nest = nla_nest_start_noflag(req->msg, attr);
5083
+ if (!nest)
5084
+ return -EMSGSIZE;
5085
+
5086
+ err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
5087
+ version_name);
5088
+ if (err)
5089
+ goto nla_put_failure;
5090
+
5091
+ err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
5092
+ version_value);
5093
+ if (err)
5094
+ goto nla_put_failure;
5095
+
5096
+ nla_nest_end(req->msg, nest);
5097
+
5098
+ return 0;
5099
+
5100
+nla_put_failure:
5101
+ nla_nest_cancel(req->msg, nest);
5102
+ return err;
5103
+}
5104
+
5105
+int devlink_info_version_fixed_put(struct devlink_info_req *req,
5106
+ const char *version_name,
5107
+ const char *version_value)
5108
+{
5109
+ return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
5110
+ version_name, version_value);
5111
+}
5112
+EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
5113
+
5114
+int devlink_info_version_stored_put(struct devlink_info_req *req,
5115
+ const char *version_name,
5116
+ const char *version_value)
5117
+{
5118
+ return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
5119
+ version_name, version_value);
5120
+}
5121
+EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
5122
+
5123
+int devlink_info_version_running_put(struct devlink_info_req *req,
5124
+ const char *version_name,
5125
+ const char *version_value)
5126
+{
5127
+ return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
5128
+ version_name, version_value);
5129
+}
5130
+EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
5131
+
5132
+static int
5133
+devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
5134
+ enum devlink_command cmd, u32 portid,
5135
+ u32 seq, int flags, struct netlink_ext_ack *extack)
5136
+{
5137
+ struct devlink_info_req req;
5138
+ void *hdr;
5139
+ int err;
5140
+
5141
+ hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5142
+ if (!hdr)
5143
+ return -EMSGSIZE;
5144
+
5145
+ err = -EMSGSIZE;
5146
+ if (devlink_nl_put_handle(msg, devlink))
5147
+ goto err_cancel_msg;
5148
+
5149
+ req.msg = msg;
5150
+ err = devlink->ops->info_get(devlink, &req, extack);
5151
+ if (err)
5152
+ goto err_cancel_msg;
5153
+
5154
+ genlmsg_end(msg, hdr);
5155
+ return 0;
5156
+
5157
+err_cancel_msg:
5158
+ genlmsg_cancel(msg, hdr);
5159
+ return err;
5160
+}
5161
+
5162
+static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
5163
+ struct genl_info *info)
5164
+{
5165
+ struct devlink *devlink = info->user_ptr[0];
5166
+ struct sk_buff *msg;
5167
+ int err;
5168
+
5169
+ if (!devlink->ops->info_get)
5170
+ return -EOPNOTSUPP;
5171
+
5172
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5173
+ if (!msg)
5174
+ return -ENOMEM;
5175
+
5176
+ err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
5177
+ info->snd_portid, info->snd_seq, 0,
5178
+ info->extack);
5179
+ if (err) {
5180
+ nlmsg_free(msg);
5181
+ return err;
5182
+ }
5183
+
5184
+ return genlmsg_reply(msg, info);
5185
+}
5186
+
5187
+static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
5188
+ struct netlink_callback *cb)
5189
+{
5190
+ struct devlink *devlink;
5191
+ int start = cb->args[0];
5192
+ int idx = 0;
5193
+ int err = 0;
5194
+
5195
+ mutex_lock(&devlink_mutex);
5196
+ list_for_each_entry(devlink, &devlink_list, list) {
5197
+ if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5198
+ continue;
5199
+ if (idx < start) {
5200
+ idx++;
5201
+ continue;
5202
+ }
5203
+
5204
+ if (!devlink->ops->info_get) {
5205
+ idx++;
5206
+ continue;
5207
+ }
5208
+
5209
+ mutex_lock(&devlink->lock);
5210
+ err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
5211
+ NETLINK_CB(cb->skb).portid,
5212
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
5213
+ cb->extack);
5214
+ mutex_unlock(&devlink->lock);
5215
+ if (err == -EOPNOTSUPP)
5216
+ err = 0;
5217
+ else if (err)
5218
+ break;
5219
+ idx++;
5220
+ }
5221
+ mutex_unlock(&devlink_mutex);
5222
+
5223
+ if (err != -EMSGSIZE)
5224
+ return err;
5225
+
5226
+ cb->args[0] = idx;
5227
+ return msg->len;
5228
+}
5229
+
5230
+struct devlink_fmsg_item {
5231
+ struct list_head list;
5232
+ int attrtype;
5233
+ u8 nla_type;
5234
+ u16 len;
5235
+ int value[];
5236
+};
5237
+
5238
+struct devlink_fmsg {
5239
+ struct list_head item_list;
5240
+ bool putting_binary; /* This flag forces enclosing of binary data
5241
+ * in an array brackets. It forces using
5242
+ * of designated API:
5243
+ * devlink_fmsg_binary_pair_nest_start()
5244
+ * devlink_fmsg_binary_pair_nest_end()
5245
+ */
5246
+};
5247
+
5248
+static struct devlink_fmsg *devlink_fmsg_alloc(void)
5249
+{
5250
+ struct devlink_fmsg *fmsg;
5251
+
5252
+ fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
5253
+ if (!fmsg)
5254
+ return NULL;
5255
+
5256
+ INIT_LIST_HEAD(&fmsg->item_list);
5257
+
5258
+ return fmsg;
5259
+}
5260
+
5261
+static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
5262
+{
5263
+ struct devlink_fmsg_item *item, *tmp;
5264
+
5265
+ list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
5266
+ list_del(&item->list);
5267
+ kfree(item);
5268
+ }
5269
+ kfree(fmsg);
5270
+}
5271
+
5272
+static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
5273
+ int attrtype)
5274
+{
5275
+ struct devlink_fmsg_item *item;
5276
+
5277
+ item = kzalloc(sizeof(*item), GFP_KERNEL);
5278
+ if (!item)
5279
+ return -ENOMEM;
5280
+
5281
+ item->attrtype = attrtype;
5282
+ list_add_tail(&item->list, &fmsg->item_list);
5283
+
35845284 return 0;
35855285 }
35865286
5287
+int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
5288
+{
5289
+ if (fmsg->putting_binary)
5290
+ return -EINVAL;
5291
+
5292
+ return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
5293
+}
5294
+EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
5295
+
5296
+static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
5297
+{
5298
+ if (fmsg->putting_binary)
5299
+ return -EINVAL;
5300
+
5301
+ return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
5302
+}
5303
+
5304
+int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
5305
+{
5306
+ if (fmsg->putting_binary)
5307
+ return -EINVAL;
5308
+
5309
+ return devlink_fmsg_nest_end(fmsg);
5310
+}
5311
+EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
5312
+
5313
+#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
5314
+
5315
+static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
5316
+{
5317
+ struct devlink_fmsg_item *item;
5318
+
5319
+ if (fmsg->putting_binary)
5320
+ return -EINVAL;
5321
+
5322
+ if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
5323
+ return -EMSGSIZE;
5324
+
5325
+ item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
5326
+ if (!item)
5327
+ return -ENOMEM;
5328
+
5329
+ item->nla_type = NLA_NUL_STRING;
5330
+ item->len = strlen(name) + 1;
5331
+ item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
5332
+ memcpy(&item->value, name, item->len);
5333
+ list_add_tail(&item->list, &fmsg->item_list);
5334
+
5335
+ return 0;
5336
+}
5337
+
5338
+int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
5339
+{
5340
+ int err;
5341
+
5342
+ if (fmsg->putting_binary)
5343
+ return -EINVAL;
5344
+
5345
+ err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
5346
+ if (err)
5347
+ return err;
5348
+
5349
+ err = devlink_fmsg_put_name(fmsg, name);
5350
+ if (err)
5351
+ return err;
5352
+
5353
+ return 0;
5354
+}
5355
+EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
5356
+
5357
+int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
5358
+{
5359
+ if (fmsg->putting_binary)
5360
+ return -EINVAL;
5361
+
5362
+ return devlink_fmsg_nest_end(fmsg);
5363
+}
5364
+EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
5365
+
5366
+int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
5367
+ const char *name)
5368
+{
5369
+ int err;
5370
+
5371
+ if (fmsg->putting_binary)
5372
+ return -EINVAL;
5373
+
5374
+ err = devlink_fmsg_pair_nest_start(fmsg, name);
5375
+ if (err)
5376
+ return err;
5377
+
5378
+ err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
5379
+ if (err)
5380
+ return err;
5381
+
5382
+ return 0;
5383
+}
5384
+EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
5385
+
5386
+int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
5387
+{
5388
+ int err;
5389
+
5390
+ if (fmsg->putting_binary)
5391
+ return -EINVAL;
5392
+
5393
+ err = devlink_fmsg_nest_end(fmsg);
5394
+ if (err)
5395
+ return err;
5396
+
5397
+ err = devlink_fmsg_nest_end(fmsg);
5398
+ if (err)
5399
+ return err;
5400
+
5401
+ return 0;
5402
+}
5403
+EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
5404
+
5405
+int devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg,
5406
+ const char *name)
5407
+{
5408
+ int err;
5409
+
5410
+ err = devlink_fmsg_arr_pair_nest_start(fmsg, name);
5411
+ if (err)
5412
+ return err;
5413
+
5414
+ fmsg->putting_binary = true;
5415
+ return err;
5416
+}
5417
+EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start);
5418
+
5419
+int devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg)
5420
+{
5421
+ if (!fmsg->putting_binary)
5422
+ return -EINVAL;
5423
+
5424
+ fmsg->putting_binary = false;
5425
+ return devlink_fmsg_arr_pair_nest_end(fmsg);
5426
+}
5427
+EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end);
5428
+
5429
+static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
5430
+ const void *value, u16 value_len,
5431
+ u8 value_nla_type)
5432
+{
5433
+ struct devlink_fmsg_item *item;
5434
+
5435
+ if (value_len > DEVLINK_FMSG_MAX_SIZE)
5436
+ return -EMSGSIZE;
5437
+
5438
+ item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
5439
+ if (!item)
5440
+ return -ENOMEM;
5441
+
5442
+ item->nla_type = value_nla_type;
5443
+ item->len = value_len;
5444
+ item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
5445
+ memcpy(&item->value, value, item->len);
5446
+ list_add_tail(&item->list, &fmsg->item_list);
5447
+
5448
+ return 0;
5449
+}
5450
+
5451
+int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
5452
+{
5453
+ if (fmsg->putting_binary)
5454
+ return -EINVAL;
5455
+
5456
+ return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
5457
+}
5458
+EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
5459
+
5460
+int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
5461
+{
5462
+ if (fmsg->putting_binary)
5463
+ return -EINVAL;
5464
+
5465
+ return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
5466
+}
5467
+EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
5468
+
5469
+int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
5470
+{
5471
+ if (fmsg->putting_binary)
5472
+ return -EINVAL;
5473
+
5474
+ return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
5475
+}
5476
+EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
5477
+
5478
+int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
5479
+{
5480
+ if (fmsg->putting_binary)
5481
+ return -EINVAL;
5482
+
5483
+ return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
5484
+}
5485
+EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
5486
+
5487
+int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
5488
+{
5489
+ if (fmsg->putting_binary)
5490
+ return -EINVAL;
5491
+
5492
+ return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
5493
+ NLA_NUL_STRING);
5494
+}
5495
+EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
5496
+
5497
+int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
5498
+ u16 value_len)
5499
+{
5500
+ if (!fmsg->putting_binary)
5501
+ return -EINVAL;
5502
+
5503
+ return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
5504
+}
5505
+EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
5506
+
5507
+int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
5508
+ bool value)
5509
+{
5510
+ int err;
5511
+
5512
+ err = devlink_fmsg_pair_nest_start(fmsg, name);
5513
+ if (err)
5514
+ return err;
5515
+
5516
+ err = devlink_fmsg_bool_put(fmsg, value);
5517
+ if (err)
5518
+ return err;
5519
+
5520
+ err = devlink_fmsg_pair_nest_end(fmsg);
5521
+ if (err)
5522
+ return err;
5523
+
5524
+ return 0;
5525
+}
5526
+EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
5527
+
5528
+int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
5529
+ u8 value)
5530
+{
5531
+ int err;
5532
+
5533
+ err = devlink_fmsg_pair_nest_start(fmsg, name);
5534
+ if (err)
5535
+ return err;
5536
+
5537
+ err = devlink_fmsg_u8_put(fmsg, value);
5538
+ if (err)
5539
+ return err;
5540
+
5541
+ err = devlink_fmsg_pair_nest_end(fmsg);
5542
+ if (err)
5543
+ return err;
5544
+
5545
+ return 0;
5546
+}
5547
+EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
5548
+
5549
+int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
5550
+ u32 value)
5551
+{
5552
+ int err;
5553
+
5554
+ err = devlink_fmsg_pair_nest_start(fmsg, name);
5555
+ if (err)
5556
+ return err;
5557
+
5558
+ err = devlink_fmsg_u32_put(fmsg, value);
5559
+ if (err)
5560
+ return err;
5561
+
5562
+ err = devlink_fmsg_pair_nest_end(fmsg);
5563
+ if (err)
5564
+ return err;
5565
+
5566
+ return 0;
5567
+}
5568
+EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
5569
+
5570
+int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
5571
+ u64 value)
5572
+{
5573
+ int err;
5574
+
5575
+ err = devlink_fmsg_pair_nest_start(fmsg, name);
5576
+ if (err)
5577
+ return err;
5578
+
5579
+ err = devlink_fmsg_u64_put(fmsg, value);
5580
+ if (err)
5581
+ return err;
5582
+
5583
+ err = devlink_fmsg_pair_nest_end(fmsg);
5584
+ if (err)
5585
+ return err;
5586
+
5587
+ return 0;
5588
+}
5589
+EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
5590
+
5591
+int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
5592
+ const char *value)
5593
+{
5594
+ int err;
5595
+
5596
+ err = devlink_fmsg_pair_nest_start(fmsg, name);
5597
+ if (err)
5598
+ return err;
5599
+
5600
+ err = devlink_fmsg_string_put(fmsg, value);
5601
+ if (err)
5602
+ return err;
5603
+
5604
+ err = devlink_fmsg_pair_nest_end(fmsg);
5605
+ if (err)
5606
+ return err;
5607
+
5608
+ return 0;
5609
+}
5610
+EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
5611
+
5612
+int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
5613
+ const void *value, u32 value_len)
5614
+{
5615
+ u32 data_size;
5616
+ int end_err;
5617
+ u32 offset;
5618
+ int err;
5619
+
5620
+ err = devlink_fmsg_binary_pair_nest_start(fmsg, name);
5621
+ if (err)
5622
+ return err;
5623
+
5624
+ for (offset = 0; offset < value_len; offset += data_size) {
5625
+ data_size = value_len - offset;
5626
+ if (data_size > DEVLINK_FMSG_MAX_SIZE)
5627
+ data_size = DEVLINK_FMSG_MAX_SIZE;
5628
+ err = devlink_fmsg_binary_put(fmsg, value + offset, data_size);
5629
+ if (err)
5630
+ break;
5631
+ /* Exit from loop with a break (instead of
5632
+ * return) to make sure putting_binary is turned off in
5633
+ * devlink_fmsg_binary_pair_nest_end
5634
+ */
5635
+ }
5636
+
5637
+ end_err = devlink_fmsg_binary_pair_nest_end(fmsg);
5638
+ if (end_err)
5639
+ err = end_err;
5640
+
5641
+ return err;
5642
+}
5643
+EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
5644
+
5645
+static int
5646
+devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
5647
+{
5648
+ switch (msg->nla_type) {
5649
+ case NLA_FLAG:
5650
+ case NLA_U8:
5651
+ case NLA_U32:
5652
+ case NLA_U64:
5653
+ case NLA_NUL_STRING:
5654
+ case NLA_BINARY:
5655
+ return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
5656
+ msg->nla_type);
5657
+ default:
5658
+ return -EINVAL;
5659
+ }
5660
+}
5661
+
5662
+static int
5663
+devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
5664
+{
5665
+ int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
5666
+ u8 tmp;
5667
+
5668
+ switch (msg->nla_type) {
5669
+ case NLA_FLAG:
5670
+ /* Always provide flag data, regardless of its value */
5671
+ tmp = *(bool *) msg->value;
5672
+
5673
+ return nla_put_u8(skb, attrtype, tmp);
5674
+ case NLA_U8:
5675
+ return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
5676
+ case NLA_U32:
5677
+ return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
5678
+ case NLA_U64:
5679
+ return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
5680
+ DEVLINK_ATTR_PAD);
5681
+ case NLA_NUL_STRING:
5682
+ return nla_put_string(skb, attrtype, (char *) &msg->value);
5683
+ case NLA_BINARY:
5684
+ return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
5685
+ default:
5686
+ return -EINVAL;
5687
+ }
5688
+}
5689
+
5690
+static int
5691
+devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
5692
+ int *start)
5693
+{
5694
+ struct devlink_fmsg_item *item;
5695
+ struct nlattr *fmsg_nlattr;
5696
+ int i = 0;
5697
+ int err;
5698
+
5699
+ fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
5700
+ if (!fmsg_nlattr)
5701
+ return -EMSGSIZE;
5702
+
5703
+ list_for_each_entry(item, &fmsg->item_list, list) {
5704
+ if (i < *start) {
5705
+ i++;
5706
+ continue;
5707
+ }
5708
+
5709
+ switch (item->attrtype) {
5710
+ case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
5711
+ case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
5712
+ case DEVLINK_ATTR_FMSG_ARR_NEST_START:
5713
+ case DEVLINK_ATTR_FMSG_NEST_END:
5714
+ err = nla_put_flag(skb, item->attrtype);
5715
+ break;
5716
+ case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
5717
+ err = devlink_fmsg_item_fill_type(item, skb);
5718
+ if (err)
5719
+ break;
5720
+ err = devlink_fmsg_item_fill_data(item, skb);
5721
+ break;
5722
+ case DEVLINK_ATTR_FMSG_OBJ_NAME:
5723
+ err = nla_put_string(skb, item->attrtype,
5724
+ (char *) &item->value);
5725
+ break;
5726
+ default:
5727
+ err = -EINVAL;
5728
+ break;
5729
+ }
5730
+ if (!err)
5731
+ *start = ++i;
5732
+ else
5733
+ break;
5734
+ }
5735
+
5736
+ nla_nest_end(skb, fmsg_nlattr);
5737
+ return err;
5738
+}
5739
+
5740
+static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
5741
+ struct genl_info *info,
5742
+ enum devlink_command cmd, int flags)
5743
+{
5744
+ struct nlmsghdr *nlh;
5745
+ struct sk_buff *skb;
5746
+ bool last = false;
5747
+ int index = 0;
5748
+ void *hdr;
5749
+ int err;
5750
+
5751
+ while (!last) {
5752
+ int tmp_index = index;
5753
+
5754
+ skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
5755
+ if (!skb)
5756
+ return -ENOMEM;
5757
+
5758
+ hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
5759
+ &devlink_nl_family, flags | NLM_F_MULTI, cmd);
5760
+ if (!hdr) {
5761
+ err = -EMSGSIZE;
5762
+ goto nla_put_failure;
5763
+ }
5764
+
5765
+ err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
5766
+ if (!err)
5767
+ last = true;
5768
+ else if (err != -EMSGSIZE || tmp_index == index)
5769
+ goto nla_put_failure;
5770
+
5771
+ genlmsg_end(skb, hdr);
5772
+ err = genlmsg_reply(skb, info);
5773
+ if (err)
5774
+ return err;
5775
+ }
5776
+
5777
+ skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
5778
+ if (!skb)
5779
+ return -ENOMEM;
5780
+ nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
5781
+ NLMSG_DONE, 0, flags | NLM_F_MULTI);
5782
+ if (!nlh) {
5783
+ err = -EMSGSIZE;
5784
+ goto nla_put_failure;
5785
+ }
5786
+
5787
+ return genlmsg_reply(skb, info);
5788
+
5789
+nla_put_failure:
5790
+ nlmsg_free(skb);
5791
+ return err;
5792
+}
5793
+
5794
+static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
5795
+ struct netlink_callback *cb,
5796
+ enum devlink_command cmd)
5797
+{
5798
+ int index = cb->args[0];
5799
+ int tmp_index = index;
5800
+ void *hdr;
5801
+ int err;
5802
+
5803
+ hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
5804
+ &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
5805
+ if (!hdr) {
5806
+ err = -EMSGSIZE;
5807
+ goto nla_put_failure;
5808
+ }
5809
+
5810
+ err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
5811
+ if ((err && err != -EMSGSIZE) || tmp_index == index)
5812
+ goto nla_put_failure;
5813
+
5814
+ cb->args[0] = index;
5815
+ genlmsg_end(skb, hdr);
5816
+ return skb->len;
5817
+
5818
+nla_put_failure:
5819
+ genlmsg_cancel(skb, hdr);
5820
+ return err;
5821
+}
5822
+
5823
+struct devlink_health_reporter {
5824
+ struct list_head list;
5825
+ void *priv;
5826
+ const struct devlink_health_reporter_ops *ops;
5827
+ struct devlink *devlink;
5828
+ struct devlink_port *devlink_port;
5829
+ struct devlink_fmsg *dump_fmsg;
5830
+ struct mutex dump_lock; /* lock parallel read/write from dump buffers */
5831
+ u64 graceful_period;
5832
+ bool auto_recover;
5833
+ bool auto_dump;
5834
+ u8 health_state;
5835
+ u64 dump_ts;
5836
+ u64 dump_real_ts;
5837
+ u64 error_count;
5838
+ u64 recovery_count;
5839
+ u64 last_recovery_ts;
5840
+ refcount_t refcount;
5841
+};
5842
+
5843
+void *
5844
+devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
5845
+{
5846
+ return reporter->priv;
5847
+}
5848
+EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
5849
+
5850
+static struct devlink_health_reporter *
5851
+__devlink_health_reporter_find_by_name(struct list_head *reporter_list,
5852
+ struct mutex *list_lock,
5853
+ const char *reporter_name)
5854
+{
5855
+ struct devlink_health_reporter *reporter;
5856
+
5857
+ lockdep_assert_held(list_lock);
5858
+ list_for_each_entry(reporter, reporter_list, list)
5859
+ if (!strcmp(reporter->ops->name, reporter_name))
5860
+ return reporter;
5861
+ return NULL;
5862
+}
5863
+
5864
+static struct devlink_health_reporter *
5865
+devlink_health_reporter_find_by_name(struct devlink *devlink,
5866
+ const char *reporter_name)
5867
+{
5868
+ return __devlink_health_reporter_find_by_name(&devlink->reporter_list,
5869
+ &devlink->reporters_lock,
5870
+ reporter_name);
5871
+}
5872
+
5873
+static struct devlink_health_reporter *
5874
+devlink_port_health_reporter_find_by_name(struct devlink_port *devlink_port,
5875
+ const char *reporter_name)
5876
+{
5877
+ return __devlink_health_reporter_find_by_name(&devlink_port->reporter_list,
5878
+ &devlink_port->reporters_lock,
5879
+ reporter_name);
5880
+}
5881
+
5882
+static struct devlink_health_reporter *
5883
+__devlink_health_reporter_create(struct devlink *devlink,
5884
+ const struct devlink_health_reporter_ops *ops,
5885
+ u64 graceful_period, void *priv)
5886
+{
5887
+ struct devlink_health_reporter *reporter;
5888
+
5889
+ if (WARN_ON(graceful_period && !ops->recover))
5890
+ return ERR_PTR(-EINVAL);
5891
+
5892
+ reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
5893
+ if (!reporter)
5894
+ return ERR_PTR(-ENOMEM);
5895
+
5896
+ reporter->priv = priv;
5897
+ reporter->ops = ops;
5898
+ reporter->devlink = devlink;
5899
+ reporter->graceful_period = graceful_period;
5900
+ reporter->auto_recover = !!ops->recover;
5901
+ reporter->auto_dump = !!ops->dump;
5902
+ mutex_init(&reporter->dump_lock);
5903
+ refcount_set(&reporter->refcount, 1);
5904
+ return reporter;
5905
+}
5906
+
5907
+/**
5908
+ * devlink_port_health_reporter_create - create devlink health reporter for
5909
+ * specified port instance
5910
+ *
5911
+ * @port: devlink_port which should contain the new reporter
5912
+ * @ops: ops
5913
+ * @graceful_period: to avoid recovery loops, in msecs
5914
+ * @priv: priv
5915
+ */
5916
+struct devlink_health_reporter *
5917
+devlink_port_health_reporter_create(struct devlink_port *port,
5918
+ const struct devlink_health_reporter_ops *ops,
5919
+ u64 graceful_period, void *priv)
5920
+{
5921
+ struct devlink_health_reporter *reporter;
5922
+
5923
+ mutex_lock(&port->reporters_lock);
5924
+ if (__devlink_health_reporter_find_by_name(&port->reporter_list,
5925
+ &port->reporters_lock, ops->name)) {
5926
+ reporter = ERR_PTR(-EEXIST);
5927
+ goto unlock;
5928
+ }
5929
+
5930
+ reporter = __devlink_health_reporter_create(port->devlink, ops,
5931
+ graceful_period, priv);
5932
+ if (IS_ERR(reporter))
5933
+ goto unlock;
5934
+
5935
+ reporter->devlink_port = port;
5936
+ list_add_tail(&reporter->list, &port->reporter_list);
5937
+unlock:
5938
+ mutex_unlock(&port->reporters_lock);
5939
+ return reporter;
5940
+}
5941
+EXPORT_SYMBOL_GPL(devlink_port_health_reporter_create);
5942
+
5943
+/**
5944
+ * devlink_health_reporter_create - create devlink health reporter
5945
+ *
5946
+ * @devlink: devlink
5947
+ * @ops: ops
5948
+ * @graceful_period: to avoid recovery loops, in msecs
5949
+ * @priv: priv
5950
+ */
5951
+struct devlink_health_reporter *
5952
+devlink_health_reporter_create(struct devlink *devlink,
5953
+ const struct devlink_health_reporter_ops *ops,
5954
+ u64 graceful_period, void *priv)
5955
+{
5956
+ struct devlink_health_reporter *reporter;
5957
+
5958
+ mutex_lock(&devlink->reporters_lock);
5959
+ if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
5960
+ reporter = ERR_PTR(-EEXIST);
5961
+ goto unlock;
5962
+ }
5963
+
5964
+ reporter = __devlink_health_reporter_create(devlink, ops,
5965
+ graceful_period, priv);
5966
+ if (IS_ERR(reporter))
5967
+ goto unlock;
5968
+
5969
+ list_add_tail(&reporter->list, &devlink->reporter_list);
5970
+unlock:
5971
+ mutex_unlock(&devlink->reporters_lock);
5972
+ return reporter;
5973
+}
5974
+EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
5975
+
5976
+static void
5977
+devlink_health_reporter_free(struct devlink_health_reporter *reporter)
5978
+{
5979
+ mutex_destroy(&reporter->dump_lock);
5980
+ if (reporter->dump_fmsg)
5981
+ devlink_fmsg_free(reporter->dump_fmsg);
5982
+ kfree(reporter);
5983
+}
5984
+
5985
+static void
5986
+devlink_health_reporter_put(struct devlink_health_reporter *reporter)
5987
+{
5988
+ if (refcount_dec_and_test(&reporter->refcount))
5989
+ devlink_health_reporter_free(reporter);
5990
+}
5991
+
5992
+static void
5993
+__devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
5994
+{
5995
+ list_del(&reporter->list);
5996
+ devlink_health_reporter_put(reporter);
5997
+}
5998
+
5999
+/**
6000
+ * devlink_health_reporter_destroy - destroy devlink health reporter
6001
+ *
6002
+ * @reporter: devlink health reporter to destroy
6003
+ */
6004
+void
6005
+devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
6006
+{
6007
+ struct mutex *lock = &reporter->devlink->reporters_lock;
6008
+
6009
+ mutex_lock(lock);
6010
+ __devlink_health_reporter_destroy(reporter);
6011
+ mutex_unlock(lock);
6012
+}
6013
+EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
6014
+
6015
+/**
6016
+ * devlink_port_health_reporter_destroy - destroy devlink port health reporter
6017
+ *
6018
+ * @reporter: devlink health reporter to destroy
6019
+ */
6020
+void
6021
+devlink_port_health_reporter_destroy(struct devlink_health_reporter *reporter)
6022
+{
6023
+ struct mutex *lock = &reporter->devlink_port->reporters_lock;
6024
+
6025
+ mutex_lock(lock);
6026
+ __devlink_health_reporter_destroy(reporter);
6027
+ mutex_unlock(lock);
6028
+}
6029
+EXPORT_SYMBOL_GPL(devlink_port_health_reporter_destroy);
6030
+
6031
+static int
6032
+devlink_nl_health_reporter_fill(struct sk_buff *msg,
6033
+ struct devlink *devlink,
6034
+ struct devlink_health_reporter *reporter,
6035
+ enum devlink_command cmd, u32 portid,
6036
+ u32 seq, int flags)
6037
+{
6038
+ struct nlattr *reporter_attr;
6039
+ void *hdr;
6040
+
6041
+ hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6042
+ if (!hdr)
6043
+ return -EMSGSIZE;
6044
+
6045
+ if (devlink_nl_put_handle(msg, devlink))
6046
+ goto genlmsg_cancel;
6047
+
6048
+ if (reporter->devlink_port) {
6049
+ if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, reporter->devlink_port->index))
6050
+ goto genlmsg_cancel;
6051
+ }
6052
+ reporter_attr = nla_nest_start_noflag(msg,
6053
+ DEVLINK_ATTR_HEALTH_REPORTER);
6054
+ if (!reporter_attr)
6055
+ goto genlmsg_cancel;
6056
+ if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
6057
+ reporter->ops->name))
6058
+ goto reporter_nest_cancel;
6059
+ if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
6060
+ reporter->health_state))
6061
+ goto reporter_nest_cancel;
6062
+ if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
6063
+ reporter->error_count, DEVLINK_ATTR_PAD))
6064
+ goto reporter_nest_cancel;
6065
+ if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
6066
+ reporter->recovery_count, DEVLINK_ATTR_PAD))
6067
+ goto reporter_nest_cancel;
6068
+ if (reporter->ops->recover &&
6069
+ nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
6070
+ reporter->graceful_period,
6071
+ DEVLINK_ATTR_PAD))
6072
+ goto reporter_nest_cancel;
6073
+ if (reporter->ops->recover &&
6074
+ nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
6075
+ reporter->auto_recover))
6076
+ goto reporter_nest_cancel;
6077
+ if (reporter->dump_fmsg &&
6078
+ nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
6079
+ jiffies_to_msecs(reporter->dump_ts),
6080
+ DEVLINK_ATTR_PAD))
6081
+ goto reporter_nest_cancel;
6082
+ if (reporter->dump_fmsg &&
6083
+ nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS,
6084
+ reporter->dump_real_ts, DEVLINK_ATTR_PAD))
6085
+ goto reporter_nest_cancel;
6086
+ if (reporter->ops->dump &&
6087
+ nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
6088
+ reporter->auto_dump))
6089
+ goto reporter_nest_cancel;
6090
+
6091
+ nla_nest_end(msg, reporter_attr);
6092
+ genlmsg_end(msg, hdr);
6093
+ return 0;
6094
+
6095
+reporter_nest_cancel:
6096
+ nla_nest_end(msg, reporter_attr);
6097
+genlmsg_cancel:
6098
+ genlmsg_cancel(msg, hdr);
6099
+ return -EMSGSIZE;
6100
+}
6101
+
6102
+static void devlink_recover_notify(struct devlink_health_reporter *reporter,
6103
+ enum devlink_command cmd)
6104
+{
6105
+ struct sk_buff *msg;
6106
+ int err;
6107
+
6108
+ WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
6109
+
6110
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6111
+ if (!msg)
6112
+ return;
6113
+
6114
+ err = devlink_nl_health_reporter_fill(msg, reporter->devlink,
6115
+ reporter, cmd, 0, 0, 0);
6116
+ if (err) {
6117
+ nlmsg_free(msg);
6118
+ return;
6119
+ }
6120
+
6121
+ genlmsg_multicast_netns(&devlink_nl_family,
6122
+ devlink_net(reporter->devlink),
6123
+ msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
6124
+}
6125
+
6126
+void
6127
+devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter)
6128
+{
6129
+ reporter->recovery_count++;
6130
+ reporter->last_recovery_ts = jiffies;
6131
+}
6132
+EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done);
6133
+
6134
+static int
6135
+devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
6136
+ void *priv_ctx, struct netlink_ext_ack *extack)
6137
+{
6138
+ int err;
6139
+
6140
+ if (reporter->health_state == DEVLINK_HEALTH_REPORTER_STATE_HEALTHY)
6141
+ return 0;
6142
+
6143
+ if (!reporter->ops->recover)
6144
+ return -EOPNOTSUPP;
6145
+
6146
+ err = reporter->ops->recover(reporter, priv_ctx, extack);
6147
+ if (err)
6148
+ return err;
6149
+
6150
+ devlink_health_reporter_recovery_done(reporter);
6151
+ reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
6152
+ devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
6153
+
6154
+ return 0;
6155
+}
6156
+
6157
+static void
6158
+devlink_health_dump_clear(struct devlink_health_reporter *reporter)
6159
+{
6160
+ if (!reporter->dump_fmsg)
6161
+ return;
6162
+ devlink_fmsg_free(reporter->dump_fmsg);
6163
+ reporter->dump_fmsg = NULL;
6164
+}
6165
+
6166
+static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
6167
+ void *priv_ctx,
6168
+ struct netlink_ext_ack *extack)
6169
+{
6170
+ int err;
6171
+
6172
+ if (!reporter->ops->dump)
6173
+ return 0;
6174
+
6175
+ if (reporter->dump_fmsg)
6176
+ return 0;
6177
+
6178
+ reporter->dump_fmsg = devlink_fmsg_alloc();
6179
+ if (!reporter->dump_fmsg) {
6180
+ err = -ENOMEM;
6181
+ return err;
6182
+ }
6183
+
6184
+ err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
6185
+ if (err)
6186
+ goto dump_err;
6187
+
6188
+ err = reporter->ops->dump(reporter, reporter->dump_fmsg,
6189
+ priv_ctx, extack);
6190
+ if (err)
6191
+ goto dump_err;
6192
+
6193
+ err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
6194
+ if (err)
6195
+ goto dump_err;
6196
+
6197
+ reporter->dump_ts = jiffies;
6198
+ reporter->dump_real_ts = ktime_get_real_ns();
6199
+
6200
+ return 0;
6201
+
6202
+dump_err:
6203
+ devlink_health_dump_clear(reporter);
6204
+ return err;
6205
+}
6206
+
6207
+int devlink_health_report(struct devlink_health_reporter *reporter,
6208
+ const char *msg, void *priv_ctx)
6209
+{
6210
+ enum devlink_health_reporter_state prev_health_state;
6211
+ struct devlink *devlink = reporter->devlink;
6212
+ unsigned long recover_ts_threshold;
6213
+
6214
+ /* write a log message of the current error */
6215
+ WARN_ON(!msg);
6216
+ trace_devlink_health_report(devlink, reporter->ops->name, msg);
6217
+ reporter->error_count++;
6218
+ prev_health_state = reporter->health_state;
6219
+ reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
6220
+ devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
6221
+
6222
+ /* abort if the previous error wasn't recovered */
6223
+ recover_ts_threshold = reporter->last_recovery_ts +
6224
+ msecs_to_jiffies(reporter->graceful_period);
6225
+ if (reporter->auto_recover &&
6226
+ (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
6227
+ (reporter->last_recovery_ts && reporter->recovery_count &&
6228
+ time_is_after_jiffies(recover_ts_threshold)))) {
6229
+ trace_devlink_health_recover_aborted(devlink,
6230
+ reporter->ops->name,
6231
+ reporter->health_state,
6232
+ jiffies -
6233
+ reporter->last_recovery_ts);
6234
+ return -ECANCELED;
6235
+ }
6236
+
6237
+ reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
6238
+
6239
+ if (reporter->auto_dump) {
6240
+ mutex_lock(&reporter->dump_lock);
6241
+ /* store current dump of current error, for later analysis */
6242
+ devlink_health_do_dump(reporter, priv_ctx, NULL);
6243
+ mutex_unlock(&reporter->dump_lock);
6244
+ }
6245
+
6246
+ if (reporter->auto_recover)
6247
+ return devlink_health_reporter_recover(reporter,
6248
+ priv_ctx, NULL);
6249
+
6250
+ return 0;
6251
+}
6252
+EXPORT_SYMBOL_GPL(devlink_health_report);
6253
+
6254
+static struct devlink_health_reporter *
6255
+devlink_health_reporter_get_from_attrs(struct devlink *devlink,
6256
+ struct nlattr **attrs)
6257
+{
6258
+ struct devlink_health_reporter *reporter;
6259
+ struct devlink_port *devlink_port;
6260
+ char *reporter_name;
6261
+
6262
+ if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
6263
+ return NULL;
6264
+
6265
+ reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
6266
+ devlink_port = devlink_port_get_from_attrs(devlink, attrs);
6267
+ if (IS_ERR(devlink_port)) {
6268
+ mutex_lock(&devlink->reporters_lock);
6269
+ reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
6270
+ if (reporter)
6271
+ refcount_inc(&reporter->refcount);
6272
+ mutex_unlock(&devlink->reporters_lock);
6273
+ } else {
6274
+ mutex_lock(&devlink_port->reporters_lock);
6275
+ reporter = devlink_port_health_reporter_find_by_name(devlink_port, reporter_name);
6276
+ if (reporter)
6277
+ refcount_inc(&reporter->refcount);
6278
+ mutex_unlock(&devlink_port->reporters_lock);
6279
+ }
6280
+
6281
+ return reporter;
6282
+}
6283
+
6284
+static struct devlink_health_reporter *
6285
+devlink_health_reporter_get_from_info(struct devlink *devlink,
6286
+ struct genl_info *info)
6287
+{
6288
+ return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
6289
+}
6290
+
6291
+static struct devlink_health_reporter *
6292
+devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
6293
+{
6294
+ const struct genl_dumpit_info *info = genl_dumpit_info(cb);
6295
+ struct devlink_health_reporter *reporter;
6296
+ struct nlattr **attrs = info->attrs;
6297
+ struct devlink *devlink;
6298
+
6299
+ mutex_lock(&devlink_mutex);
6300
+ devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
6301
+ if (IS_ERR(devlink))
6302
+ goto unlock;
6303
+
6304
+ reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
6305
+ mutex_unlock(&devlink_mutex);
6306
+ return reporter;
6307
+unlock:
6308
+ mutex_unlock(&devlink_mutex);
6309
+ return NULL;
6310
+}
6311
+
6312
+void
6313
+devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
6314
+ enum devlink_health_reporter_state state)
6315
+{
6316
+ if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
6317
+ state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
6318
+ return;
6319
+
6320
+ if (reporter->health_state == state)
6321
+ return;
6322
+
6323
+ reporter->health_state = state;
6324
+ trace_devlink_health_reporter_state_update(reporter->devlink,
6325
+ reporter->ops->name, state);
6326
+ devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
6327
+}
6328
+EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
6329
+
6330
+static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
6331
+ struct genl_info *info)
6332
+{
6333
+ struct devlink *devlink = info->user_ptr[0];
6334
+ struct devlink_health_reporter *reporter;
6335
+ struct sk_buff *msg;
6336
+ int err;
6337
+
6338
+ reporter = devlink_health_reporter_get_from_info(devlink, info);
6339
+ if (!reporter)
6340
+ return -EINVAL;
6341
+
6342
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6343
+ if (!msg) {
6344
+ err = -ENOMEM;
6345
+ goto out;
6346
+ }
6347
+
6348
+ err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
6349
+ DEVLINK_CMD_HEALTH_REPORTER_GET,
6350
+ info->snd_portid, info->snd_seq,
6351
+ 0);
6352
+ if (err) {
6353
+ nlmsg_free(msg);
6354
+ goto out;
6355
+ }
6356
+
6357
+ err = genlmsg_reply(msg, info);
6358
+out:
6359
+ devlink_health_reporter_put(reporter);
6360
+ return err;
6361
+}
6362
+
6363
+static int
6364
+devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
6365
+ struct netlink_callback *cb)
6366
+{
6367
+ struct devlink_health_reporter *reporter;
6368
+ struct devlink_port *port;
6369
+ struct devlink *devlink;
6370
+ int start = cb->args[0];
6371
+ int idx = 0;
6372
+ int err;
6373
+
6374
+ mutex_lock(&devlink_mutex);
6375
+ list_for_each_entry(devlink, &devlink_list, list) {
6376
+ if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6377
+ continue;
6378
+ mutex_lock(&devlink->reporters_lock);
6379
+ list_for_each_entry(reporter, &devlink->reporter_list,
6380
+ list) {
6381
+ if (idx < start) {
6382
+ idx++;
6383
+ continue;
6384
+ }
6385
+ err = devlink_nl_health_reporter_fill(msg, devlink,
6386
+ reporter,
6387
+ DEVLINK_CMD_HEALTH_REPORTER_GET,
6388
+ NETLINK_CB(cb->skb).portid,
6389
+ cb->nlh->nlmsg_seq,
6390
+ NLM_F_MULTI);
6391
+ if (err) {
6392
+ mutex_unlock(&devlink->reporters_lock);
6393
+ goto out;
6394
+ }
6395
+ idx++;
6396
+ }
6397
+ mutex_unlock(&devlink->reporters_lock);
6398
+ }
6399
+
6400
+ list_for_each_entry(devlink, &devlink_list, list) {
6401
+ if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6402
+ continue;
6403
+ mutex_lock(&devlink->lock);
6404
+ list_for_each_entry(port, &devlink->port_list, list) {
6405
+ mutex_lock(&port->reporters_lock);
6406
+ list_for_each_entry(reporter, &port->reporter_list, list) {
6407
+ if (idx < start) {
6408
+ idx++;
6409
+ continue;
6410
+ }
6411
+ err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
6412
+ DEVLINK_CMD_HEALTH_REPORTER_GET,
6413
+ NETLINK_CB(cb->skb).portid,
6414
+ cb->nlh->nlmsg_seq,
6415
+ NLM_F_MULTI);
6416
+ if (err) {
6417
+ mutex_unlock(&port->reporters_lock);
6418
+ mutex_unlock(&devlink->lock);
6419
+ goto out;
6420
+ }
6421
+ idx++;
6422
+ }
6423
+ mutex_unlock(&port->reporters_lock);
6424
+ }
6425
+ mutex_unlock(&devlink->lock);
6426
+ }
6427
+out:
6428
+ mutex_unlock(&devlink_mutex);
6429
+
6430
+ cb->args[0] = idx;
6431
+ return msg->len;
6432
+}
6433
+
6434
+static int
6435
+devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
6436
+ struct genl_info *info)
6437
+{
6438
+ struct devlink *devlink = info->user_ptr[0];
6439
+ struct devlink_health_reporter *reporter;
6440
+ int err;
6441
+
6442
+ reporter = devlink_health_reporter_get_from_info(devlink, info);
6443
+ if (!reporter)
6444
+ return -EINVAL;
6445
+
6446
+ if (!reporter->ops->recover &&
6447
+ (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
6448
+ info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) {
6449
+ err = -EOPNOTSUPP;
6450
+ goto out;
6451
+ }
6452
+ if (!reporter->ops->dump &&
6453
+ info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]) {
6454
+ err = -EOPNOTSUPP;
6455
+ goto out;
6456
+ }
6457
+
6458
+ if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
6459
+ reporter->graceful_period =
6460
+ nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
6461
+
6462
+ if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
6463
+ reporter->auto_recover =
6464
+ nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
6465
+
6466
+ if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
6467
+ reporter->auto_dump =
6468
+ nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]);
6469
+
6470
+ devlink_health_reporter_put(reporter);
6471
+ return 0;
6472
+out:
6473
+ devlink_health_reporter_put(reporter);
6474
+ return err;
6475
+}
6476
+
6477
+static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
6478
+ struct genl_info *info)
6479
+{
6480
+ struct devlink *devlink = info->user_ptr[0];
6481
+ struct devlink_health_reporter *reporter;
6482
+ int err;
6483
+
6484
+ reporter = devlink_health_reporter_get_from_info(devlink, info);
6485
+ if (!reporter)
6486
+ return -EINVAL;
6487
+
6488
+ err = devlink_health_reporter_recover(reporter, NULL, info->extack);
6489
+
6490
+ devlink_health_reporter_put(reporter);
6491
+ return err;
6492
+}
6493
+
6494
+static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
6495
+ struct genl_info *info)
6496
+{
6497
+ struct devlink *devlink = info->user_ptr[0];
6498
+ struct devlink_health_reporter *reporter;
6499
+ struct devlink_fmsg *fmsg;
6500
+ int err;
6501
+
6502
+ reporter = devlink_health_reporter_get_from_info(devlink, info);
6503
+ if (!reporter)
6504
+ return -EINVAL;
6505
+
6506
+ if (!reporter->ops->diagnose) {
6507
+ devlink_health_reporter_put(reporter);
6508
+ return -EOPNOTSUPP;
6509
+ }
6510
+
6511
+ fmsg = devlink_fmsg_alloc();
6512
+ if (!fmsg) {
6513
+ devlink_health_reporter_put(reporter);
6514
+ return -ENOMEM;
6515
+ }
6516
+
6517
+ err = devlink_fmsg_obj_nest_start(fmsg);
6518
+ if (err)
6519
+ goto out;
6520
+
6521
+ err = reporter->ops->diagnose(reporter, fmsg, info->extack);
6522
+ if (err)
6523
+ goto out;
6524
+
6525
+ err = devlink_fmsg_obj_nest_end(fmsg);
6526
+ if (err)
6527
+ goto out;
6528
+
6529
+ err = devlink_fmsg_snd(fmsg, info,
6530
+ DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
6531
+
6532
+out:
6533
+ devlink_fmsg_free(fmsg);
6534
+ devlink_health_reporter_put(reporter);
6535
+ return err;
6536
+}
6537
+
6538
+static int
6539
+devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
6540
+ struct netlink_callback *cb)
6541
+{
6542
+ struct devlink_health_reporter *reporter;
6543
+ u64 start = cb->args[0];
6544
+ int err;
6545
+
6546
+ reporter = devlink_health_reporter_get_from_cb(cb);
6547
+ if (!reporter)
6548
+ return -EINVAL;
6549
+
6550
+ if (!reporter->ops->dump) {
6551
+ err = -EOPNOTSUPP;
6552
+ goto out;
6553
+ }
6554
+ mutex_lock(&reporter->dump_lock);
6555
+ if (!start) {
6556
+ err = devlink_health_do_dump(reporter, NULL, cb->extack);
6557
+ if (err)
6558
+ goto unlock;
6559
+ cb->args[1] = reporter->dump_ts;
6560
+ }
6561
+ if (!reporter->dump_fmsg || cb->args[1] != reporter->dump_ts) {
6562
+ NL_SET_ERR_MSG_MOD(cb->extack, "Dump trampled, please retry");
6563
+ err = -EAGAIN;
6564
+ goto unlock;
6565
+ }
6566
+
6567
+ err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
6568
+ DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
6569
+unlock:
6570
+ mutex_unlock(&reporter->dump_lock);
6571
+out:
6572
+ devlink_health_reporter_put(reporter);
6573
+ return err;
6574
+}
6575
+
6576
+static int
6577
+devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
6578
+ struct genl_info *info)
6579
+{
6580
+ struct devlink *devlink = info->user_ptr[0];
6581
+ struct devlink_health_reporter *reporter;
6582
+
6583
+ reporter = devlink_health_reporter_get_from_info(devlink, info);
6584
+ if (!reporter)
6585
+ return -EINVAL;
6586
+
6587
+ if (!reporter->ops->dump) {
6588
+ devlink_health_reporter_put(reporter);
6589
+ return -EOPNOTSUPP;
6590
+ }
6591
+
6592
+ mutex_lock(&reporter->dump_lock);
6593
+ devlink_health_dump_clear(reporter);
6594
+ mutex_unlock(&reporter->dump_lock);
6595
+ devlink_health_reporter_put(reporter);
6596
+ return 0;
6597
+}
6598
+
6599
+static int devlink_nl_cmd_health_reporter_test_doit(struct sk_buff *skb,
6600
+ struct genl_info *info)
6601
+{
6602
+ struct devlink *devlink = info->user_ptr[0];
6603
+ struct devlink_health_reporter *reporter;
6604
+ int err;
6605
+
6606
+ reporter = devlink_health_reporter_get_from_info(devlink, info);
6607
+ if (!reporter)
6608
+ return -EINVAL;
6609
+
6610
+ if (!reporter->ops->test) {
6611
+ devlink_health_reporter_put(reporter);
6612
+ return -EOPNOTSUPP;
6613
+ }
6614
+
6615
+ err = reporter->ops->test(reporter, info->extack);
6616
+
6617
+ devlink_health_reporter_put(reporter);
6618
+ return err;
6619
+}
6620
+
6621
+struct devlink_stats {
6622
+ u64 rx_bytes;
6623
+ u64 rx_packets;
6624
+ struct u64_stats_sync syncp;
6625
+};
6626
+
6627
+/**
6628
+ * struct devlink_trap_policer_item - Packet trap policer attributes.
6629
+ * @policer: Immutable packet trap policer attributes.
6630
+ * @rate: Rate in packets / sec.
6631
+ * @burst: Burst size in packets.
6632
+ * @list: trap_policer_list member.
6633
+ *
6634
+ * Describes packet trap policer attributes. Created by devlink during trap
6635
+ * policer registration.
6636
+ */
6637
+struct devlink_trap_policer_item {
6638
+ const struct devlink_trap_policer *policer;
6639
+ u64 rate;
6640
+ u64 burst;
6641
+ struct list_head list;
6642
+};
6643
+
6644
+/**
6645
+ * struct devlink_trap_group_item - Packet trap group attributes.
6646
+ * @group: Immutable packet trap group attributes.
6647
+ * @policer_item: Associated policer item. Can be NULL.
6648
+ * @list: trap_group_list member.
6649
+ * @stats: Trap group statistics.
6650
+ *
6651
+ * Describes packet trap group attributes. Created by devlink during trap
6652
+ * group registration.
6653
+ */
6654
+struct devlink_trap_group_item {
6655
+ const struct devlink_trap_group *group;
6656
+ struct devlink_trap_policer_item *policer_item;
6657
+ struct list_head list;
6658
+ struct devlink_stats __percpu *stats;
6659
+};
6660
+
6661
+/**
6662
+ * struct devlink_trap_item - Packet trap attributes.
6663
+ * @trap: Immutable packet trap attributes.
6664
+ * @group_item: Associated group item.
6665
+ * @list: trap_list member.
6666
+ * @action: Trap action.
6667
+ * @stats: Trap statistics.
6668
+ * @priv: Driver private information.
6669
+ *
6670
+ * Describes both mutable and immutable packet trap attributes. Created by
6671
+ * devlink during trap registration and used for all trap related operations.
6672
+ */
6673
+struct devlink_trap_item {
6674
+ const struct devlink_trap *trap;
6675
+ struct devlink_trap_group_item *group_item;
6676
+ struct list_head list;
6677
+ enum devlink_trap_action action;
6678
+ struct devlink_stats __percpu *stats;
6679
+ void *priv;
6680
+};
6681
+
6682
+static struct devlink_trap_policer_item *
6683
+devlink_trap_policer_item_lookup(struct devlink *devlink, u32 id)
6684
+{
6685
+ struct devlink_trap_policer_item *policer_item;
6686
+
6687
+ list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
6688
+ if (policer_item->policer->id == id)
6689
+ return policer_item;
6690
+ }
6691
+
6692
+ return NULL;
6693
+}
6694
+
6695
+static struct devlink_trap_item *
6696
+devlink_trap_item_lookup(struct devlink *devlink, const char *name)
6697
+{
6698
+ struct devlink_trap_item *trap_item;
6699
+
6700
+ list_for_each_entry(trap_item, &devlink->trap_list, list) {
6701
+ if (!strcmp(trap_item->trap->name, name))
6702
+ return trap_item;
6703
+ }
6704
+
6705
+ return NULL;
6706
+}
6707
+
6708
+static struct devlink_trap_item *
6709
+devlink_trap_item_get_from_info(struct devlink *devlink,
6710
+ struct genl_info *info)
6711
+{
6712
+ struct nlattr *attr;
6713
+
6714
+ if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
6715
+ return NULL;
6716
+ attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
6717
+
6718
+ return devlink_trap_item_lookup(devlink, nla_data(attr));
6719
+}
6720
+
6721
+static int
6722
+devlink_trap_action_get_from_info(struct genl_info *info,
6723
+ enum devlink_trap_action *p_trap_action)
6724
+{
6725
+ u8 val;
6726
+
6727
+ val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
6728
+ switch (val) {
6729
+ case DEVLINK_TRAP_ACTION_DROP:
6730
+ case DEVLINK_TRAP_ACTION_TRAP:
6731
+ case DEVLINK_TRAP_ACTION_MIRROR:
6732
+ *p_trap_action = val;
6733
+ break;
6734
+ default:
6735
+ return -EINVAL;
6736
+ }
6737
+
6738
+ return 0;
6739
+}
6740
+
6741
+static int devlink_trap_metadata_put(struct sk_buff *msg,
6742
+ const struct devlink_trap *trap)
6743
+{
6744
+ struct nlattr *attr;
6745
+
6746
+ attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
6747
+ if (!attr)
6748
+ return -EMSGSIZE;
6749
+
6750
+ if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
6751
+ nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
6752
+ goto nla_put_failure;
6753
+ if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE) &&
6754
+ nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE))
6755
+ goto nla_put_failure;
6756
+
6757
+ nla_nest_end(msg, attr);
6758
+
6759
+ return 0;
6760
+
6761
+nla_put_failure:
6762
+ nla_nest_cancel(msg, attr);
6763
+ return -EMSGSIZE;
6764
+}
6765
+
6766
+static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
6767
+ struct devlink_stats *stats)
6768
+{
6769
+ int i;
6770
+
6771
+ memset(stats, 0, sizeof(*stats));
6772
+ for_each_possible_cpu(i) {
6773
+ struct devlink_stats *cpu_stats;
6774
+ u64 rx_packets, rx_bytes;
6775
+ unsigned int start;
6776
+
6777
+ cpu_stats = per_cpu_ptr(trap_stats, i);
6778
+ do {
6779
+ start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
6780
+ rx_packets = cpu_stats->rx_packets;
6781
+ rx_bytes = cpu_stats->rx_bytes;
6782
+ } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
6783
+
6784
+ stats->rx_packets += rx_packets;
6785
+ stats->rx_bytes += rx_bytes;
6786
+ }
6787
+}
6788
+
6789
+static int devlink_trap_stats_put(struct sk_buff *msg,
6790
+ struct devlink_stats __percpu *trap_stats)
6791
+{
6792
+ struct devlink_stats stats;
6793
+ struct nlattr *attr;
6794
+
6795
+ devlink_trap_stats_read(trap_stats, &stats);
6796
+
6797
+ attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
6798
+ if (!attr)
6799
+ return -EMSGSIZE;
6800
+
6801
+ if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
6802
+ stats.rx_packets, DEVLINK_ATTR_PAD))
6803
+ goto nla_put_failure;
6804
+
6805
+ if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
6806
+ stats.rx_bytes, DEVLINK_ATTR_PAD))
6807
+ goto nla_put_failure;
6808
+
6809
+ nla_nest_end(msg, attr);
6810
+
6811
+ return 0;
6812
+
6813
+nla_put_failure:
6814
+ nla_nest_cancel(msg, attr);
6815
+ return -EMSGSIZE;
6816
+}
6817
+
6818
+static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
6819
+ const struct devlink_trap_item *trap_item,
6820
+ enum devlink_command cmd, u32 portid, u32 seq,
6821
+ int flags)
6822
+{
6823
+ struct devlink_trap_group_item *group_item = trap_item->group_item;
6824
+ void *hdr;
6825
+ int err;
6826
+
6827
+ hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6828
+ if (!hdr)
6829
+ return -EMSGSIZE;
6830
+
6831
+ if (devlink_nl_put_handle(msg, devlink))
6832
+ goto nla_put_failure;
6833
+
6834
+ if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
6835
+ group_item->group->name))
6836
+ goto nla_put_failure;
6837
+
6838
+ if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
6839
+ goto nla_put_failure;
6840
+
6841
+ if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
6842
+ goto nla_put_failure;
6843
+
6844
+ if (trap_item->trap->generic &&
6845
+ nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
6846
+ goto nla_put_failure;
6847
+
6848
+ if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
6849
+ goto nla_put_failure;
6850
+
6851
+ err = devlink_trap_metadata_put(msg, trap_item->trap);
6852
+ if (err)
6853
+ goto nla_put_failure;
6854
+
6855
+ err = devlink_trap_stats_put(msg, trap_item->stats);
6856
+ if (err)
6857
+ goto nla_put_failure;
6858
+
6859
+ genlmsg_end(msg, hdr);
6860
+
6861
+ return 0;
6862
+
6863
+nla_put_failure:
6864
+ genlmsg_cancel(msg, hdr);
6865
+ return -EMSGSIZE;
6866
+}
6867
+
6868
+static int devlink_nl_cmd_trap_get_doit(struct sk_buff *skb,
6869
+ struct genl_info *info)
6870
+{
6871
+ struct netlink_ext_ack *extack = info->extack;
6872
+ struct devlink *devlink = info->user_ptr[0];
6873
+ struct devlink_trap_item *trap_item;
6874
+ struct sk_buff *msg;
6875
+ int err;
6876
+
6877
+ if (list_empty(&devlink->trap_list))
6878
+ return -EOPNOTSUPP;
6879
+
6880
+ trap_item = devlink_trap_item_get_from_info(devlink, info);
6881
+ if (!trap_item) {
6882
+ NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
6883
+ return -ENOENT;
6884
+ }
6885
+
6886
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6887
+ if (!msg)
6888
+ return -ENOMEM;
6889
+
6890
+ err = devlink_nl_trap_fill(msg, devlink, trap_item,
6891
+ DEVLINK_CMD_TRAP_NEW, info->snd_portid,
6892
+ info->snd_seq, 0);
6893
+ if (err)
6894
+ goto err_trap_fill;
6895
+
6896
+ return genlmsg_reply(msg, info);
6897
+
6898
+err_trap_fill:
6899
+ nlmsg_free(msg);
6900
+ return err;
6901
+}
6902
+
6903
+static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg,
6904
+ struct netlink_callback *cb)
6905
+{
6906
+ struct devlink_trap_item *trap_item;
6907
+ struct devlink *devlink;
6908
+ int start = cb->args[0];
6909
+ int idx = 0;
6910
+ int err;
6911
+
6912
+ mutex_lock(&devlink_mutex);
6913
+ list_for_each_entry(devlink, &devlink_list, list) {
6914
+ if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6915
+ continue;
6916
+ mutex_lock(&devlink->lock);
6917
+ list_for_each_entry(trap_item, &devlink->trap_list, list) {
6918
+ if (idx < start) {
6919
+ idx++;
6920
+ continue;
6921
+ }
6922
+ err = devlink_nl_trap_fill(msg, devlink, trap_item,
6923
+ DEVLINK_CMD_TRAP_NEW,
6924
+ NETLINK_CB(cb->skb).portid,
6925
+ cb->nlh->nlmsg_seq,
6926
+ NLM_F_MULTI);
6927
+ if (err) {
6928
+ mutex_unlock(&devlink->lock);
6929
+ goto out;
6930
+ }
6931
+ idx++;
6932
+ }
6933
+ mutex_unlock(&devlink->lock);
6934
+ }
6935
+out:
6936
+ mutex_unlock(&devlink_mutex);
6937
+
6938
+ cb->args[0] = idx;
6939
+ return msg->len;
6940
+}
6941
+
6942
+static int __devlink_trap_action_set(struct devlink *devlink,
6943
+ struct devlink_trap_item *trap_item,
6944
+ enum devlink_trap_action trap_action,
6945
+ struct netlink_ext_ack *extack)
6946
+{
6947
+ int err;
6948
+
6949
+ if (trap_item->action != trap_action &&
6950
+ trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
6951
+ NL_SET_ERR_MSG_MOD(extack, "Cannot change action of non-drop traps. Skipping");
6952
+ return 0;
6953
+ }
6954
+
6955
+ err = devlink->ops->trap_action_set(devlink, trap_item->trap,
6956
+ trap_action, extack);
6957
+ if (err)
6958
+ return err;
6959
+
6960
+ trap_item->action = trap_action;
6961
+
6962
+ return 0;
6963
+}
6964
+
6965
+static int devlink_trap_action_set(struct devlink *devlink,
6966
+ struct devlink_trap_item *trap_item,
6967
+ struct genl_info *info)
6968
+{
6969
+ enum devlink_trap_action trap_action;
6970
+ int err;
6971
+
6972
+ if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
6973
+ return 0;
6974
+
6975
+ err = devlink_trap_action_get_from_info(info, &trap_action);
6976
+ if (err) {
6977
+ NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
6978
+ return -EINVAL;
6979
+ }
6980
+
6981
+ return __devlink_trap_action_set(devlink, trap_item, trap_action,
6982
+ info->extack);
6983
+}
6984
+
6985
+static int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb,
6986
+ struct genl_info *info)
6987
+{
6988
+ struct netlink_ext_ack *extack = info->extack;
6989
+ struct devlink *devlink = info->user_ptr[0];
6990
+ struct devlink_trap_item *trap_item;
6991
+ int err;
6992
+
6993
+ if (list_empty(&devlink->trap_list))
6994
+ return -EOPNOTSUPP;
6995
+
6996
+ trap_item = devlink_trap_item_get_from_info(devlink, info);
6997
+ if (!trap_item) {
6998
+ NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
6999
+ return -ENOENT;
7000
+ }
7001
+
7002
+ err = devlink_trap_action_set(devlink, trap_item, info);
7003
+ if (err)
7004
+ return err;
7005
+
7006
+ return 0;
7007
+}
7008
+
7009
+static struct devlink_trap_group_item *
7010
+devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
7011
+{
7012
+ struct devlink_trap_group_item *group_item;
7013
+
7014
+ list_for_each_entry(group_item, &devlink->trap_group_list, list) {
7015
+ if (!strcmp(group_item->group->name, name))
7016
+ return group_item;
7017
+ }
7018
+
7019
+ return NULL;
7020
+}
7021
+
7022
+static struct devlink_trap_group_item *
7023
+devlink_trap_group_item_lookup_by_id(struct devlink *devlink, u16 id)
7024
+{
7025
+ struct devlink_trap_group_item *group_item;
7026
+
7027
+ list_for_each_entry(group_item, &devlink->trap_group_list, list) {
7028
+ if (group_item->group->id == id)
7029
+ return group_item;
7030
+ }
7031
+
7032
+ return NULL;
7033
+}
7034
+
7035
+static struct devlink_trap_group_item *
7036
+devlink_trap_group_item_get_from_info(struct devlink *devlink,
7037
+ struct genl_info *info)
7038
+{
7039
+ char *name;
7040
+
7041
+ if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
7042
+ return NULL;
7043
+ name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
7044
+
7045
+ return devlink_trap_group_item_lookup(devlink, name);
7046
+}
7047
+
7048
+static int
7049
+devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
7050
+ const struct devlink_trap_group_item *group_item,
7051
+ enum devlink_command cmd, u32 portid, u32 seq,
7052
+ int flags)
7053
+{
7054
+ void *hdr;
7055
+ int err;
7056
+
7057
+ hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
7058
+ if (!hdr)
7059
+ return -EMSGSIZE;
7060
+
7061
+ if (devlink_nl_put_handle(msg, devlink))
7062
+ goto nla_put_failure;
7063
+
7064
+ if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
7065
+ group_item->group->name))
7066
+ goto nla_put_failure;
7067
+
7068
+ if (group_item->group->generic &&
7069
+ nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
7070
+ goto nla_put_failure;
7071
+
7072
+ if (group_item->policer_item &&
7073
+ nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
7074
+ group_item->policer_item->policer->id))
7075
+ goto nla_put_failure;
7076
+
7077
+ err = devlink_trap_stats_put(msg, group_item->stats);
7078
+ if (err)
7079
+ goto nla_put_failure;
7080
+
7081
+ genlmsg_end(msg, hdr);
7082
+
7083
+ return 0;
7084
+
7085
+nla_put_failure:
7086
+ genlmsg_cancel(msg, hdr);
7087
+ return -EMSGSIZE;
7088
+}
7089
+
7090
+static int devlink_nl_cmd_trap_group_get_doit(struct sk_buff *skb,
7091
+ struct genl_info *info)
7092
+{
7093
+ struct netlink_ext_ack *extack = info->extack;
7094
+ struct devlink *devlink = info->user_ptr[0];
7095
+ struct devlink_trap_group_item *group_item;
7096
+ struct sk_buff *msg;
7097
+ int err;
7098
+
7099
+ if (list_empty(&devlink->trap_group_list))
7100
+ return -EOPNOTSUPP;
7101
+
7102
+ group_item = devlink_trap_group_item_get_from_info(devlink, info);
7103
+ if (!group_item) {
7104
+ NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
7105
+ return -ENOENT;
7106
+ }
7107
+
7108
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7109
+ if (!msg)
7110
+ return -ENOMEM;
7111
+
7112
+ err = devlink_nl_trap_group_fill(msg, devlink, group_item,
7113
+ DEVLINK_CMD_TRAP_GROUP_NEW,
7114
+ info->snd_portid, info->snd_seq, 0);
7115
+ if (err)
7116
+ goto err_trap_group_fill;
7117
+
7118
+ return genlmsg_reply(msg, info);
7119
+
7120
+err_trap_group_fill:
7121
+ nlmsg_free(msg);
7122
+ return err;
7123
+}
7124
+
7125
+static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg,
7126
+ struct netlink_callback *cb)
7127
+{
7128
+ enum devlink_command cmd = DEVLINK_CMD_TRAP_GROUP_NEW;
7129
+ struct devlink_trap_group_item *group_item;
7130
+ u32 portid = NETLINK_CB(cb->skb).portid;
7131
+ struct devlink *devlink;
7132
+ int start = cb->args[0];
7133
+ int idx = 0;
7134
+ int err;
7135
+
7136
+ mutex_lock(&devlink_mutex);
7137
+ list_for_each_entry(devlink, &devlink_list, list) {
7138
+ if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
7139
+ continue;
7140
+ mutex_lock(&devlink->lock);
7141
+ list_for_each_entry(group_item, &devlink->trap_group_list,
7142
+ list) {
7143
+ if (idx < start) {
7144
+ idx++;
7145
+ continue;
7146
+ }
7147
+ err = devlink_nl_trap_group_fill(msg, devlink,
7148
+ group_item, cmd,
7149
+ portid,
7150
+ cb->nlh->nlmsg_seq,
7151
+ NLM_F_MULTI);
7152
+ if (err) {
7153
+ mutex_unlock(&devlink->lock);
7154
+ goto out;
7155
+ }
7156
+ idx++;
7157
+ }
7158
+ mutex_unlock(&devlink->lock);
7159
+ }
7160
+out:
7161
+ mutex_unlock(&devlink_mutex);
7162
+
7163
+ cb->args[0] = idx;
7164
+ return msg->len;
7165
+}
7166
+
7167
+static int
7168
+__devlink_trap_group_action_set(struct devlink *devlink,
7169
+ struct devlink_trap_group_item *group_item,
7170
+ enum devlink_trap_action trap_action,
7171
+ struct netlink_ext_ack *extack)
7172
+{
7173
+ const char *group_name = group_item->group->name;
7174
+ struct devlink_trap_item *trap_item;
7175
+ int err;
7176
+
7177
+ if (devlink->ops->trap_group_action_set) {
7178
+ err = devlink->ops->trap_group_action_set(devlink, group_item->group,
7179
+ trap_action, extack);
7180
+ if (err)
7181
+ return err;
7182
+
7183
+ list_for_each_entry(trap_item, &devlink->trap_list, list) {
7184
+ if (strcmp(trap_item->group_item->group->name, group_name))
7185
+ continue;
7186
+ if (trap_item->action != trap_action &&
7187
+ trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP)
7188
+ continue;
7189
+ trap_item->action = trap_action;
7190
+ }
7191
+
7192
+ return 0;
7193
+ }
7194
+
7195
+ list_for_each_entry(trap_item, &devlink->trap_list, list) {
7196
+ if (strcmp(trap_item->group_item->group->name, group_name))
7197
+ continue;
7198
+ err = __devlink_trap_action_set(devlink, trap_item,
7199
+ trap_action, extack);
7200
+ if (err)
7201
+ return err;
7202
+ }
7203
+
7204
+ return 0;
7205
+}
7206
+
7207
+static int
7208
+devlink_trap_group_action_set(struct devlink *devlink,
7209
+ struct devlink_trap_group_item *group_item,
7210
+ struct genl_info *info, bool *p_modified)
7211
+{
7212
+ enum devlink_trap_action trap_action;
7213
+ int err;
7214
+
7215
+ if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
7216
+ return 0;
7217
+
7218
+ err = devlink_trap_action_get_from_info(info, &trap_action);
7219
+ if (err) {
7220
+ NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
7221
+ return -EINVAL;
7222
+ }
7223
+
7224
+ err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
7225
+ info->extack);
7226
+ if (err)
7227
+ return err;
7228
+
7229
+ *p_modified = true;
7230
+
7231
+ return 0;
7232
+}
7233
+
7234
+static int devlink_trap_group_set(struct devlink *devlink,
7235
+ struct devlink_trap_group_item *group_item,
7236
+ struct genl_info *info)
7237
+{
7238
+ struct devlink_trap_policer_item *policer_item;
7239
+ struct netlink_ext_ack *extack = info->extack;
7240
+ const struct devlink_trap_policer *policer;
7241
+ struct nlattr **attrs = info->attrs;
7242
+ int err;
7243
+
7244
+ if (!attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
7245
+ return 0;
7246
+
7247
+ if (!devlink->ops->trap_group_set)
7248
+ return -EOPNOTSUPP;
7249
+
7250
+ policer_item = group_item->policer_item;
7251
+ if (attrs[DEVLINK_ATTR_TRAP_POLICER_ID]) {
7252
+ u32 policer_id;
7253
+
7254
+ policer_id = nla_get_u32(attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
7255
+ policer_item = devlink_trap_policer_item_lookup(devlink,
7256
+ policer_id);
7257
+ if (policer_id && !policer_item) {
7258
+ NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
7259
+ return -ENOENT;
7260
+ }
7261
+ }
7262
+ policer = policer_item ? policer_item->policer : NULL;
7263
+
7264
+ err = devlink->ops->trap_group_set(devlink, group_item->group, policer,
7265
+ extack);
7266
+ if (err)
7267
+ return err;
7268
+
7269
+ group_item->policer_item = policer_item;
7270
+
7271
+ return 0;
7272
+}
7273
+
7274
+static int devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb,
7275
+ struct genl_info *info)
7276
+{
7277
+ struct netlink_ext_ack *extack = info->extack;
7278
+ struct devlink *devlink = info->user_ptr[0];
7279
+ struct devlink_trap_group_item *group_item;
7280
+ bool modified = false;
7281
+ int err;
7282
+
7283
+ if (list_empty(&devlink->trap_group_list))
7284
+ return -EOPNOTSUPP;
7285
+
7286
+ group_item = devlink_trap_group_item_get_from_info(devlink, info);
7287
+ if (!group_item) {
7288
+ NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
7289
+ return -ENOENT;
7290
+ }
7291
+
7292
+ err = devlink_trap_group_action_set(devlink, group_item, info,
7293
+ &modified);
7294
+ if (err)
7295
+ return err;
7296
+
7297
+ err = devlink_trap_group_set(devlink, group_item, info);
7298
+ if (err)
7299
+ goto err_trap_group_set;
7300
+
7301
+ return 0;
7302
+
7303
+err_trap_group_set:
7304
+ if (modified)
7305
+ NL_SET_ERR_MSG_MOD(extack, "Trap group set failed, but some changes were committed already");
7306
+ return err;
7307
+}
7308
+
7309
+static struct devlink_trap_policer_item *
7310
+devlink_trap_policer_item_get_from_info(struct devlink *devlink,
7311
+ struct genl_info *info)
7312
+{
7313
+ u32 id;
7314
+
7315
+ if (!info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
7316
+ return NULL;
7317
+ id = nla_get_u32(info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
7318
+
7319
+ return devlink_trap_policer_item_lookup(devlink, id);
7320
+}
7321
+
7322
+static int
7323
+devlink_trap_policer_stats_put(struct sk_buff *msg, struct devlink *devlink,
7324
+ const struct devlink_trap_policer *policer)
7325
+{
7326
+ struct nlattr *attr;
7327
+ u64 drops;
7328
+ int err;
7329
+
7330
+ if (!devlink->ops->trap_policer_counter_get)
7331
+ return 0;
7332
+
7333
+ err = devlink->ops->trap_policer_counter_get(devlink, policer, &drops);
7334
+ if (err)
7335
+ return err;
7336
+
7337
+ attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
7338
+ if (!attr)
7339
+ return -EMSGSIZE;
7340
+
7341
+ if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops,
7342
+ DEVLINK_ATTR_PAD))
7343
+ goto nla_put_failure;
7344
+
7345
+ nla_nest_end(msg, attr);
7346
+
7347
+ return 0;
7348
+
7349
+nla_put_failure:
7350
+ nla_nest_cancel(msg, attr);
7351
+ return -EMSGSIZE;
7352
+}
7353
+
7354
+static int
7355
+devlink_nl_trap_policer_fill(struct sk_buff *msg, struct devlink *devlink,
7356
+ const struct devlink_trap_policer_item *policer_item,
7357
+ enum devlink_command cmd, u32 portid, u32 seq,
7358
+ int flags)
7359
+{
7360
+ void *hdr;
7361
+ int err;
7362
+
7363
+ hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
7364
+ if (!hdr)
7365
+ return -EMSGSIZE;
7366
+
7367
+ if (devlink_nl_put_handle(msg, devlink))
7368
+ goto nla_put_failure;
7369
+
7370
+ if (nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
7371
+ policer_item->policer->id))
7372
+ goto nla_put_failure;
7373
+
7374
+ if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_RATE,
7375
+ policer_item->rate, DEVLINK_ATTR_PAD))
7376
+ goto nla_put_failure;
7377
+
7378
+ if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_BURST,
7379
+ policer_item->burst, DEVLINK_ATTR_PAD))
7380
+ goto nla_put_failure;
7381
+
7382
+ err = devlink_trap_policer_stats_put(msg, devlink,
7383
+ policer_item->policer);
7384
+ if (err)
7385
+ goto nla_put_failure;
7386
+
7387
+ genlmsg_end(msg, hdr);
7388
+
7389
+ return 0;
7390
+
7391
+nla_put_failure:
7392
+ genlmsg_cancel(msg, hdr);
7393
+ return -EMSGSIZE;
7394
+}
7395
+
7396
+static int devlink_nl_cmd_trap_policer_get_doit(struct sk_buff *skb,
7397
+ struct genl_info *info)
7398
+{
7399
+ struct devlink_trap_policer_item *policer_item;
7400
+ struct netlink_ext_ack *extack = info->extack;
7401
+ struct devlink *devlink = info->user_ptr[0];
7402
+ struct sk_buff *msg;
7403
+ int err;
7404
+
7405
+ if (list_empty(&devlink->trap_policer_list))
7406
+ return -EOPNOTSUPP;
7407
+
7408
+ policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
7409
+ if (!policer_item) {
7410
+ NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
7411
+ return -ENOENT;
7412
+ }
7413
+
7414
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7415
+ if (!msg)
7416
+ return -ENOMEM;
7417
+
7418
+ err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
7419
+ DEVLINK_CMD_TRAP_POLICER_NEW,
7420
+ info->snd_portid, info->snd_seq, 0);
7421
+ if (err)
7422
+ goto err_trap_policer_fill;
7423
+
7424
+ return genlmsg_reply(msg, info);
7425
+
7426
+err_trap_policer_fill:
7427
+ nlmsg_free(msg);
7428
+ return err;
7429
+}
7430
+
7431
+static int devlink_nl_cmd_trap_policer_get_dumpit(struct sk_buff *msg,
7432
+ struct netlink_callback *cb)
7433
+{
7434
+ enum devlink_command cmd = DEVLINK_CMD_TRAP_POLICER_NEW;
7435
+ struct devlink_trap_policer_item *policer_item;
7436
+ u32 portid = NETLINK_CB(cb->skb).portid;
7437
+ struct devlink *devlink;
7438
+ int start = cb->args[0];
7439
+ int idx = 0;
7440
+ int err;
7441
+
7442
+ mutex_lock(&devlink_mutex);
7443
+ list_for_each_entry(devlink, &devlink_list, list) {
7444
+ if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
7445
+ continue;
7446
+ mutex_lock(&devlink->lock);
7447
+ list_for_each_entry(policer_item, &devlink->trap_policer_list,
7448
+ list) {
7449
+ if (idx < start) {
7450
+ idx++;
7451
+ continue;
7452
+ }
7453
+ err = devlink_nl_trap_policer_fill(msg, devlink,
7454
+ policer_item, cmd,
7455
+ portid,
7456
+ cb->nlh->nlmsg_seq,
7457
+ NLM_F_MULTI);
7458
+ if (err) {
7459
+ mutex_unlock(&devlink->lock);
7460
+ goto out;
7461
+ }
7462
+ idx++;
7463
+ }
7464
+ mutex_unlock(&devlink->lock);
7465
+ }
7466
+out:
7467
+ mutex_unlock(&devlink_mutex);
7468
+
7469
+ cb->args[0] = idx;
7470
+ return msg->len;
7471
+}
7472
+
7473
+static int
7474
+devlink_trap_policer_set(struct devlink *devlink,
7475
+ struct devlink_trap_policer_item *policer_item,
7476
+ struct genl_info *info)
7477
+{
7478
+ struct netlink_ext_ack *extack = info->extack;
7479
+ struct nlattr **attrs = info->attrs;
7480
+ u64 rate, burst;
7481
+ int err;
7482
+
7483
+ rate = policer_item->rate;
7484
+ burst = policer_item->burst;
7485
+
7486
+ if (attrs[DEVLINK_ATTR_TRAP_POLICER_RATE])
7487
+ rate = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]);
7488
+
7489
+ if (attrs[DEVLINK_ATTR_TRAP_POLICER_BURST])
7490
+ burst = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]);
7491
+
7492
+ if (rate < policer_item->policer->min_rate) {
7493
+ NL_SET_ERR_MSG_MOD(extack, "Policer rate lower than limit");
7494
+ return -EINVAL;
7495
+ }
7496
+
7497
+ if (rate > policer_item->policer->max_rate) {
7498
+ NL_SET_ERR_MSG_MOD(extack, "Policer rate higher than limit");
7499
+ return -EINVAL;
7500
+ }
7501
+
7502
+ if (burst < policer_item->policer->min_burst) {
7503
+ NL_SET_ERR_MSG_MOD(extack, "Policer burst size lower than limit");
7504
+ return -EINVAL;
7505
+ }
7506
+
7507
+ if (burst > policer_item->policer->max_burst) {
7508
+ NL_SET_ERR_MSG_MOD(extack, "Policer burst size higher than limit");
7509
+ return -EINVAL;
7510
+ }
7511
+
7512
+ err = devlink->ops->trap_policer_set(devlink, policer_item->policer,
7513
+ rate, burst, info->extack);
7514
+ if (err)
7515
+ return err;
7516
+
7517
+ policer_item->rate = rate;
7518
+ policer_item->burst = burst;
7519
+
7520
+ return 0;
7521
+}
7522
+
7523
+static int devlink_nl_cmd_trap_policer_set_doit(struct sk_buff *skb,
7524
+ struct genl_info *info)
7525
+{
7526
+ struct devlink_trap_policer_item *policer_item;
7527
+ struct netlink_ext_ack *extack = info->extack;
7528
+ struct devlink *devlink = info->user_ptr[0];
7529
+
7530
+ if (list_empty(&devlink->trap_policer_list))
7531
+ return -EOPNOTSUPP;
7532
+
7533
+ if (!devlink->ops->trap_policer_set)
7534
+ return -EOPNOTSUPP;
7535
+
7536
+ policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
7537
+ if (!policer_item) {
7538
+ NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
7539
+ return -ENOENT;
7540
+ }
7541
+
7542
+ return devlink_trap_policer_set(devlink, policer_item, info);
7543
+}
7544
+
35877545 static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
7546
+ [DEVLINK_ATTR_UNSPEC] = { .strict_start_type =
7547
+ DEVLINK_ATTR_TRAP_POLICER_ID },
35887548 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
35897549 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
35907550 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
3591
- [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
7551
+ [DEVLINK_ATTR_PORT_TYPE] = NLA_POLICY_RANGE(NLA_U16, DEVLINK_PORT_TYPE_AUTO,
7552
+ DEVLINK_PORT_TYPE_IB),
35927553 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
35937554 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
35947555 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
....@@ -3597,7 +7558,8 @@
35977558 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
35987559 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
35997560 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
3600
- [DEVLINK_ATTR_ESWITCH_MODE] = { .type = NLA_U16 },
7561
+ [DEVLINK_ATTR_ESWITCH_MODE] = NLA_POLICY_RANGE(NLA_U16, DEVLINK_ESWITCH_MODE_LEGACY,
7562
+ DEVLINK_ESWITCH_MODE_SWITCHDEV),
36017563 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
36027564 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
36037565 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
....@@ -3611,225 +7573,340 @@
36117573 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
36127574 [DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .type = NLA_U64 },
36137575 [DEVLINK_ATTR_REGION_CHUNK_LEN] = { .type = NLA_U64 },
7576
+ [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
7577
+ [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
7578
+ [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
7579
+ [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
7580
+ [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
7581
+ [DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK] =
7582
+ NLA_POLICY_BITFIELD32(DEVLINK_SUPPORTED_FLASH_OVERWRITE_SECTIONS),
7583
+ [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING },
7584
+ [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 },
7585
+ [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING },
7586
+ [DEVLINK_ATTR_NETNS_PID] = { .type = NLA_U32 },
7587
+ [DEVLINK_ATTR_NETNS_FD] = { .type = NLA_U32 },
7588
+ [DEVLINK_ATTR_NETNS_ID] = { .type = NLA_U32 },
7589
+ [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .type = NLA_U8 },
7590
+ [DEVLINK_ATTR_TRAP_POLICER_ID] = { .type = NLA_U32 },
7591
+ [DEVLINK_ATTR_TRAP_POLICER_RATE] = { .type = NLA_U64 },
7592
+ [DEVLINK_ATTR_TRAP_POLICER_BURST] = { .type = NLA_U64 },
7593
+ [DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED },
7594
+ [DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
7595
+ DEVLINK_RELOAD_ACTION_MAX),
7596
+ [DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(DEVLINK_RELOAD_LIMITS_VALID_MASK),
36147597 };
36157598
3616
-static const struct genl_ops devlink_nl_ops[] = {
7599
+static const struct genl_small_ops devlink_nl_ops[] = {
36177600 {
36187601 .cmd = DEVLINK_CMD_GET,
7602
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
36197603 .doit = devlink_nl_cmd_get_doit,
36207604 .dumpit = devlink_nl_cmd_get_dumpit,
3621
- .policy = devlink_nl_policy,
3622
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
36237605 /* can be retrieved by unprivileged users */
36247606 },
36257607 {
36267608 .cmd = DEVLINK_CMD_PORT_GET,
7609
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
36277610 .doit = devlink_nl_cmd_port_get_doit,
36287611 .dumpit = devlink_nl_cmd_port_get_dumpit,
3629
- .policy = devlink_nl_policy,
36307612 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
36317613 /* can be retrieved by unprivileged users */
36327614 },
36337615 {
36347616 .cmd = DEVLINK_CMD_PORT_SET,
7617
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
36357618 .doit = devlink_nl_cmd_port_set_doit,
3636
- .policy = devlink_nl_policy,
36377619 .flags = GENL_ADMIN_PERM,
36387620 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
36397621 },
36407622 {
36417623 .cmd = DEVLINK_CMD_PORT_SPLIT,
7624
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
36427625 .doit = devlink_nl_cmd_port_split_doit,
3643
- .policy = devlink_nl_policy,
36447626 .flags = GENL_ADMIN_PERM,
3645
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
3646
- DEVLINK_NL_FLAG_NO_LOCK,
7627
+ .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
36477628 },
36487629 {
36497630 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
7631
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
36507632 .doit = devlink_nl_cmd_port_unsplit_doit,
3651
- .policy = devlink_nl_policy,
36527633 .flags = GENL_ADMIN_PERM,
3653
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
3654
- DEVLINK_NL_FLAG_NO_LOCK,
7634
+ .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
36557635 },
36567636 {
36577637 .cmd = DEVLINK_CMD_SB_GET,
7638
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
36587639 .doit = devlink_nl_cmd_sb_get_doit,
36597640 .dumpit = devlink_nl_cmd_sb_get_dumpit,
3660
- .policy = devlink_nl_policy,
3661
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
3662
- DEVLINK_NL_FLAG_NEED_SB,
36637641 /* can be retrieved by unprivileged users */
36647642 },
36657643 {
36667644 .cmd = DEVLINK_CMD_SB_POOL_GET,
7645
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
36677646 .doit = devlink_nl_cmd_sb_pool_get_doit,
36687647 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
3669
- .policy = devlink_nl_policy,
3670
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
3671
- DEVLINK_NL_FLAG_NEED_SB,
36727648 /* can be retrieved by unprivileged users */
36737649 },
36747650 {
36757651 .cmd = DEVLINK_CMD_SB_POOL_SET,
7652
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
36767653 .doit = devlink_nl_cmd_sb_pool_set_doit,
3677
- .policy = devlink_nl_policy,
36787654 .flags = GENL_ADMIN_PERM,
3679
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
3680
- DEVLINK_NL_FLAG_NEED_SB,
36817655 },
36827656 {
36837657 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
7658
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
36847659 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
36857660 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
3686
- .policy = devlink_nl_policy,
3687
- .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
3688
- DEVLINK_NL_FLAG_NEED_SB,
7661
+ .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
36897662 /* can be retrieved by unprivileged users */
36907663 },
36917664 {
36927665 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
7666
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
36937667 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
3694
- .policy = devlink_nl_policy,
36957668 .flags = GENL_ADMIN_PERM,
3696
- .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
3697
- DEVLINK_NL_FLAG_NEED_SB,
7669
+ .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
36987670 },
36997671 {
37007672 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
7673
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
37017674 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
37027675 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
3703
- .policy = devlink_nl_policy,
3704
- .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
3705
- DEVLINK_NL_FLAG_NEED_SB,
7676
+ .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
37067677 /* can be retrieved by unprivileged users */
37077678 },
37087679 {
37097680 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
7681
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
37107682 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
3711
- .policy = devlink_nl_policy,
37127683 .flags = GENL_ADMIN_PERM,
3713
- .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
3714
- DEVLINK_NL_FLAG_NEED_SB,
7684
+ .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
37157685 },
37167686 {
37177687 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
7688
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
37187689 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
3719
- .policy = devlink_nl_policy,
37207690 .flags = GENL_ADMIN_PERM,
3721
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
3722
- DEVLINK_NL_FLAG_NEED_SB,
37237691 },
37247692 {
37257693 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
7694
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
37267695 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
3727
- .policy = devlink_nl_policy,
37287696 .flags = GENL_ADMIN_PERM,
3729
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
3730
- DEVLINK_NL_FLAG_NEED_SB,
37317697 },
37327698 {
37337699 .cmd = DEVLINK_CMD_ESWITCH_GET,
7700
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
37347701 .doit = devlink_nl_cmd_eswitch_get_doit,
3735
- .policy = devlink_nl_policy,
37367702 .flags = GENL_ADMIN_PERM,
3737
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7703
+ .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
37387704 },
37397705 {
37407706 .cmd = DEVLINK_CMD_ESWITCH_SET,
7707
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
37417708 .doit = devlink_nl_cmd_eswitch_set_doit,
3742
- .policy = devlink_nl_policy,
37437709 .flags = GENL_ADMIN_PERM,
3744
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
3745
- DEVLINK_NL_FLAG_NO_LOCK,
7710
+ .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
37467711 },
37477712 {
37487713 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
7714
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
37497715 .doit = devlink_nl_cmd_dpipe_table_get,
3750
- .policy = devlink_nl_policy,
3751
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
37527716 /* can be retrieved by unprivileged users */
37537717 },
37547718 {
37557719 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
7720
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
37567721 .doit = devlink_nl_cmd_dpipe_entries_get,
3757
- .policy = devlink_nl_policy,
3758
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
37597722 /* can be retrieved by unprivileged users */
37607723 },
37617724 {
37627725 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
7726
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
37637727 .doit = devlink_nl_cmd_dpipe_headers_get,
3764
- .policy = devlink_nl_policy,
3765
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
37667728 /* can be retrieved by unprivileged users */
37677729 },
37687730 {
37697731 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
7732
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
37707733 .doit = devlink_nl_cmd_dpipe_table_counters_set,
3771
- .policy = devlink_nl_policy,
37727734 .flags = GENL_ADMIN_PERM,
3773
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
37747735 },
37757736 {
37767737 .cmd = DEVLINK_CMD_RESOURCE_SET,
7738
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
37777739 .doit = devlink_nl_cmd_resource_set,
3778
- .policy = devlink_nl_policy,
37797740 .flags = GENL_ADMIN_PERM,
3780
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
37817741 },
37827742 {
37837743 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
7744
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
37847745 .doit = devlink_nl_cmd_resource_dump,
3785
- .policy = devlink_nl_policy,
3786
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
37877746 /* can be retrieved by unprivileged users */
37887747 },
37897748 {
37907749 .cmd = DEVLINK_CMD_RELOAD,
7750
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
37917751 .doit = devlink_nl_cmd_reload,
3792
- .policy = devlink_nl_policy,
37937752 .flags = GENL_ADMIN_PERM,
3794
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
3795
- DEVLINK_NL_FLAG_NO_LOCK,
7753
+ .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
37967754 },
37977755 {
37987756 .cmd = DEVLINK_CMD_PARAM_GET,
7757
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
37997758 .doit = devlink_nl_cmd_param_get_doit,
38007759 .dumpit = devlink_nl_cmd_param_get_dumpit,
3801
- .policy = devlink_nl_policy,
3802
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
38037760 /* can be retrieved by unprivileged users */
38047761 },
38057762 {
38067763 .cmd = DEVLINK_CMD_PARAM_SET,
7764
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
38077765 .doit = devlink_nl_cmd_param_set_doit,
3808
- .policy = devlink_nl_policy,
38097766 .flags = GENL_ADMIN_PERM,
3810
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7767
+ },
7768
+ {
7769
+ .cmd = DEVLINK_CMD_PORT_PARAM_GET,
7770
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7771
+ .doit = devlink_nl_cmd_port_param_get_doit,
7772
+ .dumpit = devlink_nl_cmd_port_param_get_dumpit,
7773
+ .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7774
+ /* can be retrieved by unprivileged users */
7775
+ },
7776
+ {
7777
+ .cmd = DEVLINK_CMD_PORT_PARAM_SET,
7778
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7779
+ .doit = devlink_nl_cmd_port_param_set_doit,
7780
+ .flags = GENL_ADMIN_PERM,
7781
+ .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
38117782 },
38127783 {
38137784 .cmd = DEVLINK_CMD_REGION_GET,
7785
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
38147786 .doit = devlink_nl_cmd_region_get_doit,
38157787 .dumpit = devlink_nl_cmd_region_get_dumpit,
3816
- .policy = devlink_nl_policy,
38177788 .flags = GENL_ADMIN_PERM,
3818
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7789
+ },
7790
+ {
7791
+ .cmd = DEVLINK_CMD_REGION_NEW,
7792
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7793
+ .doit = devlink_nl_cmd_region_new,
7794
+ .flags = GENL_ADMIN_PERM,
38197795 },
38207796 {
38217797 .cmd = DEVLINK_CMD_REGION_DEL,
7798
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
38227799 .doit = devlink_nl_cmd_region_del,
3823
- .policy = devlink_nl_policy,
38247800 .flags = GENL_ADMIN_PERM,
3825
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
38267801 },
38277802 {
38287803 .cmd = DEVLINK_CMD_REGION_READ,
7804
+ .validate = GENL_DONT_VALIDATE_STRICT |
7805
+ GENL_DONT_VALIDATE_DUMP_STRICT,
38297806 .dumpit = devlink_nl_cmd_region_read_dumpit,
3830
- .policy = devlink_nl_policy,
38317807 .flags = GENL_ADMIN_PERM,
3832
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7808
+ },
7809
+ {
7810
+ .cmd = DEVLINK_CMD_INFO_GET,
7811
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7812
+ .doit = devlink_nl_cmd_info_get_doit,
7813
+ .dumpit = devlink_nl_cmd_info_get_dumpit,
7814
+ /* can be retrieved by unprivileged users */
7815
+ },
7816
+ {
7817
+ .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
7818
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7819
+ .doit = devlink_nl_cmd_health_reporter_get_doit,
7820
+ .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
7821
+ .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
7822
+ DEVLINK_NL_FLAG_NO_LOCK,
7823
+ /* can be retrieved by unprivileged users */
7824
+ },
7825
+ {
7826
+ .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
7827
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7828
+ .doit = devlink_nl_cmd_health_reporter_set_doit,
7829
+ .flags = GENL_ADMIN_PERM,
7830
+ .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
7831
+ DEVLINK_NL_FLAG_NO_LOCK,
7832
+ },
7833
+ {
7834
+ .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
7835
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7836
+ .doit = devlink_nl_cmd_health_reporter_recover_doit,
7837
+ .flags = GENL_ADMIN_PERM,
7838
+ .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
7839
+ DEVLINK_NL_FLAG_NO_LOCK,
7840
+ },
7841
+ {
7842
+ .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
7843
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7844
+ .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
7845
+ .flags = GENL_ADMIN_PERM,
7846
+ .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
7847
+ DEVLINK_NL_FLAG_NO_LOCK,
7848
+ },
7849
+ {
7850
+ .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
7851
+ .validate = GENL_DONT_VALIDATE_STRICT |
7852
+ GENL_DONT_VALIDATE_DUMP_STRICT,
7853
+ .dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
7854
+ .flags = GENL_ADMIN_PERM,
7855
+ },
7856
+ {
7857
+ .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
7858
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7859
+ .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
7860
+ .flags = GENL_ADMIN_PERM,
7861
+ .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
7862
+ DEVLINK_NL_FLAG_NO_LOCK,
7863
+ },
7864
+ {
7865
+ .cmd = DEVLINK_CMD_HEALTH_REPORTER_TEST,
7866
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7867
+ .doit = devlink_nl_cmd_health_reporter_test_doit,
7868
+ .flags = GENL_ADMIN_PERM,
7869
+ .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
7870
+ DEVLINK_NL_FLAG_NO_LOCK,
7871
+ },
7872
+ {
7873
+ .cmd = DEVLINK_CMD_FLASH_UPDATE,
7874
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7875
+ .doit = devlink_nl_cmd_flash_update,
7876
+ .flags = GENL_ADMIN_PERM,
7877
+ },
7878
+ {
7879
+ .cmd = DEVLINK_CMD_TRAP_GET,
7880
+ .doit = devlink_nl_cmd_trap_get_doit,
7881
+ .dumpit = devlink_nl_cmd_trap_get_dumpit,
7882
+ /* can be retrieved by unprivileged users */
7883
+ },
7884
+ {
7885
+ .cmd = DEVLINK_CMD_TRAP_SET,
7886
+ .doit = devlink_nl_cmd_trap_set_doit,
7887
+ .flags = GENL_ADMIN_PERM,
7888
+ },
7889
+ {
7890
+ .cmd = DEVLINK_CMD_TRAP_GROUP_GET,
7891
+ .doit = devlink_nl_cmd_trap_group_get_doit,
7892
+ .dumpit = devlink_nl_cmd_trap_group_get_dumpit,
7893
+ /* can be retrieved by unprivileged users */
7894
+ },
7895
+ {
7896
+ .cmd = DEVLINK_CMD_TRAP_GROUP_SET,
7897
+ .doit = devlink_nl_cmd_trap_group_set_doit,
7898
+ .flags = GENL_ADMIN_PERM,
7899
+ },
7900
+ {
7901
+ .cmd = DEVLINK_CMD_TRAP_POLICER_GET,
7902
+ .doit = devlink_nl_cmd_trap_policer_get_doit,
7903
+ .dumpit = devlink_nl_cmd_trap_policer_get_dumpit,
7904
+ /* can be retrieved by unprivileged users */
7905
+ },
7906
+ {
7907
+ .cmd = DEVLINK_CMD_TRAP_POLICER_SET,
7908
+ .doit = devlink_nl_cmd_trap_policer_set_doit,
7909
+ .flags = GENL_ADMIN_PERM,
38337910 },
38347911 };
38357912
....@@ -3837,15 +7914,45 @@
38377914 .name = DEVLINK_GENL_NAME,
38387915 .version = DEVLINK_GENL_VERSION,
38397916 .maxattr = DEVLINK_ATTR_MAX,
7917
+ .policy = devlink_nl_policy,
38407918 .netnsok = true,
38417919 .pre_doit = devlink_nl_pre_doit,
38427920 .post_doit = devlink_nl_post_doit,
38437921 .module = THIS_MODULE,
3844
- .ops = devlink_nl_ops,
3845
- .n_ops = ARRAY_SIZE(devlink_nl_ops),
7922
+ .small_ops = devlink_nl_ops,
7923
+ .n_small_ops = ARRAY_SIZE(devlink_nl_ops),
38467924 .mcgrps = devlink_nl_mcgrps,
38477925 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
38487926 };
7927
+
7928
+static bool devlink_reload_actions_valid(const struct devlink_ops *ops)
7929
+{
7930
+ const struct devlink_reload_combination *comb;
7931
+ int i;
7932
+
7933
+ if (!devlink_reload_supported(ops)) {
7934
+ if (WARN_ON(ops->reload_actions))
7935
+ return false;
7936
+ return true;
7937
+ }
7938
+
7939
+ if (WARN_ON(!ops->reload_actions ||
7940
+ ops->reload_actions & BIT(DEVLINK_RELOAD_ACTION_UNSPEC) ||
7941
+ ops->reload_actions >= BIT(__DEVLINK_RELOAD_ACTION_MAX)))
7942
+ return false;
7943
+
7944
+ if (WARN_ON(ops->reload_limits & BIT(DEVLINK_RELOAD_LIMIT_UNSPEC) ||
7945
+ ops->reload_limits >= BIT(__DEVLINK_RELOAD_LIMIT_MAX)))
7946
+ return false;
7947
+
7948
+ for (i = 0; i < ARRAY_SIZE(devlink_reload_invalid_combinations); i++) {
7949
+ comb = &devlink_reload_invalid_combinations[i];
7950
+ if (ops->reload_actions == BIT(comb->action) &&
7951
+ ops->reload_limits == BIT(comb->limit))
7952
+ return false;
7953
+ }
7954
+ return true;
7955
+}
38497956
38507957 /**
38517958 * devlink_alloc - Allocate new devlink instance resources
....@@ -3860,18 +7967,30 @@
38607967 {
38617968 struct devlink *devlink;
38627969
7970
+ if (WARN_ON(!ops))
7971
+ return NULL;
7972
+
7973
+ if (!devlink_reload_actions_valid(ops))
7974
+ return NULL;
7975
+
38637976 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
38647977 if (!devlink)
38657978 return NULL;
38667979 devlink->ops = ops;
3867
- devlink_net_set(devlink, &init_net);
7980
+ xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC);
7981
+ __devlink_net_set(devlink, &init_net);
38687982 INIT_LIST_HEAD(&devlink->port_list);
38697983 INIT_LIST_HEAD(&devlink->sb_list);
38707984 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
38717985 INIT_LIST_HEAD(&devlink->resource_list);
38727986 INIT_LIST_HEAD(&devlink->param_list);
38737987 INIT_LIST_HEAD(&devlink->region_list);
7988
+ INIT_LIST_HEAD(&devlink->reporter_list);
7989
+ INIT_LIST_HEAD(&devlink->trap_list);
7990
+ INIT_LIST_HEAD(&devlink->trap_group_list);
7991
+ INIT_LIST_HEAD(&devlink->trap_policer_list);
38747992 mutex_init(&devlink->lock);
7993
+ mutex_init(&devlink->reporters_lock);
38757994 return devlink;
38767995 }
38777996 EXPORT_SYMBOL_GPL(devlink_alloc);
....@@ -3880,11 +7999,13 @@
38807999 * devlink_register - Register devlink instance
38818000 *
38828001 * @devlink: devlink
8002
+ * @dev: parent device
38838003 */
38848004 int devlink_register(struct devlink *devlink, struct device *dev)
38858005 {
3886
- mutex_lock(&devlink_mutex);
38878006 devlink->dev = dev;
8007
+ devlink->registered = true;
8008
+ mutex_lock(&devlink_mutex);
38888009 list_add_tail(&devlink->list, &devlink_list);
38898010 devlink_notify(devlink, DEVLINK_CMD_NEW);
38908011 mutex_unlock(&devlink_mutex);
....@@ -3900,11 +8021,48 @@
39008021 void devlink_unregister(struct devlink *devlink)
39018022 {
39028023 mutex_lock(&devlink_mutex);
8024
+ WARN_ON(devlink_reload_supported(devlink->ops) &&
8025
+ devlink->reload_enabled);
39038026 devlink_notify(devlink, DEVLINK_CMD_DEL);
39048027 list_del(&devlink->list);
39058028 mutex_unlock(&devlink_mutex);
39068029 }
39078030 EXPORT_SYMBOL_GPL(devlink_unregister);
8031
+
8032
+/**
8033
+ * devlink_reload_enable - Enable reload of devlink instance
8034
+ *
8035
+ * @devlink: devlink
8036
+ *
8037
+ * Should be called at end of device initialization
8038
+ * process when reload operation is supported.
8039
+ */
8040
+void devlink_reload_enable(struct devlink *devlink)
8041
+{
8042
+ mutex_lock(&devlink_mutex);
8043
+ devlink->reload_enabled = true;
8044
+ mutex_unlock(&devlink_mutex);
8045
+}
8046
+EXPORT_SYMBOL_GPL(devlink_reload_enable);
8047
+
8048
+/**
8049
+ * devlink_reload_disable - Disable reload of devlink instance
8050
+ *
8051
+ * @devlink: devlink
8052
+ *
8053
+ * Should be called at the beginning of device cleanup
8054
+ * process when reload operation is supported.
8055
+ */
8056
+void devlink_reload_disable(struct devlink *devlink)
8057
+{
8058
+ mutex_lock(&devlink_mutex);
8059
+ /* Mutex is taken which ensures that no reload operation is in
8060
+ * progress while setting up forbidded flag.
8061
+ */
8062
+ devlink->reload_enabled = false;
8063
+ mutex_unlock(&devlink_mutex);
8064
+}
8065
+EXPORT_SYMBOL_GPL(devlink_reload_disable);
39088066
39098067 /**
39108068 * devlink_free - Free devlink instance resources
....@@ -3913,16 +8071,67 @@
39138071 */
39148072 void devlink_free(struct devlink *devlink)
39158073 {
8074
+ mutex_destroy(&devlink->reporters_lock);
8075
+ mutex_destroy(&devlink->lock);
8076
+ WARN_ON(!list_empty(&devlink->trap_policer_list));
8077
+ WARN_ON(!list_empty(&devlink->trap_group_list));
8078
+ WARN_ON(!list_empty(&devlink->trap_list));
8079
+ WARN_ON(!list_empty(&devlink->reporter_list));
8080
+ WARN_ON(!list_empty(&devlink->region_list));
8081
+ WARN_ON(!list_empty(&devlink->param_list));
8082
+ WARN_ON(!list_empty(&devlink->resource_list));
8083
+ WARN_ON(!list_empty(&devlink->dpipe_table_list));
8084
+ WARN_ON(!list_empty(&devlink->sb_list));
8085
+ WARN_ON(!list_empty(&devlink->port_list));
8086
+
8087
+ xa_destroy(&devlink->snapshot_ids);
8088
+
39168089 kfree(devlink);
39178090 }
39188091 EXPORT_SYMBOL_GPL(devlink_free);
8092
+
8093
+static void devlink_port_type_warn(struct work_struct *work)
8094
+{
8095
+ struct devlink_port *port = container_of(to_delayed_work(work),
8096
+ struct devlink_port,
8097
+ type_warn_dw);
8098
+ dev_warn(port->devlink->dev, "Type was not set for devlink port.");
8099
+}
8100
+
8101
+static bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
8102
+{
8103
+ /* Ignore CPU and DSA flavours. */
8104
+ return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
8105
+ devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA &&
8106
+ devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_UNUSED;
8107
+}
8108
+
8109
+#define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 3600)
8110
+
8111
+static void devlink_port_type_warn_schedule(struct devlink_port *devlink_port)
8112
+{
8113
+ if (!devlink_port_type_should_warn(devlink_port))
8114
+ return;
8115
+ /* Schedule a work to WARN in case driver does not set port
8116
+ * type within timeout.
8117
+ */
8118
+ schedule_delayed_work(&devlink_port->type_warn_dw,
8119
+ DEVLINK_PORT_TYPE_WARN_TIMEOUT);
8120
+}
8121
+
8122
+static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
8123
+{
8124
+ if (!devlink_port_type_should_warn(devlink_port))
8125
+ return;
8126
+ cancel_delayed_work_sync(&devlink_port->type_warn_dw);
8127
+}
39198128
39208129 /**
39218130 * devlink_port_register - Register devlink port
39228131 *
39238132 * @devlink: devlink
39248133 * @devlink_port: devlink port
3925
- * @port_index
8134
+ * @port_index: driver-specific numerical identifier of the port
39268135 *
39278136 * Register devlink port with provided port index. User can use
39288137 * any indexing, even hw-related one. devlink_port structure
....@@ -3942,8 +8151,15 @@
39428151 devlink_port->devlink = devlink;
39438152 devlink_port->index = port_index;
39448153 devlink_port->registered = true;
8154
+ spin_lock_init(&devlink_port->type_lock);
8155
+ INIT_LIST_HEAD(&devlink_port->reporter_list);
8156
+ mutex_init(&devlink_port->reporters_lock);
39458157 list_add_tail(&devlink_port->list, &devlink->port_list);
8158
+ INIT_LIST_HEAD(&devlink_port->param_list);
8159
+ INIT_LIST_HEAD(&devlink_port->region_list);
39468160 mutex_unlock(&devlink->lock);
8161
+ INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
8162
+ devlink_port_type_warn_schedule(devlink_port);
39478163 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
39488164 return 0;
39498165 }
....@@ -3958,10 +8174,14 @@
39588174 {
39598175 struct devlink *devlink = devlink_port->devlink;
39608176
8177
+ devlink_port_type_warn_cancel(devlink_port);
39618178 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
39628179 mutex_lock(&devlink->lock);
39638180 list_del(&devlink_port->list);
39648181 mutex_unlock(&devlink->lock);
8182
+ WARN_ON(!list_empty(&devlink_port->reporter_list));
8183
+ WARN_ON(!list_empty(&devlink_port->region_list));
8184
+ mutex_destroy(&devlink_port->reporters_lock);
39658185 }
39668186 EXPORT_SYMBOL_GPL(devlink_port_unregister);
39678187
....@@ -3969,9 +8189,51 @@
39698189 enum devlink_port_type type,
39708190 void *type_dev)
39718191 {
8192
+ if (WARN_ON(!devlink_port->registered))
8193
+ return;
8194
+ devlink_port_type_warn_cancel(devlink_port);
8195
+ spin_lock_bh(&devlink_port->type_lock);
39728196 devlink_port->type = type;
39738197 devlink_port->type_dev = type_dev;
8198
+ spin_unlock_bh(&devlink_port->type_lock);
39748199 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
8200
+}
8201
+
8202
+static void devlink_port_type_netdev_checks(struct devlink_port *devlink_port,
8203
+ struct net_device *netdev)
8204
+{
8205
+ const struct net_device_ops *ops = netdev->netdev_ops;
8206
+
8207
+ /* If driver registers devlink port, it should set devlink port
8208
+ * attributes accordingly so the compat functions are called
8209
+ * and the original ops are not used.
8210
+ */
8211
+ if (ops->ndo_get_phys_port_name) {
8212
+ /* Some drivers use the same set of ndos for netdevs
8213
+ * that have devlink_port registered and also for
8214
+ * those who don't. Make sure that ndo_get_phys_port_name
8215
+ * returns -EOPNOTSUPP here in case it is defined.
8216
+ * Warn if not.
8217
+ */
8218
+ char name[IFNAMSIZ];
8219
+ int err;
8220
+
8221
+ err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
8222
+ WARN_ON(err != -EOPNOTSUPP);
8223
+ }
8224
+ if (ops->ndo_get_port_parent_id) {
8225
+ /* Some drivers use the same set of ndos for netdevs
8226
+ * that have devlink_port registered and also for
8227
+ * those who don't. Make sure that ndo_get_port_parent_id
8228
+ * returns -EOPNOTSUPP here in case it is defined.
8229
+ * Warn if not.
8230
+ */
8231
+ struct netdev_phys_item_id ppid;
8232
+ int err;
8233
+
8234
+ err = ops->ndo_get_port_parent_id(netdev, &ppid);
8235
+ WARN_ON(err != -EOPNOTSUPP);
8236
+ }
39758237 }
39768238
39778239 /**
....@@ -3983,8 +8245,14 @@
39838245 void devlink_port_type_eth_set(struct devlink_port *devlink_port,
39848246 struct net_device *netdev)
39858247 {
3986
- return __devlink_port_type_set(devlink_port,
3987
- DEVLINK_PORT_TYPE_ETH, netdev);
8248
+ if (netdev)
8249
+ devlink_port_type_netdev_checks(devlink_port, netdev);
8250
+ else
8251
+ dev_warn(devlink_port->devlink->dev,
8252
+ "devlink port type for port %d set to Ethernet without a software interface reference, device type not supported by the kernel?\n",
8253
+ devlink_port->index);
8254
+
8255
+ __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev);
39888256 }
39898257 EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
39908258
....@@ -3997,8 +8265,7 @@
39978265 void devlink_port_type_ib_set(struct devlink_port *devlink_port,
39988266 struct ib_device *ibdev)
39998267 {
4000
- return __devlink_port_type_set(devlink_port,
4001
- DEVLINK_PORT_TYPE_IB, ibdev);
8268
+ __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
40028269 }
40038270 EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
40048271
....@@ -4009,62 +8276,152 @@
40098276 */
40108277 void devlink_port_type_clear(struct devlink_port *devlink_port)
40118278 {
4012
- return __devlink_port_type_set(devlink_port,
4013
- DEVLINK_PORT_TYPE_NOTSET, NULL);
8279
+ __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
8280
+ devlink_port_type_warn_schedule(devlink_port);
40148281 }
40158282 EXPORT_SYMBOL_GPL(devlink_port_type_clear);
8283
+
8284
+static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
8285
+ enum devlink_port_flavour flavour)
8286
+{
8287
+ struct devlink_port_attrs *attrs = &devlink_port->attrs;
8288
+
8289
+ devlink_port->attrs_set = true;
8290
+ attrs->flavour = flavour;
8291
+ if (attrs->switch_id.id_len) {
8292
+ devlink_port->switch_port = true;
8293
+ if (WARN_ON(attrs->switch_id.id_len > MAX_PHYS_ITEM_ID_LEN))
8294
+ attrs->switch_id.id_len = MAX_PHYS_ITEM_ID_LEN;
8295
+ } else {
8296
+ devlink_port->switch_port = false;
8297
+ }
8298
+ return 0;
8299
+}
40168300
40178301 /**
40188302 * devlink_port_attrs_set - Set port attributes
40198303 *
40208304 * @devlink_port: devlink port
4021
- * @flavour: flavour of the port
4022
- * @port_number: number of the port that is facing user, for example
4023
- * the front panel port number
4024
- * @split: indicates if this is split port
4025
- * @split_subport_number: if the port is split, this is the number
4026
- * of subport.
8305
+ * @attrs: devlink port attrs
40278306 */
40288307 void devlink_port_attrs_set(struct devlink_port *devlink_port,
4029
- enum devlink_port_flavour flavour,
4030
- u32 port_number, bool split,
4031
- u32 split_subport_number)
8308
+ struct devlink_port_attrs *attrs)
40328309 {
4033
- struct devlink_port_attrs *attrs = &devlink_port->attrs;
8310
+ int ret;
40348311
4035
- attrs->set = true;
4036
- attrs->flavour = flavour;
4037
- attrs->port_number = port_number;
4038
- attrs->split = split;
4039
- attrs->split_subport_number = split_subport_number;
4040
- devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
8312
+ if (WARN_ON(devlink_port->registered))
8313
+ return;
8314
+ devlink_port->attrs = *attrs;
8315
+ ret = __devlink_port_attrs_set(devlink_port, attrs->flavour);
8316
+ if (ret)
8317
+ return;
8318
+ WARN_ON(attrs->splittable && attrs->split);
40418319 }
40428320 EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
40438321
4044
-int devlink_port_get_phys_port_name(struct devlink_port *devlink_port,
4045
- char *name, size_t len)
8322
+/**
8323
+ * devlink_port_attrs_pci_pf_set - Set PCI PF port attributes
8324
+ *
8325
+ * @devlink_port: devlink port
8326
+ * @controller: associated controller number for the devlink port instance
8327
+ * @pf: associated PF for the devlink port instance
8328
+ * @external: indicates if the port is for an external controller
8329
+ */
8330
+void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 controller,
8331
+ u16 pf, bool external)
8332
+{
8333
+ struct devlink_port_attrs *attrs = &devlink_port->attrs;
8334
+ int ret;
8335
+
8336
+ if (WARN_ON(devlink_port->registered))
8337
+ return;
8338
+ ret = __devlink_port_attrs_set(devlink_port,
8339
+ DEVLINK_PORT_FLAVOUR_PCI_PF);
8340
+ if (ret)
8341
+ return;
8342
+ attrs->pci_pf.controller = controller;
8343
+ attrs->pci_pf.pf = pf;
8344
+ attrs->pci_pf.external = external;
8345
+}
8346
+EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);
8347
+
8348
+/**
8349
+ * devlink_port_attrs_pci_vf_set - Set PCI VF port attributes
8350
+ *
8351
+ * @devlink_port: devlink port
8352
+ * @controller: associated controller number for the devlink port instance
8353
+ * @pf: associated PF for the devlink port instance
8354
+ * @vf: associated VF of a PF for the devlink port instance
8355
+ * @external: indicates if the port is for an external controller
8356
+ */
8357
+void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller,
8358
+ u16 pf, u16 vf, bool external)
8359
+{
8360
+ struct devlink_port_attrs *attrs = &devlink_port->attrs;
8361
+ int ret;
8362
+
8363
+ if (WARN_ON(devlink_port->registered))
8364
+ return;
8365
+ ret = __devlink_port_attrs_set(devlink_port,
8366
+ DEVLINK_PORT_FLAVOUR_PCI_VF);
8367
+ if (ret)
8368
+ return;
8369
+ attrs->pci_vf.controller = controller;
8370
+ attrs->pci_vf.pf = pf;
8371
+ attrs->pci_vf.vf = vf;
8372
+ attrs->pci_vf.external = external;
8373
+}
8374
+EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set);
8375
+
8376
+static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
8377
+ char *name, size_t len)
40468378 {
40478379 struct devlink_port_attrs *attrs = &devlink_port->attrs;
40488380 int n = 0;
40498381
4050
- if (!attrs->set)
8382
+ if (!devlink_port->attrs_set)
40518383 return -EOPNOTSUPP;
40528384
40538385 switch (attrs->flavour) {
40548386 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
40558387 if (!attrs->split)
4056
- n = snprintf(name, len, "p%u", attrs->port_number);
8388
+ n = snprintf(name, len, "p%u", attrs->phys.port_number);
40578389 else
4058
- n = snprintf(name, len, "p%us%u", attrs->port_number,
4059
- attrs->split_subport_number);
8390
+ n = snprintf(name, len, "p%us%u",
8391
+ attrs->phys.port_number,
8392
+ attrs->phys.split_subport_number);
40608393 break;
40618394 case DEVLINK_PORT_FLAVOUR_CPU:
40628395 case DEVLINK_PORT_FLAVOUR_DSA:
8396
+ case DEVLINK_PORT_FLAVOUR_UNUSED:
40638397 /* As CPU and DSA ports do not have a netdevice associated
40648398 * case should not ever happen.
40658399 */
40668400 WARN_ON(1);
40678401 return -EINVAL;
8402
+ case DEVLINK_PORT_FLAVOUR_PCI_PF:
8403
+ if (attrs->pci_pf.external) {
8404
+ n = snprintf(name, len, "c%u", attrs->pci_pf.controller);
8405
+ if (n >= len)
8406
+ return -EINVAL;
8407
+ len -= n;
8408
+ name += n;
8409
+ }
8410
+ n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
8411
+ break;
8412
+ case DEVLINK_PORT_FLAVOUR_PCI_VF:
8413
+ if (attrs->pci_vf.external) {
8414
+ n = snprintf(name, len, "c%u", attrs->pci_vf.controller);
8415
+ if (n >= len)
8416
+ return -EINVAL;
8417
+ len -= n;
8418
+ name += n;
8419
+ }
8420
+ n = snprintf(name, len, "pf%uvf%u",
8421
+ attrs->pci_vf.pf, attrs->pci_vf.vf);
8422
+ break;
8423
+ case DEVLINK_PORT_FLAVOUR_VIRTUAL:
8424
+ return -EOPNOTSUPP;
40688425 }
40698426
40708427 if (n >= len)
....@@ -4072,7 +8429,6 @@
40728429
40738430 return 0;
40748431 }
4075
-EXPORT_SYMBOL_GPL(devlink_port_get_phys_port_name);
40768432
40778433 int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
40788434 u32 size, u16 ingress_pools_count,
....@@ -4174,7 +8530,7 @@
41748530
41758531 rcu_read_lock();
41768532 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
4177
- table_name);
8533
+ table_name, devlink);
41788534 enabled = false;
41798535 if (table)
41808536 enabled = table->counters_enabled;
....@@ -4198,26 +8554,34 @@
41988554 void *priv, bool counter_control_extern)
41998555 {
42008556 struct devlink_dpipe_table *table;
4201
-
4202
- if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name))
4203
- return -EEXIST;
8557
+ int err = 0;
42048558
42058559 if (WARN_ON(!table_ops->size_get))
42068560 return -EINVAL;
42078561
8562
+ mutex_lock(&devlink->lock);
8563
+
8564
+ if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name,
8565
+ devlink)) {
8566
+ err = -EEXIST;
8567
+ goto unlock;
8568
+ }
8569
+
42088570 table = kzalloc(sizeof(*table), GFP_KERNEL);
4209
- if (!table)
4210
- return -ENOMEM;
8571
+ if (!table) {
8572
+ err = -ENOMEM;
8573
+ goto unlock;
8574
+ }
42118575
42128576 table->name = table_name;
42138577 table->table_ops = table_ops;
42148578 table->priv = priv;
42158579 table->counter_control_extern = counter_control_extern;
42168580
4217
- mutex_lock(&devlink->lock);
42188581 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
8582
+unlock:
42198583 mutex_unlock(&devlink->lock);
4220
- return 0;
8584
+ return err;
42218585 }
42228586 EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
42238587
....@@ -4234,7 +8598,7 @@
42348598
42358599 mutex_lock(&devlink->lock);
42368600 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
4237
- table_name);
8601
+ table_name, devlink);
42388602 if (!table)
42398603 goto unlock;
42408604 list_del_rcu(&table->list);
....@@ -4251,13 +8615,10 @@
42518615 *
42528616 * @devlink: devlink
42538617 * @resource_name: resource's name
4254
- * @top_hierarchy: top hierarchy
4255
- * @reload_required: reload is required for new configuration to
4256
- * apply
42578618 * @resource_size: resource's size
42588619 * @resource_id: resource's id
4259
- * @parent_reosurce_id: resource's parent id
4260
- * @size params: size parameters
8620
+ * @parent_resource_id: resource's parent id
8621
+ * @size_params: size parameters
42618622 */
42628623 int devlink_resource_register(struct devlink *devlink,
42638624 const char *resource_name,
....@@ -4394,7 +8755,7 @@
43948755
43958756 mutex_lock(&devlink->lock);
43968757 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
4397
- table_name);
8758
+ table_name, devlink);
43988759 if (!table) {
43998760 err = -EINVAL;
44008761 goto out;
....@@ -4460,6 +8821,71 @@
44608821 }
44618822 EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
44628823
8824
+static int devlink_param_verify(const struct devlink_param *param)
8825
+{
8826
+ if (!param || !param->name || !param->supported_cmodes)
8827
+ return -EINVAL;
8828
+ if (param->generic)
8829
+ return devlink_param_generic_verify(param);
8830
+ else
8831
+ return devlink_param_driver_verify(param);
8832
+}
8833
+
8834
+static int __devlink_params_register(struct devlink *devlink,
8835
+ unsigned int port_index,
8836
+ struct list_head *param_list,
8837
+ const struct devlink_param *params,
8838
+ size_t params_count,
8839
+ enum devlink_command reg_cmd,
8840
+ enum devlink_command unreg_cmd)
8841
+{
8842
+ const struct devlink_param *param = params;
8843
+ int i;
8844
+ int err;
8845
+
8846
+ mutex_lock(&devlink->lock);
8847
+ for (i = 0; i < params_count; i++, param++) {
8848
+ err = devlink_param_verify(param);
8849
+ if (err)
8850
+ goto rollback;
8851
+
8852
+ err = devlink_param_register_one(devlink, port_index,
8853
+ param_list, param, reg_cmd);
8854
+ if (err)
8855
+ goto rollback;
8856
+ }
8857
+
8858
+ mutex_unlock(&devlink->lock);
8859
+ return 0;
8860
+
8861
+rollback:
8862
+ if (!i)
8863
+ goto unlock;
8864
+ for (param--; i > 0; i--, param--)
8865
+ devlink_param_unregister_one(devlink, port_index, param_list,
8866
+ param, unreg_cmd);
8867
+unlock:
8868
+ mutex_unlock(&devlink->lock);
8869
+ return err;
8870
+}
8871
+
8872
+static void __devlink_params_unregister(struct devlink *devlink,
8873
+ unsigned int port_index,
8874
+ struct list_head *param_list,
8875
+ const struct devlink_param *params,
8876
+ size_t params_count,
8877
+ enum devlink_command cmd)
8878
+{
8879
+ const struct devlink_param *param = params;
8880
+ int i;
8881
+
8882
+ mutex_lock(&devlink->lock);
8883
+ for (i = 0; i < params_count; i++, param++)
8884
+ devlink_param_unregister_one(devlink, 0, param_list, param,
8885
+ cmd);
8886
+ mutex_unlock(&devlink->lock);
8887
+}
8888
+
44638889 /**
44648890 * devlink_params_register - register configuration parameters
44658891 *
....@@ -4473,41 +8899,10 @@
44738899 const struct devlink_param *params,
44748900 size_t params_count)
44758901 {
4476
- const struct devlink_param *param = params;
4477
- int i;
4478
- int err;
4479
-
4480
- mutex_lock(&devlink->lock);
4481
- for (i = 0; i < params_count; i++, param++) {
4482
- if (!param || !param->name || !param->supported_cmodes) {
4483
- err = -EINVAL;
4484
- goto rollback;
4485
- }
4486
- if (param->generic) {
4487
- err = devlink_param_generic_verify(param);
4488
- if (err)
4489
- goto rollback;
4490
- } else {
4491
- err = devlink_param_driver_verify(param);
4492
- if (err)
4493
- goto rollback;
4494
- }
4495
- err = devlink_param_register_one(devlink, param);
4496
- if (err)
4497
- goto rollback;
4498
- }
4499
-
4500
- mutex_unlock(&devlink->lock);
4501
- return 0;
4502
-
4503
-rollback:
4504
- if (!i)
4505
- goto unlock;
4506
- for (param--; i > 0; i--, param--)
4507
- devlink_param_unregister_one(devlink, param);
4508
-unlock:
4509
- mutex_unlock(&devlink->lock);
4510
- return err;
8902
+ return __devlink_params_register(devlink, 0, &devlink->param_list,
8903
+ params, params_count,
8904
+ DEVLINK_CMD_PARAM_NEW,
8905
+ DEVLINK_CMD_PARAM_DEL);
45118906 }
45128907 EXPORT_SYMBOL_GPL(devlink_params_register);
45138908
....@@ -4521,15 +8916,145 @@
45218916 const struct devlink_param *params,
45228917 size_t params_count)
45238918 {
4524
- const struct devlink_param *param = params;
4525
- int i;
4526
-
4527
- mutex_lock(&devlink->lock);
4528
- for (i = 0; i < params_count; i++, param++)
4529
- devlink_param_unregister_one(devlink, param);
4530
- mutex_unlock(&devlink->lock);
8919
+ return __devlink_params_unregister(devlink, 0, &devlink->param_list,
8920
+ params, params_count,
8921
+ DEVLINK_CMD_PARAM_DEL);
45318922 }
45328923 EXPORT_SYMBOL_GPL(devlink_params_unregister);
8924
+
8925
+/**
8926
+ * devlink_params_publish - publish configuration parameters
8927
+ *
8928
+ * @devlink: devlink
8929
+ *
8930
+ * Publish previously registered configuration parameters.
8931
+ */
8932
+void devlink_params_publish(struct devlink *devlink)
8933
+{
8934
+ struct devlink_param_item *param_item;
8935
+
8936
+ list_for_each_entry(param_item, &devlink->param_list, list) {
8937
+ if (param_item->published)
8938
+ continue;
8939
+ param_item->published = true;
8940
+ devlink_param_notify(devlink, 0, param_item,
8941
+ DEVLINK_CMD_PARAM_NEW);
8942
+ }
8943
+}
8944
+EXPORT_SYMBOL_GPL(devlink_params_publish);
8945
+
8946
+/**
8947
+ * devlink_params_unpublish - unpublish configuration parameters
8948
+ *
8949
+ * @devlink: devlink
8950
+ *
8951
+ * Unpublish previously registered configuration parameters.
8952
+ */
8953
+void devlink_params_unpublish(struct devlink *devlink)
8954
+{
8955
+ struct devlink_param_item *param_item;
8956
+
8957
+ list_for_each_entry(param_item, &devlink->param_list, list) {
8958
+ if (!param_item->published)
8959
+ continue;
8960
+ param_item->published = false;
8961
+ devlink_param_notify(devlink, 0, param_item,
8962
+ DEVLINK_CMD_PARAM_DEL);
8963
+ }
8964
+}
8965
+EXPORT_SYMBOL_GPL(devlink_params_unpublish);
8966
+
8967
+/**
8968
+ * devlink_port_params_register - register port configuration parameters
8969
+ *
8970
+ * @devlink_port: devlink port
8971
+ * @params: configuration parameters array
8972
+ * @params_count: number of parameters provided
8973
+ *
8974
+ * Register the configuration parameters supported by the port.
8975
+ */
8976
+int devlink_port_params_register(struct devlink_port *devlink_port,
8977
+ const struct devlink_param *params,
8978
+ size_t params_count)
8979
+{
8980
+ return __devlink_params_register(devlink_port->devlink,
8981
+ devlink_port->index,
8982
+ &devlink_port->param_list, params,
8983
+ params_count,
8984
+ DEVLINK_CMD_PORT_PARAM_NEW,
8985
+ DEVLINK_CMD_PORT_PARAM_DEL);
8986
+}
8987
+EXPORT_SYMBOL_GPL(devlink_port_params_register);
8988
+
8989
+/**
8990
+ * devlink_port_params_unregister - unregister port configuration
8991
+ * parameters
8992
+ *
8993
+ * @devlink_port: devlink port
8994
+ * @params: configuration parameters array
8995
+ * @params_count: number of parameters provided
8996
+ */
8997
+void devlink_port_params_unregister(struct devlink_port *devlink_port,
8998
+ const struct devlink_param *params,
8999
+ size_t params_count)
9000
+{
9001
+ return __devlink_params_unregister(devlink_port->devlink,
9002
+ devlink_port->index,
9003
+ &devlink_port->param_list,
9004
+ params, params_count,
9005
+ DEVLINK_CMD_PORT_PARAM_DEL);
9006
+}
9007
+EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
9008
+
9009
+static int
9010
+__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
9011
+ union devlink_param_value *init_val)
9012
+{
9013
+ struct devlink_param_item *param_item;
9014
+
9015
+ param_item = devlink_param_find_by_id(param_list, param_id);
9016
+ if (!param_item)
9017
+ return -EINVAL;
9018
+
9019
+ if (!param_item->driverinit_value_valid ||
9020
+ !devlink_param_cmode_is_supported(param_item->param,
9021
+ DEVLINK_PARAM_CMODE_DRIVERINIT))
9022
+ return -EOPNOTSUPP;
9023
+
9024
+ if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
9025
+ strcpy(init_val->vstr, param_item->driverinit_value.vstr);
9026
+ else
9027
+ *init_val = param_item->driverinit_value;
9028
+
9029
+ return 0;
9030
+}
9031
+
9032
+static int
9033
+__devlink_param_driverinit_value_set(struct devlink *devlink,
9034
+ unsigned int port_index,
9035
+ struct list_head *param_list, u32 param_id,
9036
+ union devlink_param_value init_val,
9037
+ enum devlink_command cmd)
9038
+{
9039
+ struct devlink_param_item *param_item;
9040
+
9041
+ param_item = devlink_param_find_by_id(param_list, param_id);
9042
+ if (!param_item)
9043
+ return -EINVAL;
9044
+
9045
+ if (!devlink_param_cmode_is_supported(param_item->param,
9046
+ DEVLINK_PARAM_CMODE_DRIVERINIT))
9047
+ return -EOPNOTSUPP;
9048
+
9049
+ if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
9050
+ strcpy(param_item->driverinit_value.vstr, init_val.vstr);
9051
+ else
9052
+ param_item->driverinit_value = init_val;
9053
+ param_item->driverinit_value_valid = true;
9054
+
9055
+ devlink_param_notify(devlink, port_index, param_item, cmd);
9056
+ return 0;
9057
+}
45339058
45349059 /**
45359060 * devlink_param_driverinit_value_get - get configuration parameter
....@@ -4545,26 +9070,11 @@
45459070 int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
45469071 union devlink_param_value *init_val)
45479072 {
4548
- struct devlink_param_item *param_item;
4549
-
4550
- if (!devlink->ops || !devlink->ops->reload)
9073
+ if (!devlink_reload_supported(devlink->ops))
45519074 return -EOPNOTSUPP;
45529075
4553
- param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
4554
- if (!param_item)
4555
- return -EINVAL;
4556
-
4557
- if (!param_item->driverinit_value_valid ||
4558
- !devlink_param_cmode_is_supported(param_item->param,
4559
- DEVLINK_PARAM_CMODE_DRIVERINIT))
4560
- return -EOPNOTSUPP;
4561
-
4562
- if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
4563
- strcpy(init_val->vstr, param_item->driverinit_value.vstr);
4564
- else
4565
- *init_val = param_item->driverinit_value;
4566
-
4567
- return 0;
9076
+ return __devlink_param_driverinit_value_get(&devlink->param_list,
9077
+ param_id, init_val);
45689078 }
45699079 EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
45709080
....@@ -4583,26 +9093,61 @@
45839093 int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
45849094 union devlink_param_value init_val)
45859095 {
4586
- struct devlink_param_item *param_item;
4587
-
4588
- param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
4589
- if (!param_item)
4590
- return -EINVAL;
4591
-
4592
- if (!devlink_param_cmode_is_supported(param_item->param,
4593
- DEVLINK_PARAM_CMODE_DRIVERINIT))
4594
- return -EOPNOTSUPP;
4595
-
4596
- if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
4597
- strcpy(param_item->driverinit_value.vstr, init_val.vstr);
4598
- else
4599
- param_item->driverinit_value = init_val;
4600
- param_item->driverinit_value_valid = true;
4601
-
4602
- devlink_param_notify(devlink, param_item, DEVLINK_CMD_PARAM_NEW);
4603
- return 0;
9096
+ return __devlink_param_driverinit_value_set(devlink, 0,
9097
+ &devlink->param_list,
9098
+ param_id, init_val,
9099
+ DEVLINK_CMD_PARAM_NEW);
46049100 }
46059101 EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
9102
+
9103
+/**
9104
+ * devlink_port_param_driverinit_value_get - get configuration parameter
9105
+ * value for driver initializing
9106
+ *
9107
+ * @devlink_port: devlink_port
9108
+ * @param_id: parameter ID
9109
+ * @init_val: value of parameter in driverinit configuration mode
9110
+ *
9111
+ * This function should be used by the driver to get driverinit
9112
+ * configuration for initialization after reload command.
9113
+ */
9114
+int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
9115
+ u32 param_id,
9116
+ union devlink_param_value *init_val)
9117
+{
9118
+ struct devlink *devlink = devlink_port->devlink;
9119
+
9120
+ if (!devlink_reload_supported(devlink->ops))
9121
+ return -EOPNOTSUPP;
9122
+
9123
+ return __devlink_param_driverinit_value_get(&devlink_port->param_list,
9124
+ param_id, init_val);
9125
+}
9126
+EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
9127
+
9128
+/**
9129
+ * devlink_port_param_driverinit_value_set - set value of configuration
9130
+ * parameter for driverinit
9131
+ * configuration mode
9132
+ *
9133
+ * @devlink_port: devlink_port
9134
+ * @param_id: parameter ID
9135
+ * @init_val: value of parameter to set for driverinit configuration mode
9136
+ *
9137
+ * This function should be used by the driver to set driverinit
9138
+ * configuration mode default value.
9139
+ */
9140
+int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
9141
+ u32 param_id,
9142
+ union devlink_param_value init_val)
9143
+{
9144
+ return __devlink_param_driverinit_value_set(devlink_port->devlink,
9145
+ devlink_port->index,
9146
+ &devlink_port->param_list,
9147
+ param_id, init_val,
9148
+ DEVLINK_CMD_PORT_PARAM_NEW);
9149
+}
9150
+EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
46069151
46079152 /**
46089153 * devlink_param_value_changed - notify devlink on a parameter's value
....@@ -4615,7 +9160,6 @@
46159160 * This function should be used by the driver to notify devlink on value
46169161 * change, excluding driverinit configuration mode.
46179162 * For driverinit configuration mode driver should use the function
4618
- * devlink_param_driverinit_value_set() instead.
46199163 */
46209164 void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
46219165 {
....@@ -4624,9 +9168,36 @@
46249168 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
46259169 WARN_ON(!param_item);
46269170
4627
- devlink_param_notify(devlink, param_item, DEVLINK_CMD_PARAM_NEW);
9171
+ devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
46289172 }
46299173 EXPORT_SYMBOL_GPL(devlink_param_value_changed);
9174
+
9175
+/**
9176
+ * devlink_port_param_value_changed - notify devlink on a parameter's value
9177
+ * change. Should be called by the driver
9178
+ * right after the change.
9179
+ *
9180
+ * @devlink_port: devlink_port
9181
+ * @param_id: parameter ID
9182
+ *
9183
+ * This function should be used by the driver to notify devlink on value
9184
+ * change, excluding driverinit configuration mode.
9185
+ * For driverinit configuration mode driver should use the function
9186
+ * devlink_port_param_driverinit_value_set() instead.
9187
+ */
9188
+void devlink_port_param_value_changed(struct devlink_port *devlink_port,
9189
+ u32 param_id)
9190
+{
9191
+ struct devlink_param_item *param_item;
9192
+
9193
+ param_item = devlink_param_find_by_id(&devlink_port->param_list,
9194
+ param_id);
9195
+ WARN_ON(!param_item);
9196
+
9197
+ devlink_param_notify(devlink_port->devlink, devlink_port->index,
9198
+ param_item, DEVLINK_CMD_PORT_PARAM_NEW);
9199
+}
9200
+EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
46309201
46319202 /**
46329203 * devlink_param_value_str_fill - Safely fill-up the string preventing
....@@ -4649,21 +9220,24 @@
46499220 * devlink_region_create - create a new address region
46509221 *
46519222 * @devlink: devlink
4652
- * @region_name: region name
9223
+ * @ops: region operations and name
46539224 * @region_max_snapshots: Maximum supported number of snapshots for region
46549225 * @region_size: size of region
46559226 */
4656
-struct devlink_region *devlink_region_create(struct devlink *devlink,
4657
- const char *region_name,
4658
- u32 region_max_snapshots,
4659
- u64 region_size)
9227
+struct devlink_region *
9228
+devlink_region_create(struct devlink *devlink,
9229
+ const struct devlink_region_ops *ops,
9230
+ u32 region_max_snapshots, u64 region_size)
46609231 {
46619232 struct devlink_region *region;
46629233 int err = 0;
46639234
9235
+ if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
9236
+ return ERR_PTR(-EINVAL);
9237
+
46649238 mutex_lock(&devlink->lock);
46659239
4666
- if (devlink_region_get_by_name(devlink, region_name)) {
9240
+ if (devlink_region_get_by_name(devlink, ops->name)) {
46679241 err = -EEXIST;
46689242 goto unlock;
46699243 }
....@@ -4676,7 +9250,7 @@
46769250
46779251 region->devlink = devlink;
46789252 region->max_snapshots = region_max_snapshots;
4679
- region->name = region_name;
9253
+ region->ops = ops;
46809254 region->size = region_size;
46819255 INIT_LIST_HEAD(&region->snapshot_list);
46829256 list_add_tail(&region->list, &devlink->region_list);
....@@ -4692,6 +9266,57 @@
46929266 EXPORT_SYMBOL_GPL(devlink_region_create);
46939267
46949268 /**
9269
+ * devlink_port_region_create - create a new address region for a port
9270
+ *
9271
+ * @port: devlink port
9272
+ * @ops: region operations and name
9273
+ * @region_max_snapshots: Maximum supported number of snapshots for region
9274
+ * @region_size: size of region
9275
+ */
9276
+struct devlink_region *
9277
+devlink_port_region_create(struct devlink_port *port,
9278
+ const struct devlink_port_region_ops *ops,
9279
+ u32 region_max_snapshots, u64 region_size)
9280
+{
9281
+ struct devlink *devlink = port->devlink;
9282
+ struct devlink_region *region;
9283
+ int err = 0;
9284
+
9285
+ if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
9286
+ return ERR_PTR(-EINVAL);
9287
+
9288
+ mutex_lock(&devlink->lock);
9289
+
9290
+ if (devlink_port_region_get_by_name(port, ops->name)) {
9291
+ err = -EEXIST;
9292
+ goto unlock;
9293
+ }
9294
+
9295
+ region = kzalloc(sizeof(*region), GFP_KERNEL);
9296
+ if (!region) {
9297
+ err = -ENOMEM;
9298
+ goto unlock;
9299
+ }
9300
+
9301
+ region->devlink = devlink;
9302
+ region->port = port;
9303
+ region->max_snapshots = region_max_snapshots;
9304
+ region->port_ops = ops;
9305
+ region->size = region_size;
9306
+ INIT_LIST_HEAD(&region->snapshot_list);
9307
+ list_add_tail(&region->list, &port->region_list);
9308
+ devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
9309
+
9310
+ mutex_unlock(&devlink->lock);
9311
+ return region;
9312
+
9313
+unlock:
9314
+ mutex_unlock(&devlink->lock);
9315
+ return ERR_PTR(err);
9316
+}
9317
+EXPORT_SYMBOL_GPL(devlink_port_region_create);
9318
+
9319
+/**
46959320 * devlink_region_destroy - destroy address region
46969321 *
46979322 * @region: devlink region to destroy
....@@ -4705,7 +9330,7 @@
47059330
47069331 /* Free all snapshots of region */
47079332 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
4708
- devlink_region_snapshot_del(snapshot);
9333
+ devlink_region_snapshot_del(region, snapshot);
47099334
47109335 list_del(&region->list);
47119336
....@@ -4716,101 +9341,1013 @@
47169341 EXPORT_SYMBOL_GPL(devlink_region_destroy);
47179342
47189343 /**
4719
- * devlink_region_shapshot_id_get - get snapshot ID
9344
+ * devlink_region_snapshot_id_get - get snapshot ID
47209345 *
47219346 * This callback should be called when adding a new snapshot,
47229347 * Driver should use the same id for multiple snapshots taken
47239348 * on multiple regions at the same time/by the same trigger.
47249349 *
9350
+ * The caller of this function must use devlink_region_snapshot_id_put
9351
+ * when finished creating regions using this id.
9352
+ *
9353
+ * Returns zero on success, or a negative error code on failure.
9354
+ *
47259355 * @devlink: devlink
9356
+ * @id: storage to return id
47269357 */
4727
-u32 devlink_region_shapshot_id_get(struct devlink *devlink)
9358
+int devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
47289359 {
4729
- u32 id;
9360
+ int err;
47309361
47319362 mutex_lock(&devlink->lock);
4732
- id = ++devlink->snapshot_id;
9363
+ err = __devlink_region_snapshot_id_get(devlink, id);
47339364 mutex_unlock(&devlink->lock);
47349365
4735
- return id;
9366
+ return err;
47369367 }
4737
-EXPORT_SYMBOL_GPL(devlink_region_shapshot_id_get);
9368
+EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_get);
9369
+
9370
+/**
9371
+ * devlink_region_snapshot_id_put - put snapshot ID reference
9372
+ *
9373
+ * This should be called by a driver after finishing creating snapshots
9374
+ * with an id. Doing so ensures that the ID can later be released in the
9375
+ * event that all snapshots using it have been destroyed.
9376
+ *
9377
+ * @devlink: devlink
9378
+ * @id: id to release reference on
9379
+ */
9380
+void devlink_region_snapshot_id_put(struct devlink *devlink, u32 id)
9381
+{
9382
+ mutex_lock(&devlink->lock);
9383
+ __devlink_snapshot_id_decrement(devlink, id);
9384
+ mutex_unlock(&devlink->lock);
9385
+}
9386
+EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_put);
47389387
47399388 /**
47409389 * devlink_region_snapshot_create - create a new snapshot
47419390 * This will add a new snapshot of a region. The snapshot
47429391 * will be stored on the region struct and can be accessed
4743
- * from devlink. This is useful for future analyses of snapshots.
9392
+ * from devlink. This is useful for future analyses of snapshots.
47449393 * Multiple snapshots can be created on a region.
47459394 * The @snapshot_id should be obtained using the getter function.
47469395 *
4747
- * @devlink_region: devlink region of the snapshot
4748
- * @data_len: size of snapshot data
9396
+ * @region: devlink region of the snapshot
47499397 * @data: snapshot data
47509398 * @snapshot_id: snapshot id to be created
4751
- * @data_destructor: pointer to destructor function to free data
47529399 */
4753
-int devlink_region_snapshot_create(struct devlink_region *region, u64 data_len,
4754
- u8 *data, u32 snapshot_id,
4755
- devlink_snapshot_data_dest_t *data_destructor)
9400
+int devlink_region_snapshot_create(struct devlink_region *region,
9401
+ u8 *data, u32 snapshot_id)
47569402 {
47579403 struct devlink *devlink = region->devlink;
4758
- struct devlink_snapshot *snapshot;
47599404 int err;
47609405
47619406 mutex_lock(&devlink->lock);
4762
-
4763
- /* check if region can hold one more snapshot */
4764
- if (region->cur_snapshots == region->max_snapshots) {
4765
- err = -ENOMEM;
4766
- goto unlock;
4767
- }
4768
-
4769
- if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
4770
- err = -EEXIST;
4771
- goto unlock;
4772
- }
4773
-
4774
- snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
4775
- if (!snapshot) {
4776
- err = -ENOMEM;
4777
- goto unlock;
4778
- }
4779
-
4780
- snapshot->id = snapshot_id;
4781
- snapshot->region = region;
4782
- snapshot->data = data;
4783
- snapshot->data_len = data_len;
4784
- snapshot->data_destructor = data_destructor;
4785
-
4786
- list_add_tail(&snapshot->list, &region->snapshot_list);
4787
-
4788
- region->cur_snapshots++;
4789
-
4790
- devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
9407
+ err = __devlink_region_snapshot_create(region, data, snapshot_id);
47919408 mutex_unlock(&devlink->lock);
4792
- return 0;
47939409
4794
-unlock:
4795
- mutex_unlock(&devlink->lock);
47969410 return err;
47979411 }
47989412 EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
47999413
4800
-static int __init devlink_module_init(void)
9414
+#define DEVLINK_TRAP(_id, _type) \
9415
+ { \
9416
+ .type = DEVLINK_TRAP_TYPE_##_type, \
9417
+ .id = DEVLINK_TRAP_GENERIC_ID_##_id, \
9418
+ .name = DEVLINK_TRAP_GENERIC_NAME_##_id, \
9419
+ }
9420
+
9421
+static const struct devlink_trap devlink_trap_generic[] = {
9422
+ DEVLINK_TRAP(SMAC_MC, DROP),
9423
+ DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
9424
+ DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
9425
+ DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
9426
+ DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
9427
+ DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
9428
+ DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
9429
+ DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
9430
+ DEVLINK_TRAP(TAIL_DROP, DROP),
9431
+ DEVLINK_TRAP(NON_IP_PACKET, DROP),
9432
+ DEVLINK_TRAP(UC_DIP_MC_DMAC, DROP),
9433
+ DEVLINK_TRAP(DIP_LB, DROP),
9434
+ DEVLINK_TRAP(SIP_MC, DROP),
9435
+ DEVLINK_TRAP(SIP_LB, DROP),
9436
+ DEVLINK_TRAP(CORRUPTED_IP_HDR, DROP),
9437
+ DEVLINK_TRAP(IPV4_SIP_BC, DROP),
9438
+ DEVLINK_TRAP(IPV6_MC_DIP_RESERVED_SCOPE, DROP),
9439
+ DEVLINK_TRAP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, DROP),
9440
+ DEVLINK_TRAP(MTU_ERROR, EXCEPTION),
9441
+ DEVLINK_TRAP(UNRESOLVED_NEIGH, EXCEPTION),
9442
+ DEVLINK_TRAP(RPF, EXCEPTION),
9443
+ DEVLINK_TRAP(REJECT_ROUTE, EXCEPTION),
9444
+ DEVLINK_TRAP(IPV4_LPM_UNICAST_MISS, EXCEPTION),
9445
+ DEVLINK_TRAP(IPV6_LPM_UNICAST_MISS, EXCEPTION),
9446
+ DEVLINK_TRAP(NON_ROUTABLE, DROP),
9447
+ DEVLINK_TRAP(DECAP_ERROR, EXCEPTION),
9448
+ DEVLINK_TRAP(OVERLAY_SMAC_MC, DROP),
9449
+ DEVLINK_TRAP(INGRESS_FLOW_ACTION_DROP, DROP),
9450
+ DEVLINK_TRAP(EGRESS_FLOW_ACTION_DROP, DROP),
9451
+ DEVLINK_TRAP(STP, CONTROL),
9452
+ DEVLINK_TRAP(LACP, CONTROL),
9453
+ DEVLINK_TRAP(LLDP, CONTROL),
9454
+ DEVLINK_TRAP(IGMP_QUERY, CONTROL),
9455
+ DEVLINK_TRAP(IGMP_V1_REPORT, CONTROL),
9456
+ DEVLINK_TRAP(IGMP_V2_REPORT, CONTROL),
9457
+ DEVLINK_TRAP(IGMP_V3_REPORT, CONTROL),
9458
+ DEVLINK_TRAP(IGMP_V2_LEAVE, CONTROL),
9459
+ DEVLINK_TRAP(MLD_QUERY, CONTROL),
9460
+ DEVLINK_TRAP(MLD_V1_REPORT, CONTROL),
9461
+ DEVLINK_TRAP(MLD_V2_REPORT, CONTROL),
9462
+ DEVLINK_TRAP(MLD_V1_DONE, CONTROL),
9463
+ DEVLINK_TRAP(IPV4_DHCP, CONTROL),
9464
+ DEVLINK_TRAP(IPV6_DHCP, CONTROL),
9465
+ DEVLINK_TRAP(ARP_REQUEST, CONTROL),
9466
+ DEVLINK_TRAP(ARP_RESPONSE, CONTROL),
9467
+ DEVLINK_TRAP(ARP_OVERLAY, CONTROL),
9468
+ DEVLINK_TRAP(IPV6_NEIGH_SOLICIT, CONTROL),
9469
+ DEVLINK_TRAP(IPV6_NEIGH_ADVERT, CONTROL),
9470
+ DEVLINK_TRAP(IPV4_BFD, CONTROL),
9471
+ DEVLINK_TRAP(IPV6_BFD, CONTROL),
9472
+ DEVLINK_TRAP(IPV4_OSPF, CONTROL),
9473
+ DEVLINK_TRAP(IPV6_OSPF, CONTROL),
9474
+ DEVLINK_TRAP(IPV4_BGP, CONTROL),
9475
+ DEVLINK_TRAP(IPV6_BGP, CONTROL),
9476
+ DEVLINK_TRAP(IPV4_VRRP, CONTROL),
9477
+ DEVLINK_TRAP(IPV6_VRRP, CONTROL),
9478
+ DEVLINK_TRAP(IPV4_PIM, CONTROL),
9479
+ DEVLINK_TRAP(IPV6_PIM, CONTROL),
9480
+ DEVLINK_TRAP(UC_LB, CONTROL),
9481
+ DEVLINK_TRAP(LOCAL_ROUTE, CONTROL),
9482
+ DEVLINK_TRAP(EXTERNAL_ROUTE, CONTROL),
9483
+ DEVLINK_TRAP(IPV6_UC_DIP_LINK_LOCAL_SCOPE, CONTROL),
9484
+ DEVLINK_TRAP(IPV6_DIP_ALL_NODES, CONTROL),
9485
+ DEVLINK_TRAP(IPV6_DIP_ALL_ROUTERS, CONTROL),
9486
+ DEVLINK_TRAP(IPV6_ROUTER_SOLICIT, CONTROL),
9487
+ DEVLINK_TRAP(IPV6_ROUTER_ADVERT, CONTROL),
9488
+ DEVLINK_TRAP(IPV6_REDIRECT, CONTROL),
9489
+ DEVLINK_TRAP(IPV4_ROUTER_ALERT, CONTROL),
9490
+ DEVLINK_TRAP(IPV6_ROUTER_ALERT, CONTROL),
9491
+ DEVLINK_TRAP(PTP_EVENT, CONTROL),
9492
+ DEVLINK_TRAP(PTP_GENERAL, CONTROL),
9493
+ DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL),
9494
+ DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL),
9495
+ DEVLINK_TRAP(EARLY_DROP, DROP),
9496
+ DEVLINK_TRAP(VXLAN_PARSING, DROP),
9497
+ DEVLINK_TRAP(LLC_SNAP_PARSING, DROP),
9498
+ DEVLINK_TRAP(VLAN_PARSING, DROP),
9499
+ DEVLINK_TRAP(PPPOE_PPP_PARSING, DROP),
9500
+ DEVLINK_TRAP(MPLS_PARSING, DROP),
9501
+ DEVLINK_TRAP(ARP_PARSING, DROP),
9502
+ DEVLINK_TRAP(IP_1_PARSING, DROP),
9503
+ DEVLINK_TRAP(IP_N_PARSING, DROP),
9504
+ DEVLINK_TRAP(GRE_PARSING, DROP),
9505
+ DEVLINK_TRAP(UDP_PARSING, DROP),
9506
+ DEVLINK_TRAP(TCP_PARSING, DROP),
9507
+ DEVLINK_TRAP(IPSEC_PARSING, DROP),
9508
+ DEVLINK_TRAP(SCTP_PARSING, DROP),
9509
+ DEVLINK_TRAP(DCCP_PARSING, DROP),
9510
+ DEVLINK_TRAP(GTP_PARSING, DROP),
9511
+ DEVLINK_TRAP(ESP_PARSING, DROP),
9512
+};
9513
+
9514
+#define DEVLINK_TRAP_GROUP(_id) \
9515
+ { \
9516
+ .id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \
9517
+ .name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \
9518
+ }
9519
+
9520
+static const struct devlink_trap_group devlink_trap_group_generic[] = {
9521
+ DEVLINK_TRAP_GROUP(L2_DROPS),
9522
+ DEVLINK_TRAP_GROUP(L3_DROPS),
9523
+ DEVLINK_TRAP_GROUP(L3_EXCEPTIONS),
9524
+ DEVLINK_TRAP_GROUP(BUFFER_DROPS),
9525
+ DEVLINK_TRAP_GROUP(TUNNEL_DROPS),
9526
+ DEVLINK_TRAP_GROUP(ACL_DROPS),
9527
+ DEVLINK_TRAP_GROUP(STP),
9528
+ DEVLINK_TRAP_GROUP(LACP),
9529
+ DEVLINK_TRAP_GROUP(LLDP),
9530
+ DEVLINK_TRAP_GROUP(MC_SNOOPING),
9531
+ DEVLINK_TRAP_GROUP(DHCP),
9532
+ DEVLINK_TRAP_GROUP(NEIGH_DISCOVERY),
9533
+ DEVLINK_TRAP_GROUP(BFD),
9534
+ DEVLINK_TRAP_GROUP(OSPF),
9535
+ DEVLINK_TRAP_GROUP(BGP),
9536
+ DEVLINK_TRAP_GROUP(VRRP),
9537
+ DEVLINK_TRAP_GROUP(PIM),
9538
+ DEVLINK_TRAP_GROUP(UC_LB),
9539
+ DEVLINK_TRAP_GROUP(LOCAL_DELIVERY),
9540
+ DEVLINK_TRAP_GROUP(EXTERNAL_DELIVERY),
9541
+ DEVLINK_TRAP_GROUP(IPV6),
9542
+ DEVLINK_TRAP_GROUP(PTP_EVENT),
9543
+ DEVLINK_TRAP_GROUP(PTP_GENERAL),
9544
+ DEVLINK_TRAP_GROUP(ACL_SAMPLE),
9545
+ DEVLINK_TRAP_GROUP(ACL_TRAP),
9546
+ DEVLINK_TRAP_GROUP(PARSER_ERROR_DROPS),
9547
+};
9548
+
9549
+static int devlink_trap_generic_verify(const struct devlink_trap *trap)
48019550 {
4802
- return genl_register_family(&devlink_nl_family);
9551
+ if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
9552
+ return -EINVAL;
9553
+
9554
+ if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
9555
+ return -EINVAL;
9556
+
9557
+ if (trap->type != devlink_trap_generic[trap->id].type)
9558
+ return -EINVAL;
9559
+
9560
+ return 0;
48039561 }
48049562
4805
-static void __exit devlink_module_exit(void)
9563
+static int devlink_trap_driver_verify(const struct devlink_trap *trap)
48069564 {
4807
- genl_unregister_family(&devlink_nl_family);
9565
+ int i;
9566
+
9567
+ if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
9568
+ return -EINVAL;
9569
+
9570
+ for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
9571
+ if (!strcmp(trap->name, devlink_trap_generic[i].name))
9572
+ return -EEXIST;
9573
+ }
9574
+
9575
+ return 0;
48089576 }
48099577
4810
-module_init(devlink_module_init);
4811
-module_exit(devlink_module_exit);
9578
+static int devlink_trap_verify(const struct devlink_trap *trap)
9579
+{
9580
+ if (!trap || !trap->name)
9581
+ return -EINVAL;
48129582
4813
-MODULE_LICENSE("GPL v2");
4814
-MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
4815
-MODULE_DESCRIPTION("Network physical device Netlink interface");
4816
-MODULE_ALIAS_GENL_FAMILY(DEVLINK_GENL_NAME);
9583
+ if (trap->generic)
9584
+ return devlink_trap_generic_verify(trap);
9585
+ else
9586
+ return devlink_trap_driver_verify(trap);
9587
+}
9588
+
9589
+static int
9590
+devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
9591
+{
9592
+ if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
9593
+ return -EINVAL;
9594
+
9595
+ if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
9596
+ return -EINVAL;
9597
+
9598
+ return 0;
9599
+}
9600
+
9601
+static int
9602
+devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
9603
+{
9604
+ int i;
9605
+
9606
+ if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
9607
+ return -EINVAL;
9608
+
9609
+ for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
9610
+ if (!strcmp(group->name, devlink_trap_group_generic[i].name))
9611
+ return -EEXIST;
9612
+ }
9613
+
9614
+ return 0;
9615
+}
9616
+
9617
+static int devlink_trap_group_verify(const struct devlink_trap_group *group)
9618
+{
9619
+ if (group->generic)
9620
+ return devlink_trap_group_generic_verify(group);
9621
+ else
9622
+ return devlink_trap_group_driver_verify(group);
9623
+}
9624
+
9625
+static void
9626
+devlink_trap_group_notify(struct devlink *devlink,
9627
+ const struct devlink_trap_group_item *group_item,
9628
+ enum devlink_command cmd)
9629
+{
9630
+ struct sk_buff *msg;
9631
+ int err;
9632
+
9633
+ WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
9634
+ cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
9635
+
9636
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9637
+ if (!msg)
9638
+ return;
9639
+
9640
+ err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
9641
+ 0);
9642
+ if (err) {
9643
+ nlmsg_free(msg);
9644
+ return;
9645
+ }
9646
+
9647
+ genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
9648
+ msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
9649
+}
9650
+
9651
+static int
9652
+devlink_trap_item_group_link(struct devlink *devlink,
9653
+ struct devlink_trap_item *trap_item)
9654
+{
9655
+ u16 group_id = trap_item->trap->init_group_id;
9656
+ struct devlink_trap_group_item *group_item;
9657
+
9658
+ group_item = devlink_trap_group_item_lookup_by_id(devlink, group_id);
9659
+ if (WARN_ON_ONCE(!group_item))
9660
+ return -EINVAL;
9661
+
9662
+ trap_item->group_item = group_item;
9663
+
9664
+ return 0;
9665
+}
9666
+
9667
+static void devlink_trap_notify(struct devlink *devlink,
9668
+ const struct devlink_trap_item *trap_item,
9669
+ enum devlink_command cmd)
9670
+{
9671
+ struct sk_buff *msg;
9672
+ int err;
9673
+
9674
+ WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
9675
+ cmd != DEVLINK_CMD_TRAP_DEL);
9676
+
9677
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9678
+ if (!msg)
9679
+ return;
9680
+
9681
+ err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
9682
+ if (err) {
9683
+ nlmsg_free(msg);
9684
+ return;
9685
+ }
9686
+
9687
+ genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
9688
+ msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
9689
+}
9690
+
9691
+static int
9692
+devlink_trap_register(struct devlink *devlink,
9693
+ const struct devlink_trap *trap, void *priv)
9694
+{
9695
+ struct devlink_trap_item *trap_item;
9696
+ int err;
9697
+
9698
+ if (devlink_trap_item_lookup(devlink, trap->name))
9699
+ return -EEXIST;
9700
+
9701
+ trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
9702
+ if (!trap_item)
9703
+ return -ENOMEM;
9704
+
9705
+ trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
9706
+ if (!trap_item->stats) {
9707
+ err = -ENOMEM;
9708
+ goto err_stats_alloc;
9709
+ }
9710
+
9711
+ trap_item->trap = trap;
9712
+ trap_item->action = trap->init_action;
9713
+ trap_item->priv = priv;
9714
+
9715
+ err = devlink_trap_item_group_link(devlink, trap_item);
9716
+ if (err)
9717
+ goto err_group_link;
9718
+
9719
+ err = devlink->ops->trap_init(devlink, trap, trap_item);
9720
+ if (err)
9721
+ goto err_trap_init;
9722
+
9723
+ list_add_tail(&trap_item->list, &devlink->trap_list);
9724
+ devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
9725
+
9726
+ return 0;
9727
+
9728
+err_trap_init:
9729
+err_group_link:
9730
+ free_percpu(trap_item->stats);
9731
+err_stats_alloc:
9732
+ kfree(trap_item);
9733
+ return err;
9734
+}
9735
+
9736
+static void devlink_trap_unregister(struct devlink *devlink,
9737
+ const struct devlink_trap *trap)
9738
+{
9739
+ struct devlink_trap_item *trap_item;
9740
+
9741
+ trap_item = devlink_trap_item_lookup(devlink, trap->name);
9742
+ if (WARN_ON_ONCE(!trap_item))
9743
+ return;
9744
+
9745
+ devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
9746
+ list_del(&trap_item->list);
9747
+ if (devlink->ops->trap_fini)
9748
+ devlink->ops->trap_fini(devlink, trap, trap_item);
9749
+ free_percpu(trap_item->stats);
9750
+ kfree(trap_item);
9751
+}
9752
+
9753
+static void devlink_trap_disable(struct devlink *devlink,
9754
+ const struct devlink_trap *trap)
9755
+{
9756
+ struct devlink_trap_item *trap_item;
9757
+
9758
+ trap_item = devlink_trap_item_lookup(devlink, trap->name);
9759
+ if (WARN_ON_ONCE(!trap_item))
9760
+ return;
9761
+
9762
+ devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP,
9763
+ NULL);
9764
+ trap_item->action = DEVLINK_TRAP_ACTION_DROP;
9765
+}
9766
+
9767
+/**
9768
+ * devlink_traps_register - Register packet traps with devlink.
9769
+ * @devlink: devlink.
9770
+ * @traps: Packet traps.
9771
+ * @traps_count: Count of provided packet traps.
9772
+ * @priv: Driver private information.
9773
+ *
9774
+ * Return: Non-zero value on failure.
9775
+ */
9776
+int devlink_traps_register(struct devlink *devlink,
9777
+ const struct devlink_trap *traps,
9778
+ size_t traps_count, void *priv)
9779
+{
9780
+ int i, err;
9781
+
9782
+ if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
9783
+ return -EINVAL;
9784
+
9785
+ mutex_lock(&devlink->lock);
9786
+ for (i = 0; i < traps_count; i++) {
9787
+ const struct devlink_trap *trap = &traps[i];
9788
+
9789
+ err = devlink_trap_verify(trap);
9790
+ if (err)
9791
+ goto err_trap_verify;
9792
+
9793
+ err = devlink_trap_register(devlink, trap, priv);
9794
+ if (err)
9795
+ goto err_trap_register;
9796
+ }
9797
+ mutex_unlock(&devlink->lock);
9798
+
9799
+ return 0;
9800
+
9801
+err_trap_register:
9802
+err_trap_verify:
9803
+ for (i--; i >= 0; i--)
9804
+ devlink_trap_unregister(devlink, &traps[i]);
9805
+ mutex_unlock(&devlink->lock);
9806
+ return err;
9807
+}
9808
+EXPORT_SYMBOL_GPL(devlink_traps_register);
9809
+
9810
+/**
9811
+ * devlink_traps_unregister - Unregister packet traps from devlink.
9812
+ * @devlink: devlink.
9813
+ * @traps: Packet traps.
9814
+ * @traps_count: Count of provided packet traps.
9815
+ */
9816
+void devlink_traps_unregister(struct devlink *devlink,
9817
+ const struct devlink_trap *traps,
9818
+ size_t traps_count)
9819
+{
9820
+ int i;
9821
+
9822
+ mutex_lock(&devlink->lock);
9823
+ /* Make sure we do not have any packets in-flight while unregistering
9824
+ * traps by disabling all of them and waiting for a grace period.
9825
+ */
9826
+ for (i = traps_count - 1; i >= 0; i--)
9827
+ devlink_trap_disable(devlink, &traps[i]);
9828
+ synchronize_rcu();
9829
+ for (i = traps_count - 1; i >= 0; i--)
9830
+ devlink_trap_unregister(devlink, &traps[i]);
9831
+ mutex_unlock(&devlink->lock);
9832
+}
9833
+EXPORT_SYMBOL_GPL(devlink_traps_unregister);
9834
+
9835
+static void
9836
+devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
9837
+ size_t skb_len)
9838
+{
9839
+ struct devlink_stats *stats;
9840
+
9841
+ stats = this_cpu_ptr(trap_stats);
9842
+ u64_stats_update_begin(&stats->syncp);
9843
+ stats->rx_bytes += skb_len;
9844
+ stats->rx_packets++;
9845
+ u64_stats_update_end(&stats->syncp);
9846
+}
9847
+
9848
+static void
9849
+devlink_trap_report_metadata_set(struct devlink_trap_metadata *metadata,
9850
+ const struct devlink_trap_item *trap_item,
9851
+ struct devlink_port *in_devlink_port,
9852
+ const struct flow_action_cookie *fa_cookie)
9853
+{
9854
+ metadata->trap_name = trap_item->trap->name;
9855
+ metadata->trap_group_name = trap_item->group_item->group->name;
9856
+ metadata->fa_cookie = fa_cookie;
9857
+ metadata->trap_type = trap_item->trap->type;
9858
+
9859
+ spin_lock(&in_devlink_port->type_lock);
9860
+ if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
9861
+ metadata->input_dev = in_devlink_port->type_dev;
9862
+ spin_unlock(&in_devlink_port->type_lock);
9863
+}
9864
+
9865
+/**
9866
+ * devlink_trap_report - Report trapped packet to drop monitor.
9867
+ * @devlink: devlink.
9868
+ * @skb: Trapped packet.
9869
+ * @trap_ctx: Trap context.
9870
+ * @in_devlink_port: Input devlink port.
9871
+ * @fa_cookie: Flow action cookie. Could be NULL.
9872
+ */
9873
+void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
9874
+ void *trap_ctx, struct devlink_port *in_devlink_port,
9875
+ const struct flow_action_cookie *fa_cookie)
9876
+
9877
+{
9878
+ struct devlink_trap_item *trap_item = trap_ctx;
9879
+
9880
+ devlink_trap_stats_update(trap_item->stats, skb->len);
9881
+ devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
9882
+
9883
+ if (trace_devlink_trap_report_enabled()) {
9884
+ struct devlink_trap_metadata metadata = {};
9885
+
9886
+ devlink_trap_report_metadata_set(&metadata, trap_item,
9887
+ in_devlink_port, fa_cookie);
9888
+ trace_devlink_trap_report(devlink, skb, &metadata);
9889
+ }
9890
+}
9891
+EXPORT_SYMBOL_GPL(devlink_trap_report);
9892
+
9893
+/**
9894
+ * devlink_trap_ctx_priv - Trap context to driver private information.
9895
+ * @trap_ctx: Trap context.
9896
+ *
9897
+ * Return: Driver private information passed during registration.
9898
+ */
9899
+void *devlink_trap_ctx_priv(void *trap_ctx)
9900
+{
9901
+ struct devlink_trap_item *trap_item = trap_ctx;
9902
+
9903
+ return trap_item->priv;
9904
+}
9905
+EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
9906
+
9907
+static int
9908
+devlink_trap_group_item_policer_link(struct devlink *devlink,
9909
+ struct devlink_trap_group_item *group_item)
9910
+{
9911
+ u32 policer_id = group_item->group->init_policer_id;
9912
+ struct devlink_trap_policer_item *policer_item;
9913
+
9914
+ if (policer_id == 0)
9915
+ return 0;
9916
+
9917
+ policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
9918
+ if (WARN_ON_ONCE(!policer_item))
9919
+ return -EINVAL;
9920
+
9921
+ group_item->policer_item = policer_item;
9922
+
9923
+ return 0;
9924
+}
9925
+
9926
+static int
9927
+devlink_trap_group_register(struct devlink *devlink,
9928
+ const struct devlink_trap_group *group)
9929
+{
9930
+ struct devlink_trap_group_item *group_item;
9931
+ int err;
9932
+
9933
+ if (devlink_trap_group_item_lookup(devlink, group->name))
9934
+ return -EEXIST;
9935
+
9936
+ group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
9937
+ if (!group_item)
9938
+ return -ENOMEM;
9939
+
9940
+ group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
9941
+ if (!group_item->stats) {
9942
+ err = -ENOMEM;
9943
+ goto err_stats_alloc;
9944
+ }
9945
+
9946
+ group_item->group = group;
9947
+
9948
+ err = devlink_trap_group_item_policer_link(devlink, group_item);
9949
+ if (err)
9950
+ goto err_policer_link;
9951
+
9952
+ if (devlink->ops->trap_group_init) {
9953
+ err = devlink->ops->trap_group_init(devlink, group);
9954
+ if (err)
9955
+ goto err_group_init;
9956
+ }
9957
+
9958
+ list_add_tail(&group_item->list, &devlink->trap_group_list);
9959
+ devlink_trap_group_notify(devlink, group_item,
9960
+ DEVLINK_CMD_TRAP_GROUP_NEW);
9961
+
9962
+ return 0;
9963
+
9964
+err_group_init:
9965
+err_policer_link:
9966
+ free_percpu(group_item->stats);
9967
+err_stats_alloc:
9968
+ kfree(group_item);
9969
+ return err;
9970
+}
9971
+
9972
+static void
9973
+devlink_trap_group_unregister(struct devlink *devlink,
9974
+ const struct devlink_trap_group *group)
9975
+{
9976
+ struct devlink_trap_group_item *group_item;
9977
+
9978
+ group_item = devlink_trap_group_item_lookup(devlink, group->name);
9979
+ if (WARN_ON_ONCE(!group_item))
9980
+ return;
9981
+
9982
+ devlink_trap_group_notify(devlink, group_item,
9983
+ DEVLINK_CMD_TRAP_GROUP_DEL);
9984
+ list_del(&group_item->list);
9985
+ free_percpu(group_item->stats);
9986
+ kfree(group_item);
9987
+}
9988
+
9989
+/**
9990
+ * devlink_trap_groups_register - Register packet trap groups with devlink.
9991
+ * @devlink: devlink.
9992
+ * @groups: Packet trap groups.
9993
+ * @groups_count: Count of provided packet trap groups.
9994
+ *
9995
+ * Return: Non-zero value on failure.
9996
+ */
9997
+int devlink_trap_groups_register(struct devlink *devlink,
9998
+ const struct devlink_trap_group *groups,
9999
+ size_t groups_count)
10000
+{
10001
+ int i, err;
10002
+
10003
+ mutex_lock(&devlink->lock);
10004
+ for (i = 0; i < groups_count; i++) {
10005
+ const struct devlink_trap_group *group = &groups[i];
10006
+
10007
+ err = devlink_trap_group_verify(group);
10008
+ if (err)
10009
+ goto err_trap_group_verify;
10010
+
10011
+ err = devlink_trap_group_register(devlink, group);
10012
+ if (err)
10013
+ goto err_trap_group_register;
10014
+ }
10015
+ mutex_unlock(&devlink->lock);
10016
+
10017
+ return 0;
10018
+
10019
+err_trap_group_register:
10020
+err_trap_group_verify:
10021
+ for (i--; i >= 0; i--)
10022
+ devlink_trap_group_unregister(devlink, &groups[i]);
10023
+ mutex_unlock(&devlink->lock);
10024
+ return err;
10025
+}
10026
+EXPORT_SYMBOL_GPL(devlink_trap_groups_register);
10027
+
10028
+/**
10029
+ * devlink_trap_groups_unregister - Unregister packet trap groups from devlink.
10030
+ * @devlink: devlink.
10031
+ * @groups: Packet trap groups.
10032
+ * @groups_count: Count of provided packet trap groups.
10033
+ */
10034
+void devlink_trap_groups_unregister(struct devlink *devlink,
10035
+ const struct devlink_trap_group *groups,
10036
+ size_t groups_count)
10037
+{
10038
+ int i;
10039
+
10040
+ mutex_lock(&devlink->lock);
10041
+ for (i = groups_count - 1; i >= 0; i--)
10042
+ devlink_trap_group_unregister(devlink, &groups[i]);
10043
+ mutex_unlock(&devlink->lock);
10044
+}
10045
+EXPORT_SYMBOL_GPL(devlink_trap_groups_unregister);
10046
+
10047
+static void
10048
+devlink_trap_policer_notify(struct devlink *devlink,
10049
+ const struct devlink_trap_policer_item *policer_item,
10050
+ enum devlink_command cmd)
10051
+{
10052
+ struct sk_buff *msg;
10053
+ int err;
10054
+
10055
+ WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_POLICER_NEW &&
10056
+ cmd != DEVLINK_CMD_TRAP_POLICER_DEL);
10057
+
10058
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10059
+ if (!msg)
10060
+ return;
10061
+
10062
+ err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, cmd, 0,
10063
+ 0, 0);
10064
+ if (err) {
10065
+ nlmsg_free(msg);
10066
+ return;
10067
+ }
10068
+
10069
+ genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
10070
+ msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
10071
+}
10072
+
10073
+static int
10074
+devlink_trap_policer_register(struct devlink *devlink,
10075
+ const struct devlink_trap_policer *policer)
10076
+{
10077
+ struct devlink_trap_policer_item *policer_item;
10078
+ int err;
10079
+
10080
+ if (devlink_trap_policer_item_lookup(devlink, policer->id))
10081
+ return -EEXIST;
10082
+
10083
+ policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL);
10084
+ if (!policer_item)
10085
+ return -ENOMEM;
10086
+
10087
+ policer_item->policer = policer;
10088
+ policer_item->rate = policer->init_rate;
10089
+ policer_item->burst = policer->init_burst;
10090
+
10091
+ if (devlink->ops->trap_policer_init) {
10092
+ err = devlink->ops->trap_policer_init(devlink, policer);
10093
+ if (err)
10094
+ goto err_policer_init;
10095
+ }
10096
+
10097
+ list_add_tail(&policer_item->list, &devlink->trap_policer_list);
10098
+ devlink_trap_policer_notify(devlink, policer_item,
10099
+ DEVLINK_CMD_TRAP_POLICER_NEW);
10100
+
10101
+ return 0;
10102
+
10103
+err_policer_init:
10104
+ kfree(policer_item);
10105
+ return err;
10106
+}
10107
+
10108
+static void
10109
+devlink_trap_policer_unregister(struct devlink *devlink,
10110
+ const struct devlink_trap_policer *policer)
10111
+{
10112
+ struct devlink_trap_policer_item *policer_item;
10113
+
10114
+ policer_item = devlink_trap_policer_item_lookup(devlink, policer->id);
10115
+ if (WARN_ON_ONCE(!policer_item))
10116
+ return;
10117
+
10118
+ devlink_trap_policer_notify(devlink, policer_item,
10119
+ DEVLINK_CMD_TRAP_POLICER_DEL);
10120
+ list_del(&policer_item->list);
10121
+ if (devlink->ops->trap_policer_fini)
10122
+ devlink->ops->trap_policer_fini(devlink, policer);
10123
+ kfree(policer_item);
10124
+}
10125
+
10126
+/**
10127
+ * devlink_trap_policers_register - Register packet trap policers with devlink.
10128
+ * @devlink: devlink.
10129
+ * @policers: Packet trap policers.
10130
+ * @policers_count: Count of provided packet trap policers.
10131
+ *
10132
+ * Return: Non-zero value on failure.
10133
+ */
10134
+int
10135
+devlink_trap_policers_register(struct devlink *devlink,
10136
+ const struct devlink_trap_policer *policers,
10137
+ size_t policers_count)
10138
+{
10139
+ int i, err;
10140
+
10141
+ mutex_lock(&devlink->lock);
10142
+ for (i = 0; i < policers_count; i++) {
10143
+ const struct devlink_trap_policer *policer = &policers[i];
10144
+
10145
+ if (WARN_ON(policer->id == 0 ||
10146
+ policer->max_rate < policer->min_rate ||
10147
+ policer->max_burst < policer->min_burst)) {
10148
+ err = -EINVAL;
10149
+ goto err_trap_policer_verify;
10150
+ }
10151
+
10152
+ err = devlink_trap_policer_register(devlink, policer);
10153
+ if (err)
10154
+ goto err_trap_policer_register;
10155
+ }
10156
+ mutex_unlock(&devlink->lock);
10157
+
10158
+ return 0;
10159
+
10160
+err_trap_policer_register:
10161
+err_trap_policer_verify:
10162
+ for (i--; i >= 0; i--)
10163
+ devlink_trap_policer_unregister(devlink, &policers[i]);
10164
+ mutex_unlock(&devlink->lock);
10165
+ return err;
10166
+}
10167
+EXPORT_SYMBOL_GPL(devlink_trap_policers_register);
10168
+
10169
+/**
10170
+ * devlink_trap_policers_unregister - Unregister packet trap policers from devlink.
10171
+ * @devlink: devlink.
10172
+ * @policers: Packet trap policers.
10173
+ * @policers_count: Count of provided packet trap policers.
10174
+ */
10175
+void
10176
+devlink_trap_policers_unregister(struct devlink *devlink,
10177
+ const struct devlink_trap_policer *policers,
10178
+ size_t policers_count)
10179
+{
10180
+ int i;
10181
+
10182
+ mutex_lock(&devlink->lock);
10183
+ for (i = policers_count - 1; i >= 0; i--)
10184
+ devlink_trap_policer_unregister(devlink, &policers[i]);
10185
+ mutex_unlock(&devlink->lock);
10186
+}
10187
+EXPORT_SYMBOL_GPL(devlink_trap_policers_unregister);
10188
+
10189
+static void __devlink_compat_running_version(struct devlink *devlink,
10190
+ char *buf, size_t len)
10191
+{
10192
+ const struct nlattr *nlattr;
10193
+ struct devlink_info_req req;
10194
+ struct sk_buff *msg;
10195
+ int rem, err;
10196
+
10197
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10198
+ if (!msg)
10199
+ return;
10200
+
10201
+ req.msg = msg;
10202
+ err = devlink->ops->info_get(devlink, &req, NULL);
10203
+ if (err)
10204
+ goto free_msg;
10205
+
10206
+ nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
10207
+ const struct nlattr *kv;
10208
+ int rem_kv;
10209
+
10210
+ if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
10211
+ continue;
10212
+
10213
+ nla_for_each_nested(kv, nlattr, rem_kv) {
10214
+ if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
10215
+ continue;
10216
+
10217
+ strlcat(buf, nla_data(kv), len);
10218
+ strlcat(buf, " ", len);
10219
+ }
10220
+ }
10221
+free_msg:
10222
+ nlmsg_free(msg);
10223
+}
10224
+
10225
+void devlink_compat_running_version(struct net_device *dev,
10226
+ char *buf, size_t len)
10227
+{
10228
+ struct devlink *devlink;
10229
+
10230
+ dev_hold(dev);
10231
+ rtnl_unlock();
10232
+
10233
+ devlink = netdev_to_devlink(dev);
10234
+ if (!devlink || !devlink->ops->info_get)
10235
+ goto out;
10236
+
10237
+ mutex_lock(&devlink->lock);
10238
+ __devlink_compat_running_version(devlink, buf, len);
10239
+ mutex_unlock(&devlink->lock);
10240
+
10241
+out:
10242
+ rtnl_lock();
10243
+ dev_put(dev);
10244
+}
10245
+
10246
+int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
10247
+{
10248
+ struct devlink_flash_update_params params = {};
10249
+ struct devlink *devlink;
10250
+ int ret;
10251
+
10252
+ dev_hold(dev);
10253
+ rtnl_unlock();
10254
+
10255
+ devlink = netdev_to_devlink(dev);
10256
+ if (!devlink || !devlink->ops->flash_update) {
10257
+ ret = -EOPNOTSUPP;
10258
+ goto out;
10259
+ }
10260
+
10261
+ params.file_name = file_name;
10262
+
10263
+ mutex_lock(&devlink->lock);
10264
+ ret = devlink->ops->flash_update(devlink, &params, NULL);
10265
+ mutex_unlock(&devlink->lock);
10266
+
10267
+out:
10268
+ rtnl_lock();
10269
+ dev_put(dev);
10270
+
10271
+ return ret;
10272
+}
10273
+
10274
+int devlink_compat_phys_port_name_get(struct net_device *dev,
10275
+ char *name, size_t len)
10276
+{
10277
+ struct devlink_port *devlink_port;
10278
+
10279
+ /* RTNL mutex is held here which ensures that devlink_port
10280
+ * instance cannot disappear in the middle. No need to take
10281
+ * any devlink lock as only permanent values are accessed.
10282
+ */
10283
+ ASSERT_RTNL();
10284
+
10285
+ devlink_port = netdev_to_devlink_port(dev);
10286
+ if (!devlink_port)
10287
+ return -EOPNOTSUPP;
10288
+
10289
+ return __devlink_port_phys_port_name_get(devlink_port, name, len);
10290
+}
10291
+
10292
+int devlink_compat_switch_id_get(struct net_device *dev,
10293
+ struct netdev_phys_item_id *ppid)
10294
+{
10295
+ struct devlink_port *devlink_port;
10296
+
10297
+ /* Caller must hold RTNL mutex or reference to dev, which ensures that
10298
+ * devlink_port instance cannot disappear in the middle. No need to take
10299
+ * any devlink lock as only permanent values are accessed.
10300
+ */
10301
+ devlink_port = netdev_to_devlink_port(dev);
10302
+ if (!devlink_port || !devlink_port->switch_port)
10303
+ return -EOPNOTSUPP;
10304
+
10305
+ memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));
10306
+
10307
+ return 0;
10308
+}
10309
+
10310
+static void __net_exit devlink_pernet_pre_exit(struct net *net)
10311
+{
10312
+ struct devlink *devlink;
10313
+ u32 actions_performed;
10314
+ int err;
10315
+
10316
+ /* In case network namespace is getting destroyed, reload
10317
+ * all devlink instances from this namespace into init_net.
10318
+ */
10319
+ mutex_lock(&devlink_mutex);
10320
+ list_for_each_entry(devlink, &devlink_list, list) {
10321
+ if (net_eq(devlink_net(devlink), net)) {
10322
+ if (WARN_ON(!devlink_reload_supported(devlink->ops)))
10323
+ continue;
10324
+ err = devlink_reload(devlink, &init_net,
10325
+ DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
10326
+ DEVLINK_RELOAD_LIMIT_UNSPEC,
10327
+ &actions_performed, NULL);
10328
+ if (err && err != -EOPNOTSUPP)
10329
+ pr_warn("Failed to reload devlink instance into init_net\n");
10330
+ }
10331
+ }
10332
+ mutex_unlock(&devlink_mutex);
10333
+}
10334
+
10335
+static struct pernet_operations devlink_pernet_ops __net_initdata = {
10336
+ .pre_exit = devlink_pernet_pre_exit,
10337
+};
10338
+
10339
+static int __init devlink_init(void)
10340
+{
10341
+ int err;
10342
+
10343
+ err = genl_register_family(&devlink_nl_family);
10344
+ if (err)
10345
+ goto out;
10346
+ err = register_pernet_subsys(&devlink_pernet_ops);
10347
+
10348
+out:
10349
+ WARN_ON(err);
10350
+ return err;
10351
+}
10352
+
10353
+subsys_initcall(devlink_init);