diff options
author | Guenter Roeck <linux@roeck-us.net> | 2015-03-26 21:36:37 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-29 16:23:54 -0400 |
commit | 339d82626d225e9b876665e4e89b7eb123e96b3d (patch) | |
tree | 03ef0d816547cd8423c6c2e89c651926fb228bb8 /net/dsa | |
parent | 3f244abb53665bf1ae0a762bb452d33b6648b7df (diff) |
net: dsa: Add basic framework to support ndo_fdb functions
Provide callbacks for ndo_fdb_add, ndo_fdb_del, and ndo_fdb_dump.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Tested-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dsa')
-rw-r--r-- | net/dsa/slave.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 39555f3f263b..3597724ec3d8 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c | |||
@@ -201,6 +201,105 @@ out: | |||
201 | return 0; | 201 | return 0; |
202 | } | 202 | } |
203 | 203 | ||
204 | static int dsa_slave_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], | ||
205 | struct net_device *dev, | ||
206 | const unsigned char *addr, u16 vid, u16 nlm_flags) | ||
207 | { | ||
208 | struct dsa_slave_priv *p = netdev_priv(dev); | ||
209 | struct dsa_switch *ds = p->parent; | ||
210 | int ret = -EOPNOTSUPP; | ||
211 | |||
212 | if (ds->drv->fdb_add) | ||
213 | ret = ds->drv->fdb_add(ds, p->port, addr, vid); | ||
214 | |||
215 | return ret; | ||
216 | } | ||
217 | |||
218 | static int dsa_slave_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], | ||
219 | struct net_device *dev, | ||
220 | const unsigned char *addr, u16 vid) | ||
221 | { | ||
222 | struct dsa_slave_priv *p = netdev_priv(dev); | ||
223 | struct dsa_switch *ds = p->parent; | ||
224 | int ret = -EOPNOTSUPP; | ||
225 | |||
226 | if (ds->drv->fdb_del) | ||
227 | ret = ds->drv->fdb_del(ds, p->port, addr, vid); | ||
228 | |||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | static int dsa_slave_fill_info(struct net_device *dev, struct sk_buff *skb, | ||
233 | const unsigned char *addr, u16 vid, | ||
234 | bool is_static, | ||
235 | u32 portid, u32 seq, int type, | ||
236 | unsigned int flags) | ||
237 | { | ||
238 | struct nlmsghdr *nlh; | ||
239 | struct ndmsg *ndm; | ||
240 | |||
241 | nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags); | ||
242 | if (!nlh) | ||
243 | return -EMSGSIZE; | ||
244 | |||
245 | ndm = nlmsg_data(nlh); | ||
246 | ndm->ndm_family = AF_BRIDGE; | ||
247 | ndm->ndm_pad1 = 0; | ||
248 | ndm->ndm_pad2 = 0; | ||
249 | ndm->ndm_flags = NTF_EXT_LEARNED; | ||
250 | ndm->ndm_type = 0; | ||
251 | ndm->ndm_ifindex = dev->ifindex; | ||
252 | ndm->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; | ||
253 | |||
254 | if (nla_put(skb, NDA_LLADDR, ETH_ALEN, addr)) | ||
255 | goto nla_put_failure; | ||
256 | |||
257 | if (vid && nla_put_u16(skb, NDA_VLAN, vid)) | ||
258 | goto nla_put_failure; | ||
259 | |||
260 | nlmsg_end(skb, nlh); | ||
261 | return 0; | ||
262 | |||
263 | nla_put_failure: | ||
264 | nlmsg_cancel(skb, nlh); | ||
265 | return -EMSGSIZE; | ||
266 | } | ||
267 | |||
268 | /* Dump information about entries, in response to GETNEIGH */ | ||
269 | static int dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, | ||
270 | struct net_device *dev, | ||
271 | struct net_device *filter_dev, int idx) | ||
272 | { | ||
273 | struct dsa_slave_priv *p = netdev_priv(dev); | ||
274 | struct dsa_switch *ds = p->parent; | ||
275 | unsigned char addr[ETH_ALEN] = { 0 }; | ||
276 | int ret; | ||
277 | |||
278 | if (!ds->drv->fdb_getnext) | ||
279 | return -EOPNOTSUPP; | ||
280 | |||
281 | for (; ; idx++) { | ||
282 | bool is_static; | ||
283 | |||
284 | ret = ds->drv->fdb_getnext(ds, p->port, addr, &is_static); | ||
285 | if (ret < 0) | ||
286 | break; | ||
287 | |||
288 | if (idx < cb->args[0]) | ||
289 | continue; | ||
290 | |||
291 | ret = dsa_slave_fill_info(dev, skb, addr, 0, | ||
292 | is_static, | ||
293 | NETLINK_CB(cb->skb).portid, | ||
294 | cb->nlh->nlmsg_seq, | ||
295 | RTM_NEWNEIGH, NLM_F_MULTI); | ||
296 | if (ret < 0) | ||
297 | break; | ||
298 | } | ||
299 | |||
300 | return idx; | ||
301 | } | ||
302 | |||
204 | static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | 303 | static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
205 | { | 304 | { |
206 | struct dsa_slave_priv *p = netdev_priv(dev); | 305 | struct dsa_slave_priv *p = netdev_priv(dev); |
@@ -572,6 +671,9 @@ static const struct net_device_ops dsa_slave_netdev_ops = { | |||
572 | .ndo_change_rx_flags = dsa_slave_change_rx_flags, | 671 | .ndo_change_rx_flags = dsa_slave_change_rx_flags, |
573 | .ndo_set_rx_mode = dsa_slave_set_rx_mode, | 672 | .ndo_set_rx_mode = dsa_slave_set_rx_mode, |
574 | .ndo_set_mac_address = dsa_slave_set_mac_address, | 673 | .ndo_set_mac_address = dsa_slave_set_mac_address, |
674 | .ndo_fdb_add = dsa_slave_fdb_add, | ||
675 | .ndo_fdb_del = dsa_slave_fdb_del, | ||
676 | .ndo_fdb_dump = dsa_slave_fdb_dump, | ||
575 | .ndo_do_ioctl = dsa_slave_ioctl, | 677 | .ndo_do_ioctl = dsa_slave_ioctl, |
576 | }; | 678 | }; |
577 | 679 | ||