xref: /linux/net/core/lock_debug.c (revision 785151f50ddacac06c7a3c5f3d31642794507fdf)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Copyright Amazon.com Inc. or its affiliates. */
3 
4 #include <linux/init.h>
5 #include <linux/netdevice.h>
6 #include <linux/notifier.h>
7 #include <linux/rtnetlink.h>
8 #include <net/net_namespace.h>
9 #include <net/netdev_lock.h>
10 #include <net/netns/generic.h>
11 
netdev_debug_event(struct notifier_block * nb,unsigned long event,void * ptr)12 int netdev_debug_event(struct notifier_block *nb, unsigned long event,
13 		       void *ptr)
14 {
15 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
16 	struct net *net = dev_net(dev);
17 	enum netdev_cmd cmd = event;
18 
19 	/* Keep enum and don't add default to trigger -Werror=switch */
20 	switch (cmd) {
21 	case NETDEV_XDP_FEAT_CHANGE:
22 		netdev_assert_locked(dev);
23 		fallthrough;
24 	case NETDEV_CHANGE:
25 	case NETDEV_REGISTER:
26 	case NETDEV_UP:
27 		netdev_ops_assert_locked(dev);
28 		fallthrough;
29 	case NETDEV_DOWN:
30 	case NETDEV_REBOOT:
31 	case NETDEV_UNREGISTER:
32 	case NETDEV_CHANGEMTU:
33 	case NETDEV_CHANGEADDR:
34 	case NETDEV_PRE_CHANGEADDR:
35 	case NETDEV_GOING_DOWN:
36 	case NETDEV_FEAT_CHANGE:
37 	case NETDEV_BONDING_FAILOVER:
38 	case NETDEV_PRE_UP:
39 	case NETDEV_PRE_TYPE_CHANGE:
40 	case NETDEV_POST_TYPE_CHANGE:
41 	case NETDEV_POST_INIT:
42 	case NETDEV_PRE_UNINIT:
43 	case NETDEV_RELEASE:
44 	case NETDEV_NOTIFY_PEERS:
45 	case NETDEV_JOIN:
46 	case NETDEV_CHANGEUPPER:
47 	case NETDEV_RESEND_IGMP:
48 	case NETDEV_PRECHANGEMTU:
49 	case NETDEV_CHANGEINFODATA:
50 	case NETDEV_BONDING_INFO:
51 	case NETDEV_PRECHANGEUPPER:
52 	case NETDEV_CHANGELOWERSTATE:
53 	case NETDEV_UDP_TUNNEL_PUSH_INFO:
54 	case NETDEV_UDP_TUNNEL_DROP_INFO:
55 	case NETDEV_CHANGE_TX_QUEUE_LEN:
56 	case NETDEV_CVLAN_FILTER_PUSH_INFO:
57 	case NETDEV_CVLAN_FILTER_DROP_INFO:
58 	case NETDEV_SVLAN_FILTER_PUSH_INFO:
59 	case NETDEV_SVLAN_FILTER_DROP_INFO:
60 	case NETDEV_OFFLOAD_XSTATS_ENABLE:
61 	case NETDEV_OFFLOAD_XSTATS_DISABLE:
62 	case NETDEV_OFFLOAD_XSTATS_REPORT_USED:
63 	case NETDEV_OFFLOAD_XSTATS_REPORT_DELTA:
64 		ASSERT_RTNL();
65 		break;
66 
67 	case NETDEV_CHANGENAME:
68 		ASSERT_RTNL_NET(net);
69 		break;
70 	}
71 
72 	return NOTIFY_DONE;
73 }
74 EXPORT_SYMBOL_NS_GPL(netdev_debug_event, "NETDEV_INTERNAL");
75 
76 static int rtnl_net_debug_net_id;
77 
rtnl_net_debug_net_init(struct net * net)78 static int __net_init rtnl_net_debug_net_init(struct net *net)
79 {
80 	struct notifier_block *nb;
81 
82 	nb = net_generic(net, rtnl_net_debug_net_id);
83 	nb->notifier_call = netdev_debug_event;
84 
85 	return register_netdevice_notifier_net(net, nb);
86 }
87 
rtnl_net_debug_net_exit(struct net * net)88 static void __net_exit rtnl_net_debug_net_exit(struct net *net)
89 {
90 	struct notifier_block *nb;
91 
92 	nb = net_generic(net, rtnl_net_debug_net_id);
93 	unregister_netdevice_notifier_net(net, nb);
94 }
95 
96 static struct pernet_operations rtnl_net_debug_net_ops __net_initdata = {
97 	.init = rtnl_net_debug_net_init,
98 	.exit = rtnl_net_debug_net_exit,
99 	.id = &rtnl_net_debug_net_id,
100 	.size = sizeof(struct notifier_block),
101 };
102 
103 static struct notifier_block rtnl_net_debug_block = {
104 	.notifier_call = netdev_debug_event,
105 };
106 
rtnl_net_debug_init(void)107 static int __init rtnl_net_debug_init(void)
108 {
109 	int ret;
110 
111 	ret = register_pernet_subsys(&rtnl_net_debug_net_ops);
112 	if (ret)
113 		return ret;
114 
115 	ret = register_netdevice_notifier(&rtnl_net_debug_block);
116 	if (ret)
117 		unregister_pernet_subsys(&rtnl_net_debug_net_ops);
118 
119 	return ret;
120 }
121 
122 subsys_initcall(rtnl_net_debug_init);
123