switchdev: use gpl variant of symbol export
[firefly-linux-kernel-4.4.55.git] / net / switchdev / switchdev.c
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/ip_fib.h>
18 #include <net/switchdev.h>
19
20 /**
21  *      netdev_switch_parent_id_get - Get ID of a switch
22  *      @dev: port device
23  *      @psid: switch ID
24  *
25  *      Get ID of a switch this port is part of.
26  */
27 int netdev_switch_parent_id_get(struct net_device *dev,
28                                 struct netdev_phys_item_id *psid)
29 {
30         const struct net_device_ops *ops = dev->netdev_ops;
31
32         if (!ops->ndo_switch_parent_id_get)
33                 return -EOPNOTSUPP;
34         return ops->ndo_switch_parent_id_get(dev, psid);
35 }
36 EXPORT_SYMBOL_GPL(netdev_switch_parent_id_get);
37
38 /**
39  *      netdev_switch_port_stp_update - Notify switch device port of STP
40  *                                      state change
41  *      @dev: port device
42  *      @state: port STP state
43  *
44  *      Notify switch device port of bridge port STP state change.
45  */
46 int netdev_switch_port_stp_update(struct net_device *dev, u8 state)
47 {
48         const struct net_device_ops *ops = dev->netdev_ops;
49
50         if (!ops->ndo_switch_port_stp_update)
51                 return -EOPNOTSUPP;
52         WARN_ON(!ops->ndo_switch_parent_id_get);
53         return ops->ndo_switch_port_stp_update(dev, state);
54 }
55 EXPORT_SYMBOL_GPL(netdev_switch_port_stp_update);
56
57 static DEFINE_MUTEX(netdev_switch_mutex);
58 static RAW_NOTIFIER_HEAD(netdev_switch_notif_chain);
59
60 /**
61  *      register_netdev_switch_notifier - Register nofifier
62  *      @nb: notifier_block
63  *
64  *      Register switch device notifier. This should be used by code
65  *      which needs to monitor events happening in particular device.
66  *      Return values are same as for atomic_notifier_chain_register().
67  */
68 int register_netdev_switch_notifier(struct notifier_block *nb)
69 {
70         int err;
71
72         mutex_lock(&netdev_switch_mutex);
73         err = raw_notifier_chain_register(&netdev_switch_notif_chain, nb);
74         mutex_unlock(&netdev_switch_mutex);
75         return err;
76 }
77 EXPORT_SYMBOL_GPL(register_netdev_switch_notifier);
78
79 /**
80  *      unregister_netdev_switch_notifier - Unregister nofifier
81  *      @nb: notifier_block
82  *
83  *      Unregister switch device notifier.
84  *      Return values are same as for atomic_notifier_chain_unregister().
85  */
86 int unregister_netdev_switch_notifier(struct notifier_block *nb)
87 {
88         int err;
89
90         mutex_lock(&netdev_switch_mutex);
91         err = raw_notifier_chain_unregister(&netdev_switch_notif_chain, nb);
92         mutex_unlock(&netdev_switch_mutex);
93         return err;
94 }
95 EXPORT_SYMBOL_GPL(unregister_netdev_switch_notifier);
96
97 /**
98  *      call_netdev_switch_notifiers - Call nofifiers
99  *      @val: value passed unmodified to notifier function
100  *      @dev: port device
101  *      @info: notifier information data
102  *
103  *      Call all network notifier blocks. This should be called by driver
104  *      when it needs to propagate hardware event.
105  *      Return values are same as for atomic_notifier_call_chain().
106  */
107 int call_netdev_switch_notifiers(unsigned long val, struct net_device *dev,
108                                  struct netdev_switch_notifier_info *info)
109 {
110         int err;
111
112         info->dev = dev;
113         mutex_lock(&netdev_switch_mutex);
114         err = raw_notifier_call_chain(&netdev_switch_notif_chain, val, info);
115         mutex_unlock(&netdev_switch_mutex);
116         return err;
117 }
118 EXPORT_SYMBOL_GPL(call_netdev_switch_notifiers);
119
120 /**
121  *      netdev_switch_port_bridge_setlink - Notify switch device port of bridge
122  *      port attributes
123  *
124  *      @dev: port device
125  *      @nlh: netlink msg with bridge port attributes
126  *      @flags: bridge setlink flags
127  *
128  *      Notify switch device port of bridge port attributes
129  */
130 int netdev_switch_port_bridge_setlink(struct net_device *dev,
131                                       struct nlmsghdr *nlh, u16 flags)
132 {
133         const struct net_device_ops *ops = dev->netdev_ops;
134
135         if (!(dev->features & NETIF_F_HW_SWITCH_OFFLOAD))
136                 return 0;
137
138         if (!ops->ndo_bridge_setlink)
139                 return -EOPNOTSUPP;
140
141         return ops->ndo_bridge_setlink(dev, nlh, flags);
142 }
143 EXPORT_SYMBOL_GPL(netdev_switch_port_bridge_setlink);
144
145 /**
146  *      netdev_switch_port_bridge_dellink - Notify switch device port of bridge
147  *      port attribute delete
148  *
149  *      @dev: port device
150  *      @nlh: netlink msg with bridge port attributes
151  *      @flags: bridge setlink flags
152  *
153  *      Notify switch device port of bridge port attribute delete
154  */
155 int netdev_switch_port_bridge_dellink(struct net_device *dev,
156                                       struct nlmsghdr *nlh, u16 flags)
157 {
158         const struct net_device_ops *ops = dev->netdev_ops;
159
160         if (!(dev->features & NETIF_F_HW_SWITCH_OFFLOAD))
161                 return 0;
162
163         if (!ops->ndo_bridge_dellink)
164                 return -EOPNOTSUPP;
165
166         return ops->ndo_bridge_dellink(dev, nlh, flags);
167 }
168 EXPORT_SYMBOL_GPL(netdev_switch_port_bridge_dellink);
169
170 /**
171  *      ndo_dflt_netdev_switch_port_bridge_setlink - default ndo bridge setlink
172  *                                                   op for master devices
173  *
174  *      @dev: port device
175  *      @nlh: netlink msg with bridge port attributes
176  *      @flags: bridge setlink flags
177  *
178  *      Notify master device slaves of bridge port attributes
179  */
180 int ndo_dflt_netdev_switch_port_bridge_setlink(struct net_device *dev,
181                                                struct nlmsghdr *nlh, u16 flags)
182 {
183         struct net_device *lower_dev;
184         struct list_head *iter;
185         int ret = 0, err = 0;
186
187         if (!(dev->features & NETIF_F_HW_SWITCH_OFFLOAD))
188                 return ret;
189
190         netdev_for_each_lower_dev(dev, lower_dev, iter) {
191                 err = netdev_switch_port_bridge_setlink(lower_dev, nlh, flags);
192                 if (err && err != -EOPNOTSUPP)
193                         ret = err;
194         }
195
196         return ret;
197 }
198 EXPORT_SYMBOL_GPL(ndo_dflt_netdev_switch_port_bridge_setlink);
199
200 /**
201  *      ndo_dflt_netdev_switch_port_bridge_dellink - default ndo bridge dellink
202  *                                                   op for master devices
203  *
204  *      @dev: port device
205  *      @nlh: netlink msg with bridge port attributes
206  *      @flags: bridge dellink flags
207  *
208  *      Notify master device slaves of bridge port attribute deletes
209  */
210 int ndo_dflt_netdev_switch_port_bridge_dellink(struct net_device *dev,
211                                                struct nlmsghdr *nlh, u16 flags)
212 {
213         struct net_device *lower_dev;
214         struct list_head *iter;
215         int ret = 0, err = 0;
216
217         if (!(dev->features & NETIF_F_HW_SWITCH_OFFLOAD))
218                 return ret;
219
220         netdev_for_each_lower_dev(dev, lower_dev, iter) {
221                 err = netdev_switch_port_bridge_dellink(lower_dev, nlh, flags);
222                 if (err && err != -EOPNOTSUPP)
223                         ret = err;
224         }
225
226         return ret;
227 }
228 EXPORT_SYMBOL_GPL(ndo_dflt_netdev_switch_port_bridge_dellink);
229
230 static struct net_device *netdev_switch_get_lowest_dev(struct net_device *dev)
231 {
232         const struct net_device_ops *ops = dev->netdev_ops;
233         struct net_device *lower_dev;
234         struct net_device *port_dev;
235         struct list_head *iter;
236
237         /* Recusively search down until we find a sw port dev.
238          * (A sw port dev supports ndo_switch_parent_id_get).
239          */
240
241         if (dev->features & NETIF_F_HW_SWITCH_OFFLOAD &&
242             ops->ndo_switch_parent_id_get)
243                 return dev;
244
245         netdev_for_each_lower_dev(dev, lower_dev, iter) {
246                 port_dev = netdev_switch_get_lowest_dev(lower_dev);
247                 if (port_dev)
248                         return port_dev;
249         }
250
251         return NULL;
252 }
253
254 static struct net_device *netdev_switch_get_dev_by_nhs(struct fib_info *fi)
255 {
256         struct netdev_phys_item_id psid;
257         struct netdev_phys_item_id prev_psid;
258         struct net_device *dev = NULL;
259         int nhsel;
260
261         /* For this route, all nexthop devs must be on the same switch. */
262
263         for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
264                 const struct fib_nh *nh = &fi->fib_nh[nhsel];
265
266                 if (!nh->nh_dev)
267                         return NULL;
268
269                 dev = netdev_switch_get_lowest_dev(nh->nh_dev);
270                 if (!dev)
271                         return NULL;
272
273                 if (netdev_switch_parent_id_get(dev, &psid))
274                         return NULL;
275
276                 if (nhsel > 0) {
277                         if (prev_psid.id_len != psid.id_len)
278                                 return NULL;
279                         if (memcmp(prev_psid.id, psid.id, psid.id_len))
280                                 return NULL;
281                 }
282
283                 prev_psid = psid;
284         }
285
286         return dev;
287 }
288
289 /**
290  *      netdev_switch_fib_ipv4_add - Add IPv4 route entry to switch
291  *
292  *      @dst: route's IPv4 destination address
293  *      @dst_len: destination address length (prefix length)
294  *      @fi: route FIB info structure
295  *      @tos: route TOS
296  *      @type: route type
297  *      @tb_id: route table ID
298  *
299  *      Add IPv4 route entry to switch device.
300  */
301 int netdev_switch_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi,
302                                u8 tos, u8 type, u32 tb_id)
303 {
304         struct net_device *dev;
305         const struct net_device_ops *ops;
306         int err = 0;
307
308         /* Don't offload route if using custom ip rules or if
309          * IPv4 FIB offloading has been disabled completely.
310          */
311
312 #ifdef CONFIG_IP_MULTIPLE_TABLES
313         if (fi->fib_net->ipv4.fib_has_custom_rules)
314                 return 0;
315 #endif
316
317         if (fi->fib_net->ipv4.fib_offload_disabled)
318                 return 0;
319
320         dev = netdev_switch_get_dev_by_nhs(fi);
321         if (!dev)
322                 return 0;
323         ops = dev->netdev_ops;
324
325         if (ops->ndo_switch_fib_ipv4_add) {
326                 err = ops->ndo_switch_fib_ipv4_add(dev, htonl(dst), dst_len,
327                                                    fi, tos, type, tb_id);
328                 if (!err)
329                         fi->fib_flags |= RTNH_F_EXTERNAL;
330         }
331
332         return err;
333 }
334 EXPORT_SYMBOL_GPL(netdev_switch_fib_ipv4_add);
335
336 /**
337  *      netdev_switch_fib_ipv4_del - Delete IPv4 route entry from switch
338  *
339  *      @dst: route's IPv4 destination address
340  *      @dst_len: destination address length (prefix length)
341  *      @fi: route FIB info structure
342  *      @tos: route TOS
343  *      @type: route type
344  *      @tb_id: route table ID
345  *
346  *      Delete IPv4 route entry from switch device.
347  */
348 int netdev_switch_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi,
349                                u8 tos, u8 type, u32 tb_id)
350 {
351         struct net_device *dev;
352         const struct net_device_ops *ops;
353         int err = 0;
354
355         if (!(fi->fib_flags & RTNH_F_EXTERNAL))
356                 return 0;
357
358         dev = netdev_switch_get_dev_by_nhs(fi);
359         if (!dev)
360                 return 0;
361         ops = dev->netdev_ops;
362
363         if (ops->ndo_switch_fib_ipv4_del) {
364                 err = ops->ndo_switch_fib_ipv4_del(dev, htonl(dst), dst_len,
365                                                    fi, tos, type, tb_id);
366                 if (!err)
367                         fi->fib_flags &= ~RTNH_F_EXTERNAL;
368         }
369
370         return err;
371 }
372 EXPORT_SYMBOL_GPL(netdev_switch_fib_ipv4_del);
373
374 /**
375  *      netdev_switch_fib_ipv4_abort - Abort an IPv4 FIB operation
376  *
377  *      @fi: route FIB info structure
378  */
379 void netdev_switch_fib_ipv4_abort(struct fib_info *fi)
380 {
381         /* There was a problem installing this route to the offload
382          * device.  For now, until we come up with more refined
383          * policy handling, abruptly end IPv4 fib offloading for
384          * for entire net by flushing offload device(s) of all
385          * IPv4 routes, and mark IPv4 fib offloading broken from
386          * this point forward.
387          */
388
389         fib_flush_external(fi->fib_net);
390         fi->fib_net->ipv4.fib_offload_disabled = true;
391 }
392 EXPORT_SYMBOL_GPL(netdev_switch_fib_ipv4_abort);