diff options
author | Vivien Didelot <vivien.didelot@savoirfairelinux.com> | 2015-08-06 01:44:04 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-08-10 01:48:09 -0400 |
commit | 55045ddded0f39d84c2ca019508973be8c595a78 (patch) | |
tree | 54dbc997258825838c981688ff66f113499138de /net/dsa/slave.c | |
parent | 890248261a18c7ae22923095dfadea2c0a2a304a (diff) |
net: dsa: add support for switchdev FDB objects
Remove the fdb_{add,del,getnext} function pointer in favor of new
port_fdb_{add,del,getnext}.
Implement the switchdev_port_obj_{add,del,dump} functions in DSA to
support the SWITCHDEV_OBJ_PORT_FDB objects.
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dsa/slave.c')
-rw-r--r-- | net/dsa/slave.c | 218 |
1 files changed, 116 insertions, 102 deletions
diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 0010c690cc67..1dbdeaab2bb4 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <net/switchdev.h> | 19 | #include <net/switchdev.h> |
20 | #include <linux/if_bridge.h> | 20 | #include <linux/if_bridge.h> |
21 | #include <linux/netpoll.h> | 21 | #include <linux/netpoll.h> |
22 | #include <linux/if_vlan.h> | ||
22 | #include "dsa_priv.h" | 23 | #include "dsa_priv.h" |
23 | 24 | ||
24 | /* slave mii_bus handling ***************************************************/ | 25 | /* slave mii_bus handling ***************************************************/ |
@@ -200,105 +201,6 @@ out: | |||
200 | return 0; | 201 | return 0; |
201 | } | 202 | } |
202 | 203 | ||
203 | static int dsa_slave_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], | ||
204 | struct net_device *dev, | ||
205 | const unsigned char *addr, u16 vid, u16 nlm_flags) | ||
206 | { | ||
207 | struct dsa_slave_priv *p = netdev_priv(dev); | ||
208 | struct dsa_switch *ds = p->parent; | ||
209 | int ret = -EOPNOTSUPP; | ||
210 | |||
211 | if (ds->drv->fdb_add) | ||
212 | ret = ds->drv->fdb_add(ds, p->port, addr, vid); | ||
213 | |||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | static int dsa_slave_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], | ||
218 | struct net_device *dev, | ||
219 | const unsigned char *addr, u16 vid) | ||
220 | { | ||
221 | struct dsa_slave_priv *p = netdev_priv(dev); | ||
222 | struct dsa_switch *ds = p->parent; | ||
223 | int ret = -EOPNOTSUPP; | ||
224 | |||
225 | if (ds->drv->fdb_del) | ||
226 | ret = ds->drv->fdb_del(ds, p->port, addr, vid); | ||
227 | |||
228 | return ret; | ||
229 | } | ||
230 | |||
231 | static int dsa_slave_fill_info(struct net_device *dev, struct sk_buff *skb, | ||
232 | const unsigned char *addr, u16 vid, | ||
233 | bool is_static, | ||
234 | u32 portid, u32 seq, int type, | ||
235 | unsigned int flags) | ||
236 | { | ||
237 | struct nlmsghdr *nlh; | ||
238 | struct ndmsg *ndm; | ||
239 | |||
240 | nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags); | ||
241 | if (!nlh) | ||
242 | return -EMSGSIZE; | ||
243 | |||
244 | ndm = nlmsg_data(nlh); | ||
245 | ndm->ndm_family = AF_BRIDGE; | ||
246 | ndm->ndm_pad1 = 0; | ||
247 | ndm->ndm_pad2 = 0; | ||
248 | ndm->ndm_flags = NTF_EXT_LEARNED; | ||
249 | ndm->ndm_type = 0; | ||
250 | ndm->ndm_ifindex = dev->ifindex; | ||
251 | ndm->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; | ||
252 | |||
253 | if (nla_put(skb, NDA_LLADDR, ETH_ALEN, addr)) | ||
254 | goto nla_put_failure; | ||
255 | |||
256 | if (vid && nla_put_u16(skb, NDA_VLAN, vid)) | ||
257 | goto nla_put_failure; | ||
258 | |||
259 | nlmsg_end(skb, nlh); | ||
260 | return 0; | ||
261 | |||
262 | nla_put_failure: | ||
263 | nlmsg_cancel(skb, nlh); | ||
264 | return -EMSGSIZE; | ||
265 | } | ||
266 | |||
267 | /* Dump information about entries, in response to GETNEIGH */ | ||
268 | static int dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, | ||
269 | struct net_device *dev, | ||
270 | struct net_device *filter_dev, int idx) | ||
271 | { | ||
272 | struct dsa_slave_priv *p = netdev_priv(dev); | ||
273 | struct dsa_switch *ds = p->parent; | ||
274 | unsigned char addr[ETH_ALEN] = { 0 }; | ||
275 | int ret; | ||
276 | |||
277 | if (!ds->drv->fdb_getnext) | ||
278 | return -EOPNOTSUPP; | ||
279 | |||
280 | for (; ; idx++) { | ||
281 | bool is_static; | ||
282 | |||
283 | ret = ds->drv->fdb_getnext(ds, p->port, addr, &is_static); | ||
284 | if (ret < 0) | ||
285 | break; | ||
286 | |||
287 | if (idx < cb->args[0]) | ||
288 | continue; | ||
289 | |||
290 | ret = dsa_slave_fill_info(dev, skb, addr, 0, | ||
291 | is_static, | ||
292 | NETLINK_CB(cb->skb).portid, | ||
293 | cb->nlh->nlmsg_seq, | ||
294 | RTM_NEWNEIGH, NLM_F_MULTI); | ||
295 | if (ret < 0) | ||
296 | break; | ||
297 | } | ||
298 | |||
299 | return idx; | ||
300 | } | ||
301 | |||
302 | static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | 204 | static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
303 | { | 205 | { |
304 | struct dsa_slave_priv *p = netdev_priv(dev); | 206 | struct dsa_slave_priv *p = netdev_priv(dev); |
@@ -364,6 +266,115 @@ static int dsa_slave_port_attr_set(struct net_device *dev, | |||
364 | return ret; | 266 | return ret; |
365 | } | 267 | } |
366 | 268 | ||
269 | static int dsa_slave_port_fdb_add(struct net_device *dev, | ||
270 | struct switchdev_obj *obj) | ||
271 | { | ||
272 | struct switchdev_obj_fdb *fdb = &obj->u.fdb; | ||
273 | struct dsa_slave_priv *p = netdev_priv(dev); | ||
274 | struct dsa_switch *ds = p->parent; | ||
275 | int err; | ||
276 | |||
277 | if (obj->trans == SWITCHDEV_TRANS_PREPARE) | ||
278 | err = ds->drv->port_fdb_add ? 0 : -EOPNOTSUPP; | ||
279 | else if (obj->trans == SWITCHDEV_TRANS_COMMIT) | ||
280 | err = ds->drv->port_fdb_add(ds, p->port, fdb->vid, fdb->addr); | ||
281 | else | ||
282 | err = -EOPNOTSUPP; | ||
283 | |||
284 | return err; | ||
285 | } | ||
286 | |||
287 | static int dsa_slave_port_fdb_del(struct net_device *dev, | ||
288 | struct switchdev_obj *obj) | ||
289 | { | ||
290 | struct switchdev_obj_fdb *fdb = &obj->u.fdb; | ||
291 | struct dsa_slave_priv *p = netdev_priv(dev); | ||
292 | struct dsa_switch *ds = p->parent; | ||
293 | |||
294 | if (!ds->drv->port_fdb_del) | ||
295 | return -EOPNOTSUPP; | ||
296 | |||
297 | return ds->drv->port_fdb_del(ds, p->port, fdb->vid, fdb->addr); | ||
298 | } | ||
299 | |||
300 | static int dsa_slave_port_fdb_dump(struct net_device *dev, | ||
301 | struct switchdev_obj *obj) | ||
302 | { | ||
303 | struct switchdev_obj_fdb *fdb = &obj->u.fdb; | ||
304 | struct dsa_slave_priv *p = netdev_priv(dev); | ||
305 | struct dsa_switch *ds = p->parent; | ||
306 | int err; | ||
307 | |||
308 | if (!ds->drv->port_fdb_getnext) | ||
309 | return -EOPNOTSUPP; | ||
310 | |||
311 | memset(fdb, 0, sizeof(*fdb)); | ||
312 | |||
313 | for (;;) { | ||
314 | err = ds->drv->port_fdb_getnext(ds, p->port, &fdb->vid, | ||
315 | fdb->addr, &fdb->is_static); | ||
316 | if (err) | ||
317 | break; | ||
318 | |||
319 | err = obj->cb(dev, obj); | ||
320 | if (err) | ||
321 | break; | ||
322 | } | ||
323 | |||
324 | return err == -ENOENT ? 0 : err; | ||
325 | } | ||
326 | |||
327 | static int dsa_slave_port_obj_add(struct net_device *dev, | ||
328 | struct switchdev_obj *obj) | ||
329 | { | ||
330 | int err; | ||
331 | |||
332 | switch (obj->id) { | ||
333 | case SWITCHDEV_OBJ_PORT_FDB: | ||
334 | err = dsa_slave_port_fdb_add(dev, obj); | ||
335 | break; | ||
336 | default: | ||
337 | err = -EOPNOTSUPP; | ||
338 | break; | ||
339 | } | ||
340 | |||
341 | return err; | ||
342 | } | ||
343 | |||
344 | static int dsa_slave_port_obj_del(struct net_device *dev, | ||
345 | struct switchdev_obj *obj) | ||
346 | { | ||
347 | int err; | ||
348 | |||
349 | switch (obj->id) { | ||
350 | case SWITCHDEV_OBJ_PORT_FDB: | ||
351 | err = dsa_slave_port_fdb_del(dev, obj); | ||
352 | break; | ||
353 | default: | ||
354 | err = -EOPNOTSUPP; | ||
355 | break; | ||
356 | } | ||
357 | |||
358 | return err; | ||
359 | } | ||
360 | |||
361 | static int dsa_slave_port_obj_dump(struct net_device *dev, | ||
362 | struct switchdev_obj *obj) | ||
363 | { | ||
364 | int err; | ||
365 | |||
366 | switch (obj->id) { | ||
367 | case SWITCHDEV_OBJ_PORT_FDB: | ||
368 | err = dsa_slave_port_fdb_dump(dev, obj); | ||
369 | break; | ||
370 | default: | ||
371 | err = -EOPNOTSUPP; | ||
372 | break; | ||
373 | } | ||
374 | |||
375 | return err; | ||
376 | } | ||
377 | |||
367 | static int dsa_slave_bridge_port_join(struct net_device *dev, | 378 | static int dsa_slave_bridge_port_join(struct net_device *dev, |
368 | struct net_device *br) | 379 | struct net_device *br) |
369 | { | 380 | { |
@@ -765,9 +776,9 @@ static const struct net_device_ops dsa_slave_netdev_ops = { | |||
765 | .ndo_change_rx_flags = dsa_slave_change_rx_flags, | 776 | .ndo_change_rx_flags = dsa_slave_change_rx_flags, |
766 | .ndo_set_rx_mode = dsa_slave_set_rx_mode, | 777 | .ndo_set_rx_mode = dsa_slave_set_rx_mode, |
767 | .ndo_set_mac_address = dsa_slave_set_mac_address, | 778 | .ndo_set_mac_address = dsa_slave_set_mac_address, |
768 | .ndo_fdb_add = dsa_slave_fdb_add, | 779 | .ndo_fdb_add = switchdev_port_fdb_add, |
769 | .ndo_fdb_del = dsa_slave_fdb_del, | 780 | .ndo_fdb_del = switchdev_port_fdb_del, |
770 | .ndo_fdb_dump = dsa_slave_fdb_dump, | 781 | .ndo_fdb_dump = switchdev_port_fdb_dump, |
771 | .ndo_do_ioctl = dsa_slave_ioctl, | 782 | .ndo_do_ioctl = dsa_slave_ioctl, |
772 | .ndo_get_iflink = dsa_slave_get_iflink, | 783 | .ndo_get_iflink = dsa_slave_get_iflink, |
773 | #ifdef CONFIG_NET_POLL_CONTROLLER | 784 | #ifdef CONFIG_NET_POLL_CONTROLLER |
@@ -780,6 +791,9 @@ static const struct net_device_ops dsa_slave_netdev_ops = { | |||
780 | static const struct switchdev_ops dsa_slave_switchdev_ops = { | 791 | static const struct switchdev_ops dsa_slave_switchdev_ops = { |
781 | .switchdev_port_attr_get = dsa_slave_port_attr_get, | 792 | .switchdev_port_attr_get = dsa_slave_port_attr_get, |
782 | .switchdev_port_attr_set = dsa_slave_port_attr_set, | 793 | .switchdev_port_attr_set = dsa_slave_port_attr_set, |
794 | .switchdev_port_obj_add = dsa_slave_port_obj_add, | ||
795 | .switchdev_port_obj_del = dsa_slave_port_obj_del, | ||
796 | .switchdev_port_obj_dump = dsa_slave_port_obj_dump, | ||
783 | }; | 797 | }; |
784 | 798 | ||
785 | static void dsa_slave_adjust_link(struct net_device *dev) | 799 | static void dsa_slave_adjust_link(struct net_device *dev) |