Have the ingress helpers return the resolved vlan entry directly and let callers derive the vid from it. This keeps the vlan available for later fdb operations without carrying parallel vlan pointer and vid.
Reviewed-by: Ido Schimmel <[email protected]> Signed-off-by: Nikolay Aleksandrov <[email protected]> --- net/bridge/br_device.c | 5 +++-- net/bridge/br_input.c | 14 ++++++++------ net/bridge/br_private.h | 12 +++++++----- net/bridge/br_vlan.c | 38 +++++++++++++++++++++----------------- 4 files changed, 39 insertions(+), 30 deletions(-) diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index c6804409b60b..2423d69f2498 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -65,9 +65,10 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) skb_reset_mac_header(skb); skb_pull(skb, ETH_HLEN); - if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &vid, - &state, &vlan)) + if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &state, + &vlan)) goto out; + vid = vlan ? vlan->vid : 0; if (IS_ENABLED(CONFIG_INET) && (eth_hdr(skb)->h_proto == htons(ETH_P_ARP) || diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 68aa8fa52eba..d9a0e1f65ec9 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -86,8 +86,8 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb struct net_bridge_vlan *vlan; struct net_bridge *br; bool promisc; - u16 vid = 0; u8 state; + u16 vid; if (!p) goto drop; @@ -107,9 +107,10 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb brmctx = &p->br->multicast_ctx; pmctx = &p->multicast_ctx; - if (!br_allowed_ingress(p->br, nbp_vlan_group_rcu(p), skb, &vid, - &state, &vlan)) + if (!br_allowed_ingress(p->br, nbp_vlan_group_rcu(p), skb, &state, + &vlan)) goto out; + vid = vlan ? vlan->vid : 0; if (test_bit(BR_PORT_LOCKED_BIT, &p->flags)) { struct net_bridge_fdb_entry *fdb_src = @@ -245,14 +246,15 @@ EXPORT_SYMBOL_GPL(br_handle_frame_finish); static void __br_handle_local_finish(struct sk_buff *skb) { struct net_bridge_port *p = br_port_get_rcu(skb->dev); - u16 vid = 0; + struct net_bridge_vlan *vlan; /* check if vlan is allowed, to avoid spoofing */ if (test_bit(BR_LEARNING_BIT, &p->flags) && nbp_state_should_learn(p) && !br_opt_get(p->br, BROPT_NO_LL_LEARN) && - br_should_learn(p, skb, &vid)) - br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, 0); + br_should_learn(p, skb, &vlan)) + br_fdb_update(p->br, p, eth_hdr(skb)->h_source, + vlan ? vlan->vid : 0, 0); } /* note: already called with rcu_read_lock */ diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 2bf7f4429a3b..34e95741b940 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -1702,11 +1702,11 @@ br_multicast_ctx_options_equal(const struct net_bridge_mcast *brmctx1, #ifdef CONFIG_BRIDGE_VLAN_FILTERING bool br_allowed_ingress(const struct net_bridge *br, struct net_bridge_vlan_group *vg, struct sk_buff *skb, - u16 *vid, u8 *state, - struct net_bridge_vlan **vlan); + u8 *state, struct net_bridge_vlan **vlan); bool br_allowed_egress(struct net_bridge_vlan_group *vg, const struct sk_buff *skb); -bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid); +bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, + struct net_bridge_vlan **vlan); struct sk_buff *br_handle_vlan(struct net_bridge *br, const struct net_bridge_port *port, struct net_bridge_vlan_group *vg, @@ -1825,7 +1825,7 @@ static inline u16 br_vlan_flags(const struct net_bridge_vlan *v, u16 pvid) static inline bool br_allowed_ingress(const struct net_bridge *br, struct net_bridge_vlan_group *vg, struct sk_buff *skb, - u16 *vid, u8 *state, + u8 *state, struct net_bridge_vlan **vlan) { @@ -1840,8 +1840,10 @@ static inline bool br_allowed_egress(struct net_bridge_vlan_group *vg, } static inline bool br_should_learn(struct net_bridge_port *p, - struct sk_buff *skb, u16 *vid) + struct sk_buff *skb, + struct net_bridge_vlan **vlan) { + *vlan = NULL; return true; } diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index ce5aa15c4540..471b4e7f0571 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -583,13 +583,13 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br, /* Called under RCU */ static bool __allowed_ingress(const struct net_bridge *br, struct net_bridge_vlan_group *vg, - struct sk_buff *skb, u16 *vid, - u8 *state, + struct sk_buff *skb, u8 *state, struct net_bridge_vlan **vlan) { struct pcpu_sw_netstats *stats; struct net_bridge_vlan *v; bool tagged; + u16 vid; BR_INPUT_SKB_CB(skb)->vlan_filtered = true; /* If vlan tx offload is disabled on bridge device and frame was @@ -603,7 +603,7 @@ static bool __allowed_ingress(const struct net_bridge *br, return false; } - if (!br_vlan_get_tag(skb, vid)) { + if (!br_vlan_get_tag(skb, &vid)) { /* Tagged frame */ if (skb->vlan_proto != br->vlan_proto) { /* Protocol-mismatch, empty out vlan_tci for new tag */ @@ -615,7 +615,7 @@ static bool __allowed_ingress(const struct net_bridge *br, skb_pull(skb, ETH_HLEN); skb_reset_mac_len(skb); - *vid = 0; + vid = 0; tagged = false; } else { tagged = true; @@ -625,7 +625,7 @@ static bool __allowed_ingress(const struct net_bridge *br, tagged = false; } - if (!*vid) { + if (!vid) { v = vg ? rcu_dereference(vg->pvid) : NULL; /* 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 @@ -637,7 +637,6 @@ static bool __allowed_ingress(const struct net_bridge *br, /* PVID is set on this port. Any untagged or priority-tagged * ingress frame is considered to belong to this vlan. */ - *vid = v->vid; if (likely(!tagged)) /* Untagged Frame. */ __vlan_hwaccel_put_tag(skb, br->vlan_proto, v->vid); @@ -649,7 +648,7 @@ static bool __allowed_ingress(const struct net_bridge *br, */ skb->vlan_tci |= v->vid; } else { - v = br_vlan_find(vg, *vid); + v = br_vlan_find(vg, vid); } if (!v || !br_vlan_should_use(v)) @@ -680,8 +679,7 @@ static bool __allowed_ingress(const struct net_bridge *br, bool br_allowed_ingress(const struct net_bridge *br, struct net_bridge_vlan_group *vg, struct sk_buff *skb, - u16 *vid, u8 *state, - struct net_bridge_vlan **vlan) + u8 *state, struct net_bridge_vlan **vlan) { /* If VLAN filtering is disabled on the bridge, all packets are * permitted. @@ -692,7 +690,7 @@ bool br_allowed_ingress(const struct net_bridge *br, return true; } - return __allowed_ingress(br, vg, skb, vid, state, vlan); + return __allowed_ingress(br, vg, skb, state, vlan); } /* Called under RCU. */ @@ -716,11 +714,15 @@ bool br_allowed_egress(struct net_bridge_vlan_group *vg, } /* Called under RCU */ -bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid) +bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, + struct net_bridge_vlan **vlan) { struct net_bridge_vlan_group *vg; struct net_bridge *br = p->br; struct net_bridge_vlan *v; + u16 vid; + + *vlan = NULL; /* If filtering was disabled at input, let it pass. */ if (!br_opt_get(br, BROPT_VLAN_ENABLED)) @@ -730,20 +732,22 @@ bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid) if (!vg || !READ_ONCE(vg->num_vlans)) return false; - if (!br_vlan_get_tag(skb, vid) && skb->vlan_proto != br->vlan_proto) - *vid = 0; + if (!br_vlan_get_tag(skb, &vid) && skb->vlan_proto != br->vlan_proto) + vid = 0; - if (!*vid) { + if (!vid) { v = rcu_dereference(vg->pvid); if (!v || !br_vlan_state_allowed(br_vlan_get_state(v), true)) return false; - *vid = v->vid; + *vlan = v; return true; } - v = br_vlan_find(vg, *vid); - if (v && br_vlan_state_allowed(br_vlan_get_state(v), true)) + v = br_vlan_find(vg, vid); + if (v && br_vlan_state_allowed(br_vlan_get_state(v), true)) { + *vlan = v; return true; + } return false; } -- 2.47.3
