xref: /openbmc/linux/net/switchdev/switchdev.c (revision e0bf6c5c)
1 /*
2  * net/switchdev/switchdev.c - Switch device API
3  * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  */
10 
11 #include <linux/kernel.h>
12 #include <linux/types.h>
13 #include <linux/init.h>
14 #include <linux/mutex.h>
15 #include <linux/notifier.h>
16 #include <linux/netdevice.h>
17 #include <net/switchdev.h>
18 
19 /**
20  *	netdev_switch_parent_id_get - Get ID of a switch
21  *	@dev: port device
22  *	@psid: switch ID
23  *
24  *	Get ID of a switch this port is part of.
25  */
26 int netdev_switch_parent_id_get(struct net_device *dev,
27 				struct netdev_phys_item_id *psid)
28 {
29 	const struct net_device_ops *ops = dev->netdev_ops;
30 
31 	if (!ops->ndo_switch_parent_id_get)
32 		return -EOPNOTSUPP;
33 	return ops->ndo_switch_parent_id_get(dev, psid);
34 }
35 EXPORT_SYMBOL(netdev_switch_parent_id_get);
36 
37 /**
38  *	netdev_switch_port_stp_update - Notify switch device port of STP
39  *					state change
40  *	@dev: port device
41  *	@state: port STP state
42  *
43  *	Notify switch device port of bridge port STP state change.
44  */
45 int netdev_switch_port_stp_update(struct net_device *dev, u8 state)
46 {
47 	const struct net_device_ops *ops = dev->netdev_ops;
48 
49 	if (!ops->ndo_switch_port_stp_update)
50 		return -EOPNOTSUPP;
51 	WARN_ON(!ops->ndo_switch_parent_id_get);
52 	return ops->ndo_switch_port_stp_update(dev, state);
53 }
54 EXPORT_SYMBOL(netdev_switch_port_stp_update);
55 
56 static DEFINE_MUTEX(netdev_switch_mutex);
57 static RAW_NOTIFIER_HEAD(netdev_switch_notif_chain);
58 
59 /**
60  *	register_netdev_switch_notifier - Register nofifier
61  *	@nb: notifier_block
62  *
63  *	Register switch device notifier. This should be used by code
64  *	which needs to monitor events happening in particular device.
65  *	Return values are same as for atomic_notifier_chain_register().
66  */
67 int register_netdev_switch_notifier(struct notifier_block *nb)
68 {
69 	int err;
70 
71 	mutex_lock(&netdev_switch_mutex);
72 	err = raw_notifier_chain_register(&netdev_switch_notif_chain, nb);
73 	mutex_unlock(&netdev_switch_mutex);
74 	return err;
75 }
76 EXPORT_SYMBOL(register_netdev_switch_notifier);
77 
78 /**
79  *	unregister_netdev_switch_notifier - Unregister nofifier
80  *	@nb: notifier_block
81  *
82  *	Unregister switch device notifier.
83  *	Return values are same as for atomic_notifier_chain_unregister().
84  */
85 int unregister_netdev_switch_notifier(struct notifier_block *nb)
86 {
87 	int err;
88 
89 	mutex_lock(&netdev_switch_mutex);
90 	err = raw_notifier_chain_unregister(&netdev_switch_notif_chain, nb);
91 	mutex_unlock(&netdev_switch_mutex);
92 	return err;
93 }
94 EXPORT_SYMBOL(unregister_netdev_switch_notifier);
95 
96 /**
97  *	call_netdev_switch_notifiers - Call nofifiers
98  *	@val: value passed unmodified to notifier function
99  *	@dev: port device
100  *	@info: notifier information data
101  *
102  *	Call all network notifier blocks. This should be called by driver
103  *	when it needs to propagate hardware event.
104  *	Return values are same as for atomic_notifier_call_chain().
105  */
106 int call_netdev_switch_notifiers(unsigned long val, struct net_device *dev,
107 				 struct netdev_switch_notifier_info *info)
108 {
109 	int err;
110 
111 	info->dev = dev;
112 	mutex_lock(&netdev_switch_mutex);
113 	err = raw_notifier_call_chain(&netdev_switch_notif_chain, val, info);
114 	mutex_unlock(&netdev_switch_mutex);
115 	return err;
116 }
117 EXPORT_SYMBOL(call_netdev_switch_notifiers);
118 
119 /**
120  *	netdev_switch_port_bridge_setlink - Notify switch device port of bridge
121  *	port attributes
122  *
123  *	@dev: port device
124  *	@nlh: netlink msg with bridge port attributes
125  *	@flags: bridge setlink flags
126  *
127  *	Notify switch device port of bridge port attributes
128  */
129 int netdev_switch_port_bridge_setlink(struct net_device *dev,
130 				      struct nlmsghdr *nlh, u16 flags)
131 {
132 	const struct net_device_ops *ops = dev->netdev_ops;
133 
134 	if (!(dev->features & NETIF_F_HW_SWITCH_OFFLOAD))
135 		return 0;
136 
137 	if (!ops->ndo_bridge_setlink)
138 		return -EOPNOTSUPP;
139 
140 	return ops->ndo_bridge_setlink(dev, nlh, flags);
141 }
142 EXPORT_SYMBOL(netdev_switch_port_bridge_setlink);
143 
144 /**
145  *	netdev_switch_port_bridge_dellink - Notify switch device port of bridge
146  *	port attribute delete
147  *
148  *	@dev: port device
149  *	@nlh: netlink msg with bridge port attributes
150  *	@flags: bridge setlink flags
151  *
152  *	Notify switch device port of bridge port attribute delete
153  */
154 int netdev_switch_port_bridge_dellink(struct net_device *dev,
155 				      struct nlmsghdr *nlh, u16 flags)
156 {
157 	const struct net_device_ops *ops = dev->netdev_ops;
158 
159 	if (!(dev->features & NETIF_F_HW_SWITCH_OFFLOAD))
160 		return 0;
161 
162 	if (!ops->ndo_bridge_dellink)
163 		return -EOPNOTSUPP;
164 
165 	return ops->ndo_bridge_dellink(dev, nlh, flags);
166 }
167 EXPORT_SYMBOL(netdev_switch_port_bridge_dellink);
168 
169 /**
170  *	ndo_dflt_netdev_switch_port_bridge_setlink - default ndo bridge setlink
171  *						     op for master devices
172  *
173  *	@dev: port device
174  *	@nlh: netlink msg with bridge port attributes
175  *	@flags: bridge setlink flags
176  *
177  *	Notify master device slaves of bridge port attributes
178  */
179 int ndo_dflt_netdev_switch_port_bridge_setlink(struct net_device *dev,
180 					       struct nlmsghdr *nlh, u16 flags)
181 {
182 	struct net_device *lower_dev;
183 	struct list_head *iter;
184 	int ret = 0, err = 0;
185 
186 	if (!(dev->features & NETIF_F_HW_SWITCH_OFFLOAD))
187 		return ret;
188 
189 	netdev_for_each_lower_dev(dev, lower_dev, iter) {
190 		err = netdev_switch_port_bridge_setlink(lower_dev, nlh, flags);
191 		if (err && err != -EOPNOTSUPP)
192 			ret = err;
193 	}
194 
195 	return ret;
196 }
197 EXPORT_SYMBOL(ndo_dflt_netdev_switch_port_bridge_setlink);
198 
199 /**
200  *	ndo_dflt_netdev_switch_port_bridge_dellink - default ndo bridge dellink
201  *						     op for master devices
202  *
203  *	@dev: port device
204  *	@nlh: netlink msg with bridge port attributes
205  *	@flags: bridge dellink flags
206  *
207  *	Notify master device slaves of bridge port attribute deletes
208  */
209 int ndo_dflt_netdev_switch_port_bridge_dellink(struct net_device *dev,
210 					       struct nlmsghdr *nlh, u16 flags)
211 {
212 	struct net_device *lower_dev;
213 	struct list_head *iter;
214 	int ret = 0, err = 0;
215 
216 	if (!(dev->features & NETIF_F_HW_SWITCH_OFFLOAD))
217 		return ret;
218 
219 	netdev_for_each_lower_dev(dev, lower_dev, iter) {
220 		err = netdev_switch_port_bridge_dellink(lower_dev, nlh, flags);
221 		if (err && err != -EOPNOTSUPP)
222 			ret = err;
223 	}
224 
225 	return ret;
226 }
227 EXPORT_SYMBOL(ndo_dflt_netdev_switch_port_bridge_dellink);
228