summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Pirko <jpirko@redhat.com>2011-07-20 04:54:05 +0000
committerDavid S. Miller <davem@davemloft.net>2011-07-21 13:47:53 -0700
commitcec9c133631039f82e4a5ff3bf47b3eba14ff1aa (patch)
tree073fa703b248a8546a5b14f13998785834736a97
parentf605234066852b11096ab071124e3fe415e94420 (diff)
vlan: introduce __vlan_find_dev_deep()
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>
-rw-r--r--include/linux/if_vlan.h8
-rw-r--r--net/8021q/vlan_core.c21
2 files changed, 29 insertions, 0 deletions
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index cfb0cf2230a..69391cc20f3 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -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();
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index fcc684678af..5940366fac4 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -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;