net: dsa: move MDB handlers
[sfrench/cifs-2.6.git] / net / dsa / port.c
1 /*
2  * Handling of a single switch port
3  *
4  * Copyright (c) 2017 Savoir-faire Linux Inc.
5  *      Vivien Didelot <vivien.didelot@savoirfairelinux.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  */
12
13 #include <linux/if_bridge.h>
14 #include <linux/notifier.h>
15
16 #include "dsa_priv.h"
17
18 static int dsa_port_notify(struct dsa_port *dp, unsigned long e, void *v)
19 {
20         struct raw_notifier_head *nh = &dp->ds->dst->nh;
21         int err;
22
23         err = raw_notifier_call_chain(nh, e, v);
24
25         return notifier_to_errno(err);
26 }
27
28 int dsa_port_set_state(struct dsa_port *dp, u8 state,
29                        struct switchdev_trans *trans)
30 {
31         struct dsa_switch *ds = dp->ds;
32         int port = dp->index;
33
34         if (switchdev_trans_ph_prepare(trans))
35                 return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP;
36
37         if (ds->ops->port_stp_state_set)
38                 ds->ops->port_stp_state_set(ds, port, state);
39
40         if (ds->ops->port_fast_age) {
41                 /* Fast age FDB entries or flush appropriate forwarding database
42                  * for the given port, if we are moving it from Learning or
43                  * Forwarding state, to Disabled or Blocking or Listening state.
44                  */
45
46                 if ((dp->stp_state == BR_STATE_LEARNING ||
47                      dp->stp_state == BR_STATE_FORWARDING) &&
48                     (state == BR_STATE_DISABLED ||
49                      state == BR_STATE_BLOCKING ||
50                      state == BR_STATE_LISTENING))
51                         ds->ops->port_fast_age(ds, port);
52         }
53
54         dp->stp_state = state;
55
56         return 0;
57 }
58
59 void dsa_port_set_state_now(struct dsa_port *dp, u8 state)
60 {
61         int err;
62
63         err = dsa_port_set_state(dp, state, NULL);
64         if (err)
65                 pr_err("DSA: failed to set STP state %u (%d)\n", state, err);
66 }
67
68 int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br)
69 {
70         struct dsa_notifier_bridge_info info = {
71                 .sw_index = dp->ds->index,
72                 .port = dp->index,
73                 .br = br,
74         };
75         int err;
76
77         /* Here the port is already bridged. Reflect the current configuration
78          * so that drivers can program their chips accordingly.
79          */
80         dp->bridge_dev = br;
81
82         err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_JOIN, &info);
83
84         /* The bridging is rolled back on error */
85         if (err)
86                 dp->bridge_dev = NULL;
87
88         return err;
89 }
90
91 void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
92 {
93         struct dsa_notifier_bridge_info info = {
94                 .sw_index = dp->ds->index,
95                 .port = dp->index,
96                 .br = br,
97         };
98         int err;
99
100         /* Here the port is already unbridged. Reflect the current configuration
101          * so that drivers can program their chips accordingly.
102          */
103         dp->bridge_dev = NULL;
104
105         err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_LEAVE, &info);
106         if (err)
107                 pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n");
108
109         /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer,
110          * so allow it to be in BR_STATE_FORWARDING to be kept functional
111          */
112         dsa_port_set_state_now(dp, BR_STATE_FORWARDING);
113 }
114
115 int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
116                             struct switchdev_trans *trans)
117 {
118         struct dsa_switch *ds = dp->ds;
119
120         /* bridge skips -EOPNOTSUPP, so skip the prepare phase */
121         if (switchdev_trans_ph_prepare(trans))
122                 return 0;
123
124         if (ds->ops->port_vlan_filtering)
125                 return ds->ops->port_vlan_filtering(ds, dp->index,
126                                                     vlan_filtering);
127
128         return 0;
129 }
130
131 static unsigned int dsa_fastest_ageing_time(struct dsa_switch *ds,
132                                             unsigned int ageing_time)
133 {
134         int i;
135
136         for (i = 0; i < ds->num_ports; ++i) {
137                 struct dsa_port *dp = &ds->ports[i];
138
139                 if (dp->ageing_time && dp->ageing_time < ageing_time)
140                         ageing_time = dp->ageing_time;
141         }
142
143         return ageing_time;
144 }
145
146 int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
147                          struct switchdev_trans *trans)
148 {
149         unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock);
150         unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies);
151         struct dsa_switch *ds = dp->ds;
152
153         if (switchdev_trans_ph_prepare(trans)) {
154                 if (ds->ageing_time_min && ageing_time < ds->ageing_time_min)
155                         return -ERANGE;
156                 if (ds->ageing_time_max && ageing_time > ds->ageing_time_max)
157                         return -ERANGE;
158                 return 0;
159         }
160
161         /* Keep the fastest ageing time in case of multiple bridges */
162         dp->ageing_time = ageing_time;
163         ageing_time = dsa_fastest_ageing_time(ds, ageing_time);
164
165         if (ds->ops->set_ageing_time)
166                 return ds->ops->set_ageing_time(ds, ageing_time);
167
168         return 0;
169 }
170
171 int dsa_port_fdb_add(struct dsa_port *dp,
172                      const struct switchdev_obj_port_fdb *fdb,
173                      struct switchdev_trans *trans)
174 {
175         struct dsa_switch *ds = dp->ds;
176
177         if (switchdev_trans_ph_prepare(trans)) {
178                 if (!ds->ops->port_fdb_prepare || !ds->ops->port_fdb_add)
179                         return -EOPNOTSUPP;
180
181                 return ds->ops->port_fdb_prepare(ds, dp->index, fdb, trans);
182         }
183
184         ds->ops->port_fdb_add(ds, dp->index, fdb, trans);
185
186         return 0;
187 }
188
189 int dsa_port_fdb_del(struct dsa_port *dp,
190                      const struct switchdev_obj_port_fdb *fdb)
191 {
192         struct dsa_switch *ds = dp->ds;
193
194         if (ds->ops->port_fdb_del)
195                 return -EOPNOTSUPP;
196
197         return ds->ops->port_fdb_del(ds, dp->index, fdb);
198 }
199
200 int dsa_port_fdb_dump(struct dsa_port *dp, struct switchdev_obj_port_fdb *fdb,
201                       switchdev_obj_dump_cb_t *cb)
202 {
203         struct dsa_switch *ds = dp->ds;
204
205         if (ds->ops->port_fdb_dump)
206                 return ds->ops->port_fdb_dump(ds, dp->index, fdb, cb);
207
208         return -EOPNOTSUPP;
209 }
210
211 int dsa_port_mdb_add(struct dsa_port *dp,
212                      const struct switchdev_obj_port_mdb *mdb,
213                      struct switchdev_trans *trans)
214 {
215         struct dsa_switch *ds = dp->ds;
216
217         if (switchdev_trans_ph_prepare(trans)) {
218                 if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add)
219                         return -EOPNOTSUPP;
220
221                 return ds->ops->port_mdb_prepare(ds, dp->index, mdb, trans);
222         }
223
224         ds->ops->port_mdb_add(ds, dp->index, mdb, trans);
225
226         return 0;
227 }
228
229 int dsa_port_mdb_del(struct dsa_port *dp,
230                      const struct switchdev_obj_port_mdb *mdb)
231 {
232         struct dsa_switch *ds = dp->ds;
233
234         if (ds->ops->port_mdb_del)
235                 return ds->ops->port_mdb_del(ds, dp->index, mdb);
236
237         return -EOPNOTSUPP;
238 }
239
240 int dsa_port_mdb_dump(struct dsa_port *dp, struct switchdev_obj_port_mdb *mdb,
241                       switchdev_obj_dump_cb_t *cb)
242 {
243         struct dsa_switch *ds = dp->ds;
244
245         if (ds->ops->port_mdb_dump)
246                 return ds->ops->port_mdb_dump(ds, dp->index, mdb, cb);
247
248         return -EOPNOTSUPP;
249 }