diff options
author | Vivien Didelot <vivien.didelot@savoirfairelinux.com> | 2015-08-10 09:09:53 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-08-11 15:03:19 -0400 |
commit | ba14d9eb1999cad5b810f1fd97d1cb2d3f00869e (patch) | |
tree | bea9ab8be2cabcd21272cf1afc6f2cfe52852c9b /net/dsa | |
parent | ce80e7bc57e25062c361de8fb6444129a63bac6d (diff) |
net: dsa: add support for switchdev FDB objects
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')
-rw-r--r-- | net/dsa/slave.c | 142 |
1 files changed, 81 insertions, 61 deletions
diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 3d341b694ecf..276758406065 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c | |||
@@ -200,74 +200,38 @@ out: | |||
200 | return 0; | 200 | return 0; |
201 | } | 201 | } |
202 | 202 | ||
203 | static int dsa_slave_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], | 203 | static int dsa_slave_port_fdb_add(struct net_device *dev, |
204 | struct net_device *dev, | 204 | struct switchdev_obj *obj) |
205 | const unsigned char *addr, u16 vid, u16 nlm_flags) | ||
206 | { | 205 | { |
206 | struct switchdev_obj_fdb *fdb = &obj->u.fdb; | ||
207 | struct dsa_slave_priv *p = netdev_priv(dev); | 207 | struct dsa_slave_priv *p = netdev_priv(dev); |
208 | struct dsa_switch *ds = p->parent; | 208 | struct dsa_switch *ds = p->parent; |
209 | int ret = -EOPNOTSUPP; | 209 | int ret = -EOPNOTSUPP; |
210 | 210 | ||
211 | if (ds->drv->port_fdb_add) | 211 | if (obj->trans == SWITCHDEV_TRANS_PREPARE) |
212 | ret = ds->drv->port_fdb_add(ds, p->port, addr, vid); | 212 | ret = ds->drv->port_fdb_add ? 0 : -EOPNOTSUPP; |
213 | else if (obj->trans == SWITCHDEV_TRANS_COMMIT) | ||
214 | ret = ds->drv->port_fdb_add(ds, p->port, fdb->addr, fdb->vid); | ||
213 | 215 | ||
214 | return ret; | 216 | return ret; |
215 | } | 217 | } |
216 | 218 | ||
217 | static int dsa_slave_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], | 219 | static int dsa_slave_port_fdb_del(struct net_device *dev, |
218 | struct net_device *dev, | 220 | struct switchdev_obj *obj) |
219 | const unsigned char *addr, u16 vid) | ||
220 | { | 221 | { |
222 | struct switchdev_obj_fdb *fdb = &obj->u.fdb; | ||
221 | struct dsa_slave_priv *p = netdev_priv(dev); | 223 | struct dsa_slave_priv *p = netdev_priv(dev); |
222 | struct dsa_switch *ds = p->parent; | 224 | struct dsa_switch *ds = p->parent; |
223 | int ret = -EOPNOTSUPP; | 225 | int ret = -EOPNOTSUPP; |
224 | 226 | ||
225 | if (ds->drv->port_fdb_del) | 227 | if (ds->drv->port_fdb_del) |
226 | ret = ds->drv->port_fdb_del(ds, p->port, addr, vid); | 228 | ret = ds->drv->port_fdb_del(ds, p->port, fdb->addr, fdb->vid); |
227 | 229 | ||
228 | return ret; | 230 | return ret; |
229 | } | 231 | } |
230 | 232 | ||
231 | static int dsa_slave_fill_info(struct net_device *dev, struct sk_buff *skb, | 233 | static int dsa_slave_port_fdb_dump(struct net_device *dev, |
232 | const unsigned char *addr, u16 vid, | 234 | struct switchdev_obj *obj) |
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 | { | 235 | { |
272 | struct dsa_slave_priv *p = netdev_priv(dev); | 236 | struct dsa_slave_priv *p = netdev_priv(dev); |
273 | struct dsa_switch *ds = p->parent; | 237 | struct dsa_switch *ds = p->parent; |
@@ -278,7 +242,7 @@ static int dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, | |||
278 | if (!ds->drv->port_fdb_getnext) | 242 | if (!ds->drv->port_fdb_getnext) |
279 | return -EOPNOTSUPP; | 243 | return -EOPNOTSUPP; |
280 | 244 | ||
281 | for (; ; idx++) { | 245 | for (;;) { |
282 | bool is_static; | 246 | bool is_static; |
283 | 247 | ||
284 | ret = ds->drv->port_fdb_getnext(ds, p->port, addr, &vid, | 248 | ret = ds->drv->port_fdb_getnext(ds, p->port, addr, &vid, |
@@ -286,19 +250,16 @@ static int dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, | |||
286 | if (ret < 0) | 250 | if (ret < 0) |
287 | break; | 251 | break; |
288 | 252 | ||
289 | if (idx < cb->args[0]) | 253 | obj->u.fdb.addr = addr; |
290 | continue; | 254 | obj->u.fdb.vid = vid; |
255 | obj->u.fdb.ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; | ||
291 | 256 | ||
292 | ret = dsa_slave_fill_info(dev, skb, addr, vid, | 257 | ret = obj->cb(dev, obj); |
293 | is_static, | ||
294 | NETLINK_CB(cb->skb).portid, | ||
295 | cb->nlh->nlmsg_seq, | ||
296 | RTM_NEWNEIGH, NLM_F_MULTI); | ||
297 | if (ret < 0) | 258 | if (ret < 0) |
298 | break; | 259 | break; |
299 | } | 260 | } |
300 | 261 | ||
301 | return idx; | 262 | return ret == -ENOENT ? 0 : ret; |
302 | } | 263 | } |
303 | 264 | ||
304 | static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | 265 | static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
@@ -366,6 +327,62 @@ static int dsa_slave_port_attr_set(struct net_device *dev, | |||
366 | return ret; | 327 | return ret; |
367 | } | 328 | } |
368 | 329 | ||
330 | static int dsa_slave_port_obj_add(struct net_device *dev, | ||
331 | struct switchdev_obj *obj) | ||
332 | { | ||
333 | int err; | ||
334 | |||
335 | /* For the prepare phase, ensure the full set of changes is feasable in | ||
336 | * one go in order to signal a failure properly. If an operation is not | ||
337 | * supported, return -EOPNOTSUPP. | ||
338 | */ | ||
339 | |||
340 | switch (obj->id) { | ||
341 | case SWITCHDEV_OBJ_PORT_FDB: | ||
342 | err = dsa_slave_port_fdb_add(dev, obj); | ||
343 | break; | ||
344 | default: | ||
345 | err = -EOPNOTSUPP; | ||
346 | break; | ||
347 | } | ||
348 | |||
349 | return err; | ||
350 | } | ||
351 | |||
352 | static int dsa_slave_port_obj_del(struct net_device *dev, | ||
353 | struct switchdev_obj *obj) | ||
354 | { | ||
355 | int err; | ||
356 | |||
357 | switch (obj->id) { | ||
358 | case SWITCHDEV_OBJ_PORT_FDB: | ||
359 | err = dsa_slave_port_fdb_del(dev, obj); | ||
360 | break; | ||
361 | default: | ||
362 | err = -EOPNOTSUPP; | ||
363 | break; | ||
364 | } | ||
365 | |||
366 | return err; | ||
367 | } | ||
368 | |||
369 | static int dsa_slave_port_obj_dump(struct net_device *dev, | ||
370 | struct switchdev_obj *obj) | ||
371 | { | ||
372 | int err; | ||
373 | |||
374 | switch (obj->id) { | ||
375 | case SWITCHDEV_OBJ_PORT_FDB: | ||
376 | err = dsa_slave_port_fdb_dump(dev, obj); | ||
377 | break; | ||
378 | default: | ||
379 | err = -EOPNOTSUPP; | ||
380 | break; | ||
381 | } | ||
382 | |||
383 | return err; | ||
384 | } | ||
385 | |||
369 | static int dsa_slave_bridge_port_join(struct net_device *dev, | 386 | static int dsa_slave_bridge_port_join(struct net_device *dev, |
370 | struct net_device *br) | 387 | struct net_device *br) |
371 | { | 388 | { |
@@ -767,9 +784,9 @@ static const struct net_device_ops dsa_slave_netdev_ops = { | |||
767 | .ndo_change_rx_flags = dsa_slave_change_rx_flags, | 784 | .ndo_change_rx_flags = dsa_slave_change_rx_flags, |
768 | .ndo_set_rx_mode = dsa_slave_set_rx_mode, | 785 | .ndo_set_rx_mode = dsa_slave_set_rx_mode, |
769 | .ndo_set_mac_address = dsa_slave_set_mac_address, | 786 | .ndo_set_mac_address = dsa_slave_set_mac_address, |
770 | .ndo_fdb_add = dsa_slave_fdb_add, | 787 | .ndo_fdb_add = switchdev_port_fdb_add, |
771 | .ndo_fdb_del = dsa_slave_fdb_del, | 788 | .ndo_fdb_del = switchdev_port_fdb_del, |
772 | .ndo_fdb_dump = dsa_slave_fdb_dump, | 789 | .ndo_fdb_dump = switchdev_port_fdb_dump, |
773 | .ndo_do_ioctl = dsa_slave_ioctl, | 790 | .ndo_do_ioctl = dsa_slave_ioctl, |
774 | .ndo_get_iflink = dsa_slave_get_iflink, | 791 | .ndo_get_iflink = dsa_slave_get_iflink, |
775 | #ifdef CONFIG_NET_POLL_CONTROLLER | 792 | #ifdef CONFIG_NET_POLL_CONTROLLER |
@@ -782,6 +799,9 @@ static const struct net_device_ops dsa_slave_netdev_ops = { | |||
782 | static const struct switchdev_ops dsa_slave_switchdev_ops = { | 799 | static const struct switchdev_ops dsa_slave_switchdev_ops = { |
783 | .switchdev_port_attr_get = dsa_slave_port_attr_get, | 800 | .switchdev_port_attr_get = dsa_slave_port_attr_get, |
784 | .switchdev_port_attr_set = dsa_slave_port_attr_set, | 801 | .switchdev_port_attr_set = dsa_slave_port_attr_set, |
802 | .switchdev_port_obj_add = dsa_slave_port_obj_add, | ||
803 | .switchdev_port_obj_del = dsa_slave_port_obj_del, | ||
804 | .switchdev_port_obj_dump = dsa_slave_port_obj_dump, | ||
785 | }; | 805 | }; |
786 | 806 | ||
787 | static void dsa_slave_adjust_link(struct net_device *dev) | 807 | static void dsa_slave_adjust_link(struct net_device *dev) |