vlan: introduce __vlan_find_dev_deep()
authorJiri Pirko <jpirko@redhat.com>
Wed, 20 Jul 2011 04:54:05 +0000 (04:54 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 21 Jul 2011 20:47:53 +0000 (13:47 -0700)
Since vlan_group_get_device and vlan_group is not going to be accessible
from device drivers, introduce function which substitutes it.

Signed-off-by: Jiri Pirko <jpirko@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/if_vlan.h
net/8021q/vlan_core.c

index cfb0cf2230a9b3289e55ba5f68c322e0b3de77f9..69391cc20f3daa78c77314f6f13a76e271a2adfd 100644 (file)
@@ -120,6 +120,8 @@ static inline int is_vlan_dev(struct net_device *dev)
 
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 
+extern struct net_device *__vlan_find_dev_deep(struct net_device *real_dev,
+                                              u16 vlan_id);
 extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
 extern u16 vlan_dev_vlan_id(const struct net_device *dev);
 
@@ -135,6 +137,12 @@ vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp,
               unsigned int vlan_tci);
 
 #else
+static inline struct net_device *
+__vlan_find_dev_deep(struct net_device *real_dev, u16 vlan_id)
+{
+       return NULL;
+}
+
 static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev)
 {
        BUG();
index fcc684678af67e644c6cc043dacee9f4159fb5b4..5940366fac4870b85c442ab02c38e6637707a022 100644 (file)
@@ -63,6 +63,27 @@ bool vlan_do_receive(struct sk_buff **skbp)
        return true;
 }
 
+/* Must be invoked with rcu_read_lock or with RTNL. */
+struct net_device *__vlan_find_dev_deep(struct net_device *real_dev,
+                                       u16 vlan_id)
+{
+       struct vlan_group *grp = rcu_dereference_rtnl(real_dev->vlgrp);
+
+       if (grp) {
+               return vlan_group_get_device(grp, vlan_id);
+       } else {
+               /*
+                * Bonding slaves do not have grp assigned to themselves.
+                * Grp is assigned to bonding master instead.
+                */
+               if (netif_is_bond_slave(real_dev))
+                       return __vlan_find_dev_deep(real_dev->master, vlan_id);
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL(__vlan_find_dev_deep);
+
 struct net_device *vlan_dev_real_dev(const struct net_device *dev)
 {
        return vlan_dev_info(dev)->real_dev;