diff options
author | Nikolay Aleksandrov <nikolay@cumulusnetworks.com> | 2015-09-30 20:16:53 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-10-02 03:24:04 +0200 |
commit | 77751ee8aec3e1748e0d1471ccbfc008793e88a6 (patch) | |
tree | 65776b5154f1e6222c0fea5436cf123a5132be8b /net/bridge/br_vlan.c | |
parent | bridge: vlan: fix possible null vlgrp deref while registering new port (diff) | |
download | linux-77751ee8aec3e1748e0d1471ccbfc008793e88a6.tar.xz linux-77751ee8aec3e1748e0d1471ccbfc008793e88a6.zip |
bridge: vlan: move pvid inside net_bridge_vlan_group
One obvious way to converge more code (which was also used by the
previous vlan code) is to move pvid inside net_bridge_vlan_group. This
allows us to simplify some and remove other port-specific functions.
Also gives us the ability to simply pass the vlan group and use all of the
contained information.
Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_vlan.c')
-rw-r--r-- | net/bridge/br_vlan.c | 103 |
1 files changed, 43 insertions, 60 deletions
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 678d5c41b551..90ac4b0c55c1 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -31,37 +31,37 @@ static struct net_bridge_vlan *br_vlan_lookup(struct rhashtable *tbl, u16 vid) return rhashtable_lookup_fast(tbl, &vid, br_vlan_rht_params); } -static void __vlan_add_pvid(u16 *pvid, u16 vid) +static void __vlan_add_pvid(struct net_bridge_vlan_group *vg, u16 vid) { - if (*pvid == vid) + if (vg->pvid == vid) return; smp_wmb(); - *pvid = vid; + vg->pvid = vid; } -static void __vlan_delete_pvid(u16 *pvid, u16 vid) +static void __vlan_delete_pvid(struct net_bridge_vlan_group *vg, u16 vid) { - if (*pvid != vid) + if (vg->pvid != vid) return; smp_wmb(); - *pvid = 0; + vg->pvid = 0; } static void __vlan_add_flags(struct net_bridge_vlan *v, u16 flags) { - if (flags & BRIDGE_VLAN_INFO_PVID) { - if (br_vlan_is_master(v)) - __vlan_add_pvid(&v->br->pvid, v->vid); - else - __vlan_add_pvid(&v->port->pvid, v->vid); - } else { - if (br_vlan_is_master(v)) - __vlan_delete_pvid(&v->br->pvid, v->vid); - else - __vlan_delete_pvid(&v->port->pvid, v->vid); - } + struct net_bridge_vlan_group *vg; + + if (br_vlan_is_master(v)) + vg = v->br->vlgrp; + else + vg = v->port->vlgrp; + + if (flags & BRIDGE_VLAN_INFO_PVID) + __vlan_add_pvid(vg, v->vid); + else + __vlan_delete_pvid(vg, v->vid); if (flags & BRIDGE_VLAN_INFO_UNTAGGED) v->flags |= BRIDGE_VLAN_INFO_UNTAGGED; @@ -249,25 +249,22 @@ out_filt: static int __vlan_del(struct net_bridge_vlan *v) { struct net_bridge_vlan *masterv = v; + struct net_bridge_vlan_group *vg; struct net_bridge_port *p = NULL; struct net_bridge *br; int err = 0; - struct rhashtable *tbl; - u16 *pvid; if (br_vlan_is_master(v)) { br = v->br; - tbl = &v->br->vlgrp->vlan_hash; - pvid = &v->br->pvid; + vg = v->br->vlgrp; } else { p = v->port; br = p->br; - tbl = &p->vlgrp->vlan_hash; + vg = v->port->vlgrp; masterv = v->brvlan; - pvid = &p->pvid; } - __vlan_delete_pvid(pvid, v->vid); + __vlan_delete_pvid(vg, v->vid); if (p) { err = __vlan_vid_del(p->dev, p->br, v->vid); if (err) @@ -284,7 +281,8 @@ static int __vlan_del(struct net_bridge_vlan *v) } if (masterv != v) { - rhashtable_remove_fast(tbl, &v->vnode, br_vlan_rht_params); + rhashtable_remove_fast(&vg->vlan_hash, &v->vnode, + br_vlan_rht_params); __vlan_del_list(v); kfree_rcu(v, rcu); } @@ -299,11 +297,11 @@ out: return err; } -static void __vlan_flush(struct net_bridge_vlan_group *vlgrp, u16 *pvid) +static void __vlan_flush(struct net_bridge_vlan_group *vlgrp) { struct net_bridge_vlan *vlan, *tmp; - __vlan_delete_pvid(pvid, *pvid); + __vlan_delete_pvid(vlgrp, vlgrp->pvid); list_for_each_entry_safe(vlan, tmp, &vlgrp->vlan_list, vlist) __vlan_del(vlan); rhashtable_destroy(&vlgrp->vlan_hash); @@ -348,7 +346,7 @@ out: } /* Called under RCU */ -static bool __allowed_ingress(struct rhashtable *tbl, u16 pvid, __be16 proto, +static bool __allowed_ingress(struct net_bridge_vlan_group *vg, __be16 proto, struct sk_buff *skb, u16 *vid) { const struct net_bridge_vlan *v; @@ -389,6 +387,8 @@ static bool __allowed_ingress(struct rhashtable *tbl, u16 pvid, __be16 proto, } if (!*vid) { + u16 pvid = br_get_pvid(vg); + /* Frame had a tag with VID 0 or did not have a tag. * See if pvid is set on this port. That tells us which * vlan untagged or priority-tagged traffic belongs to. @@ -415,7 +415,7 @@ static bool __allowed_ingress(struct rhashtable *tbl, u16 pvid, __be16 proto, } /* Frame had a valid vlan tag. See if vlan is allowed */ - v = br_vlan_lookup(tbl, *vid); + v = br_vlan_find(vg, *vid); if (v && br_vlan_should_use(v)) return true; drop: @@ -423,7 +423,9 @@ drop: return false; } -bool br_allowed_ingress(struct net_bridge *br, struct sk_buff *skb, u16 *vid) +bool br_allowed_ingress(const struct net_bridge *br, + struct net_bridge_vlan_group *vg, struct sk_buff *skb, + u16 *vid) { /* If VLAN filtering is disabled on the bridge, all packets are * permitted. @@ -433,25 +435,7 @@ bool br_allowed_ingress(struct net_bridge *br, struct sk_buff *skb, u16 *vid) return true; } - return __allowed_ingress(&br->vlgrp->vlan_hash, br->pvid, - br->vlan_proto, skb, vid); -} - -bool nbp_allowed_ingress(struct net_bridge_port *p, struct sk_buff *skb, - u16 *vid) -{ - struct net_bridge *br = p->br; - - /* If VLAN filtering is disabled on the bridge, all packets are - * permitted. - */ - if (!br->vlan_enabled) { - BR_INPUT_SKB_CB(skb)->vlan_filtered = false; - return true; - } - - return __allowed_ingress(&p->vlgrp->vlan_hash, p->pvid, br->vlan_proto, - skb, vid); + return __allowed_ingress(vg, br->vlan_proto, skb, vid); } /* Called under RCU. */ @@ -491,14 +475,14 @@ bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid) *vid = 0; if (!*vid) { - *vid = nbp_get_pvid(p); + *vid = br_get_pvid(vg); if (!*vid) return false; return true; } - if (br_vlan_find(p->vlgrp, *vid)) + if (br_vlan_find(vg, *vid)) return true; return false; @@ -574,7 +558,7 @@ void br_vlan_flush(struct net_bridge *br) { ASSERT_RTNL(); - __vlan_flush(br_vlan_group(br), &br->pvid); + __vlan_flush(br_vlan_group(br)); } struct net_bridge_vlan *br_vlan_find(struct net_bridge_vlan_group *vg, u16 vid) @@ -695,12 +679,11 @@ int br_vlan_set_proto(struct net_bridge *br, unsigned long val) return err; } -static bool vlan_default_pvid(struct net_bridge_vlan_group *vg, u16 pvid, - u16 vid) +static bool vlan_default_pvid(struct net_bridge_vlan_group *vg, u16 vid) { struct net_bridge_vlan *v; - if (vid != pvid) + if (vid != vg->pvid) return false; v = br_vlan_lookup(&vg->vlan_hash, vid); @@ -719,11 +702,11 @@ static void br_vlan_disable_default_pvid(struct net_bridge *br) /* Disable default_pvid on all ports where it is still * configured. */ - if (vlan_default_pvid(br->vlgrp, br->pvid, pvid)) + if (vlan_default_pvid(br->vlgrp, pvid)) br_vlan_delete(br, pvid); list_for_each_entry(p, &br->port_list, list) { - if (vlan_default_pvid(p->vlgrp, p->pvid, pvid)) + if (vlan_default_pvid(p->vlgrp, pvid)) nbp_vlan_delete(p, pvid); } @@ -749,7 +732,7 @@ static int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid) * user configuration. */ pvent = br_vlan_find(br->vlgrp, pvid); - if ((!old_pvid || vlan_default_pvid(br->vlgrp, br->pvid, old_pvid)) && + if ((!old_pvid || vlan_default_pvid(br->vlgrp, old_pvid)) && (!pvent || !br_vlan_should_use(pvent))) { err = br_vlan_add(br, pvid, BRIDGE_VLAN_INFO_PVID | @@ -766,7 +749,7 @@ static int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid) * user configuration. */ if ((old_pvid && - !vlan_default_pvid(p->vlgrp, p->pvid, old_pvid)) || + !vlan_default_pvid(p->vlgrp, old_pvid)) || br_vlan_find(p->vlgrp, pvid)) continue; @@ -955,5 +938,5 @@ void nbp_vlan_flush(struct net_bridge_port *port) list_for_each_entry(vlan, &port->vlgrp->vlan_list, vlist) vlan_vid_del(port->dev, port->br->vlan_proto, vlan->vid); - __vlan_flush(nbp_vlan_group(port), &port->pvid); + __vlan_flush(nbp_vlan_group(port)); } |