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