Commit 12464bb8 authored by Toshiaki Makita's avatar Toshiaki Makita Committed by David S. Miller

bridge: Fix inabillity to retrieve vlan tags when tx offload is disabled

Bridge vlan code (br_vlan_get_tag()) assumes that all frames have vlan_tci
if they are tagged, but if vlan tx offload is manually disabled on bridge
device and frames are sent from vlan device on the bridge device, the tags
are embedded in skb->data and they break this assumption.
Extract embedded vlan tags and move them to vlan_tci at ingress.
Signed-off-by: default avatarToshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Acked-by: default avatarVlad Yasevich <vyasevic@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a39ee449
...@@ -49,14 +49,14 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -49,14 +49,14 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
brstats->tx_bytes += skb->len; brstats->tx_bytes += skb->len;
u64_stats_update_end(&brstats->syncp); u64_stats_update_end(&brstats->syncp);
if (!br_allowed_ingress(br, br_get_vlan_info(br), skb, &vid))
goto out;
BR_INPUT_SKB_CB(skb)->brdev = dev; BR_INPUT_SKB_CB(skb)->brdev = dev;
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
skb_pull(skb, ETH_HLEN); skb_pull(skb, ETH_HLEN);
if (!br_allowed_ingress(br, br_get_vlan_info(br), skb, &vid))
goto out;
if (is_broadcast_ether_addr(dest)) if (is_broadcast_ether_addr(dest))
br_flood_deliver(br, skb, false); br_flood_deliver(br, skb, false);
else if (is_multicast_ether_addr(dest)) { else if (is_multicast_ether_addr(dest)) {
......
...@@ -174,6 +174,18 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v, ...@@ -174,6 +174,18 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
if (!v) if (!v)
return false; return false;
/* If vlan tx offload is disabled on bridge device and frame was
* sent from vlan device on the bridge device, it does not have
* HW accelerated vlan tag.
*/
if (unlikely(!vlan_tx_tag_present(skb) &&
(skb->protocol == htons(ETH_P_8021Q) ||
skb->protocol == htons(ETH_P_8021AD)))) {
skb = vlan_untag(skb);
if (unlikely(!skb))
return false;
}
err = br_vlan_get_tag(skb, vid); err = br_vlan_get_tag(skb, vid);
if (!*vid) { if (!*vid) {
u16 pvid = br_get_pvid(v); u16 pvid = br_get_pvid(v);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment