* [PATCH v2 0/1] Fix bridge mac_len handling @ 2019-08-05 15:37 Zahari Doychev 2019-08-05 15:37 ` [PATCH v2 1/1] net: bridge: use mac_len in bridge forwarding Zahari Doychev 0 siblings, 1 reply; 5+ messages in thread From: Zahari Doychev @ 2019-08-05 15:37 UTC (permalink / raw) To: netdev Cc: bridge, nikolay, roopa, jhs, dsahern, simon.horman, makita.toshiaki, xiyou.wangcong, jiri, ast, johannes, Zahari Doychev After the last discussion about the possible solution of the problem. I have decided to resend the patches making the discussed corrections. It seems that the patches are still not the complete solution as there still can be problem handling skb->data pointing after the VLAN tag but I got the impression that all agreed that the bridge code should be able to handle mac_len correctly. Here again the description how to problem can be reproduce. The Linux bridge does not correctly forward double vlan tagged packets added using the tc act_vlan action. I am using a bridge with two netdevs and on one of them a have the clsact qdisc with tc flower rule adding two vlan tags. ip link add name br0 type bridge vlan_filtering 1 ip link set dev br0 up ip link set dev net0 up ip link set dev net0 master br0 ip link set dev net1 up ip link set dev net1 master br0 bridge vlan add dev net0 vid 100 master bridge vlan add dev br0 vid 100 self bridge vlan add dev net1 vid 100 master tc qdisc add dev net0 handle ffff: clsact tc qdisc add dev net1 handle ffff: clsact tc filter add dev net0 ingress pref 1 protocol all flower \ action vlan push id 10 pipe action vlan push id 100 tc filter add dev net0 egress pref 1 protocol 802.1q flower \ vlan_id 100 vlan_ethtype 802.1q cvlan_id 10 \ action vlan pop pipe action vlan pop When using the setup above the packets coming on net0 get double tagged but the MAC headers gets corrupted when the packets go out of net1. The second vlan header is not considered in br_dev_queue_push_xmit. The skb data pointer is decremented only by the ETH_HLEN length. This later causes the function validate_xmit_vlan to insert the outer vlan tag behind the inner vlan tag. The inner vlan becomes in this way part of the source mac address. The problem in the bridge forwarding is fixed by using the mac_len when using skb_push before forwarding the packets which ensures that the skb->data is set correctly on push/pull. Changes from v1: - reset mac_len in br_dev_xmit Zahari Doychev (1): net: bridge: use mac_len in bridge forwarding net/bridge/br_device.c | 3 ++- net/bridge/br_forward.c | 4 ++-- net/bridge/br_vlan.c | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) -- 2.22.0 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 1/1] net: bridge: use mac_len in bridge forwarding 2019-08-05 15:37 [PATCH v2 0/1] Fix bridge mac_len handling Zahari Doychev @ 2019-08-05 15:37 ` Zahari Doychev 2019-08-07 9:17 ` Nikolay Aleksandrov 0 siblings, 1 reply; 5+ messages in thread From: Zahari Doychev @ 2019-08-05 15:37 UTC (permalink / raw) To: netdev Cc: bridge, nikolay, roopa, jhs, dsahern, simon.horman, makita.toshiaki, xiyou.wangcong, jiri, ast, johannes, Zahari Doychev The bridge code cannot forward packets from various paths that set up the SKBs in different ways. Some of these packets get corrupted during the forwarding as not always is just ETH_HLEN pulled at the front. This happens e.g. when VLAN tags are pushed bu using tc act_vlan on ingress. The problem is fixed by using skb->mac_len instead of ETH_HLEN, which makes sure that the skb headers are correctly restored. This usually does not change anything, execpt the local bridge transmits which now need to set the skb->mac_len correctly in br_dev_xmit, as well as the broken case noted above. Signed-off-by: Zahari Doychev <zahari.doychev@linux.com> --- net/bridge/br_device.c | 3 ++- net/bridge/br_forward.c | 4 ++-- net/bridge/br_vlan.c | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 681b72862c16..aeb77ff60311 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -55,8 +55,9 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) BR_INPUT_SKB_CB(skb)->frag_max_size = 0; skb_reset_mac_header(skb); + skb_reset_mac_len(skb); eth = eth_hdr(skb); - skb_pull(skb, ETH_HLEN); + skb_pull(skb, skb->mac_len); if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &vid)) goto out; diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 86637000f275..edb4f3533f05 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -32,7 +32,7 @@ static inline int should_deliver(const struct net_bridge_port *p, int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb) { - skb_push(skb, ETH_HLEN); + skb_push(skb, skb->mac_len); if (!is_skb_forwardable(skb->dev, skb)) goto drop; @@ -94,7 +94,7 @@ static void __br_forward(const struct net_bridge_port *to, net = dev_net(indev); } else { if (unlikely(netpoll_tx_running(to->br->dev))) { - skb_push(skb, ETH_HLEN); + skb_push(skb, skb->mac_len); if (!is_skb_forwardable(skb->dev, skb)) kfree_skb(skb); else diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 021cc9f66804..88244c9cc653 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -466,13 +466,14 @@ static bool __allowed_ingress(const struct net_bridge *br, /* Tagged frame */ if (skb->vlan_proto != br->vlan_proto) { /* Protocol-mismatch, empty out vlan_tci for new tag */ - skb_push(skb, ETH_HLEN); + skb_push(skb, skb->mac_len); skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto, skb_vlan_tag_get(skb)); if (unlikely(!skb)) return false; skb_pull(skb, ETH_HLEN); + skb_reset_network_header(skb); skb_reset_mac_len(skb); *vid = 0; tagged = false; -- 2.22.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 1/1] net: bridge: use mac_len in bridge forwarding 2019-08-05 15:37 ` [PATCH v2 1/1] net: bridge: use mac_len in bridge forwarding Zahari Doychev @ 2019-08-07 9:17 ` Nikolay Aleksandrov 2019-08-08 8:04 ` Zahari Doychev 0 siblings, 1 reply; 5+ messages in thread From: Nikolay Aleksandrov @ 2019-08-07 9:17 UTC (permalink / raw) To: Zahari Doychev, netdev Cc: bridge, roopa, jhs, dsahern, simon.horman, makita.toshiaki, xiyou.wangcong, jiri, ast, johannes Hi Zahari, On 05/08/2019 18:37, Zahari Doychev wrote: > The bridge code cannot forward packets from various paths that set up the > SKBs in different ways. Some of these packets get corrupted during the > forwarding as not always is just ETH_HLEN pulled at the front. This happens > e.g. when VLAN tags are pushed bu using tc act_vlan on ingress. Overall the patch looks good, I think it shouldn't introduce any regressions at least from the codepaths I was able to inspect, but please include more details in here from the cover letter, in fact you don't need it just add all of the details here so we have them, especially the test setup. Also please provide some details how this patch was tested. It'd be great if you could provide a selftest for it so we can make sure it's considered when doing future changes. Thank you, Nik > > The problem is fixed by using skb->mac_len instead of ETH_HLEN, which makes > sure that the skb headers are correctly restored. This usually does not > change anything, execpt the local bridge transmits which now need to set > the skb->mac_len correctly in br_dev_xmit, as well as the broken case noted > above. > > Signed-off-by: Zahari Doychev <zahari.doychev@linux.com> > --- > net/bridge/br_device.c | 3 ++- > net/bridge/br_forward.c | 4 ++-- > net/bridge/br_vlan.c | 3 ++- > 3 files changed, 6 insertions(+), 4 deletions(-) > > diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c > index 681b72862c16..aeb77ff60311 100644 > --- a/net/bridge/br_device.c > +++ b/net/bridge/br_device.c > @@ -55,8 +55,9 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) > BR_INPUT_SKB_CB(skb)->frag_max_size = 0; > > skb_reset_mac_header(skb); > + skb_reset_mac_len(skb); > eth = eth_hdr(skb); > - skb_pull(skb, ETH_HLEN); > + skb_pull(skb, skb->mac_len); > > if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &vid)) > goto out; > diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c > index 86637000f275..edb4f3533f05 100644 > --- a/net/bridge/br_forward.c > +++ b/net/bridge/br_forward.c > @@ -32,7 +32,7 @@ static inline int should_deliver(const struct net_bridge_port *p, > > int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb) > { > - skb_push(skb, ETH_HLEN); > + skb_push(skb, skb->mac_len); > if (!is_skb_forwardable(skb->dev, skb)) > goto drop; > > @@ -94,7 +94,7 @@ static void __br_forward(const struct net_bridge_port *to, > net = dev_net(indev); > } else { > if (unlikely(netpoll_tx_running(to->br->dev))) { > - skb_push(skb, ETH_HLEN); > + skb_push(skb, skb->mac_len); > if (!is_skb_forwardable(skb->dev, skb)) > kfree_skb(skb); > else > diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c > index 021cc9f66804..88244c9cc653 100644 > --- a/net/bridge/br_vlan.c > +++ b/net/bridge/br_vlan.c > @@ -466,13 +466,14 @@ static bool __allowed_ingress(const struct net_bridge *br, > /* Tagged frame */ > if (skb->vlan_proto != br->vlan_proto) { > /* Protocol-mismatch, empty out vlan_tci for new tag */ > - skb_push(skb, ETH_HLEN); > + skb_push(skb, skb->mac_len); > skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto, > skb_vlan_tag_get(skb)); > if (unlikely(!skb)) > return false; > > skb_pull(skb, ETH_HLEN); > + skb_reset_network_header(skb); > skb_reset_mac_len(skb); > *vid = 0; > tagged = false; > ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2 1/1] net: bridge: use mac_len in bridge forwarding 2019-08-07 9:17 ` Nikolay Aleksandrov @ 2019-08-08 8:04 ` Zahari Doychev 2019-08-08 8:34 ` Nikolay Aleksandrov 0 siblings, 1 reply; 5+ messages in thread From: Zahari Doychev @ 2019-08-08 8:04 UTC (permalink / raw) To: Nikolay Aleksandrov Cc: netdev, bridge, roopa, jhs, dsahern, simon.horman, makita.toshiaki, xiyou.wangcong, jiri, ast, johannes, alexei.starovoitov On Wed, Aug 07, 2019 at 12:17:43PM +0300, Nikolay Aleksandrov wrote: > Hi Zahari, > On 05/08/2019 18:37, Zahari Doychev wrote: > > The bridge code cannot forward packets from various paths that set up the > > SKBs in different ways. Some of these packets get corrupted during the > > forwarding as not always is just ETH_HLEN pulled at the front. This happens > > e.g. when VLAN tags are pushed bu using tc act_vlan on ingress. > Overall the patch looks good, I think it shouldn't introduce any regressions > at least from the codepaths I was able to inspect, but please include more > details in here from the cover letter, in fact you don't need it just add all of > the details here so we have them, especially the test setup. Also please provide > some details how this patch was tested. It'd be great if you could provide a > selftest for it so we can make sure it's considered when doing future changes. Hi Nik, Thanks for the reply. I will do the suggested corrections and try creating a selftest. I assume it should go to the net/forwarding together with the other bridge tests as a separate patch. Regards, Zahari > > Thank you, > Nik > > > > > The problem is fixed by using skb->mac_len instead of ETH_HLEN, which makes > > sure that the skb headers are correctly restored. This usually does not > > change anything, execpt the local bridge transmits which now need to set > > the skb->mac_len correctly in br_dev_xmit, as well as the broken case noted > > above. > > > > Signed-off-by: Zahari Doychev <zahari.doychev@linux.com> > > --- > > net/bridge/br_device.c | 3 ++- > > net/bridge/br_forward.c | 4 ++-- > > net/bridge/br_vlan.c | 3 ++- > > 3 files changed, 6 insertions(+), 4 deletions(-) > > > > diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c > > index 681b72862c16..aeb77ff60311 100644 > > --- a/net/bridge/br_device.c > > +++ b/net/bridge/br_device.c > > @@ -55,8 +55,9 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) > > BR_INPUT_SKB_CB(skb)->frag_max_size = 0; > > > > skb_reset_mac_header(skb); > > + skb_reset_mac_len(skb); > > eth = eth_hdr(skb); > > - skb_pull(skb, ETH_HLEN); > > + skb_pull(skb, skb->mac_len); > > > > if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &vid)) > > goto out; > > diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c > > index 86637000f275..edb4f3533f05 100644 > > --- a/net/bridge/br_forward.c > > +++ b/net/bridge/br_forward.c > > @@ -32,7 +32,7 @@ static inline int should_deliver(const struct net_bridge_port *p, > > > > int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb) > > { > > - skb_push(skb, ETH_HLEN); > > + skb_push(skb, skb->mac_len); > > if (!is_skb_forwardable(skb->dev, skb)) > > goto drop; > > > > @@ -94,7 +94,7 @@ static void __br_forward(const struct net_bridge_port *to, > > net = dev_net(indev); > > } else { > > if (unlikely(netpoll_tx_running(to->br->dev))) { > > - skb_push(skb, ETH_HLEN); > > + skb_push(skb, skb->mac_len); > > if (!is_skb_forwardable(skb->dev, skb)) > > kfree_skb(skb); > > else > > diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c > > index 021cc9f66804..88244c9cc653 100644 > > --- a/net/bridge/br_vlan.c > > +++ b/net/bridge/br_vlan.c > > @@ -466,13 +466,14 @@ static bool __allowed_ingress(const struct net_bridge *br, > > /* Tagged frame */ > > if (skb->vlan_proto != br->vlan_proto) { > > /* Protocol-mismatch, empty out vlan_tci for new tag */ > > - skb_push(skb, ETH_HLEN); > > + skb_push(skb, skb->mac_len); > > skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto, > > skb_vlan_tag_get(skb)); > > if (unlikely(!skb)) > > return false; > > > > skb_pull(skb, ETH_HLEN); > > + skb_reset_network_header(skb); > > skb_reset_mac_len(skb); > > *vid = 0; > > tagged = false; > > > ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2 1/1] net: bridge: use mac_len in bridge forwarding 2019-08-08 8:04 ` Zahari Doychev @ 2019-08-08 8:34 ` Nikolay Aleksandrov 0 siblings, 0 replies; 5+ messages in thread From: Nikolay Aleksandrov @ 2019-08-08 8:34 UTC (permalink / raw) To: Zahari Doychev Cc: netdev, bridge, roopa, jhs, dsahern, simon.horman, makita.toshiaki, xiyou.wangcong, jiri, ast, johannes, alexei.starovoitov On 08/08/2019 11:04, Zahari Doychev wrote: > On Wed, Aug 07, 2019 at 12:17:43PM +0300, Nikolay Aleksandrov wrote: >> Hi Zahari, >> On 05/08/2019 18:37, Zahari Doychev wrote: >>> The bridge code cannot forward packets from various paths that set up the >>> SKBs in different ways. Some of these packets get corrupted during the >>> forwarding as not always is just ETH_HLEN pulled at the front. This happens >>> e.g. when VLAN tags are pushed bu using tc act_vlan on ingress. >> Overall the patch looks good, I think it shouldn't introduce any regressions >> at least from the codepaths I was able to inspect, but please include more >> details in here from the cover letter, in fact you don't need it just add all of >> the details here so we have them, especially the test setup. Also please provide >> some details how this patch was tested. It'd be great if you could provide a >> selftest for it so we can make sure it's considered when doing future changes. > > Hi Nik, > > Thanks for the reply. I will do the suggested corrections and try creating a > selftest. I assume it should go to the net/forwarding together with the other > bridge tests as a separate patch. > > Regards, > Zahari > Hi, Yes, the selftest should target net-next and go to net/forwarding. Thanks, Nik >> >> Thank you, >> Nik >> >>> >>> The problem is fixed by using skb->mac_len instead of ETH_HLEN, which makes >>> sure that the skb headers are correctly restored. This usually does not >>> change anything, execpt the local bridge transmits which now need to set >>> the skb->mac_len correctly in br_dev_xmit, as well as the broken case noted >>> above. >>> >>> Signed-off-by: Zahari Doychev <zahari.doychev@linux.com> >>> --- >>> net/bridge/br_device.c | 3 ++- >>> net/bridge/br_forward.c | 4 ++-- >>> net/bridge/br_vlan.c | 3 ++- >>> 3 files changed, 6 insertions(+), 4 deletions(-) >>> >>> diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c >>> index 681b72862c16..aeb77ff60311 100644 >>> --- a/net/bridge/br_device.c >>> +++ b/net/bridge/br_device.c >>> @@ -55,8 +55,9 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) >>> BR_INPUT_SKB_CB(skb)->frag_max_size = 0; >>> >>> skb_reset_mac_header(skb); >>> + skb_reset_mac_len(skb); >>> eth = eth_hdr(skb); >>> - skb_pull(skb, ETH_HLEN); >>> + skb_pull(skb, skb->mac_len); >>> >>> if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &vid)) >>> goto out; >>> diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c >>> index 86637000f275..edb4f3533f05 100644 >>> --- a/net/bridge/br_forward.c >>> +++ b/net/bridge/br_forward.c >>> @@ -32,7 +32,7 @@ static inline int should_deliver(const struct net_bridge_port *p, >>> >>> int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb) >>> { >>> - skb_push(skb, ETH_HLEN); >>> + skb_push(skb, skb->mac_len); >>> if (!is_skb_forwardable(skb->dev, skb)) >>> goto drop; >>> >>> @@ -94,7 +94,7 @@ static void __br_forward(const struct net_bridge_port *to, >>> net = dev_net(indev); >>> } else { >>> if (unlikely(netpoll_tx_running(to->br->dev))) { >>> - skb_push(skb, ETH_HLEN); >>> + skb_push(skb, skb->mac_len); >>> if (!is_skb_forwardable(skb->dev, skb)) >>> kfree_skb(skb); >>> else >>> diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c >>> index 021cc9f66804..88244c9cc653 100644 >>> --- a/net/bridge/br_vlan.c >>> +++ b/net/bridge/br_vlan.c >>> @@ -466,13 +466,14 @@ static bool __allowed_ingress(const struct net_bridge *br, >>> /* Tagged frame */ >>> if (skb->vlan_proto != br->vlan_proto) { >>> /* Protocol-mismatch, empty out vlan_tci for new tag */ >>> - skb_push(skb, ETH_HLEN); >>> + skb_push(skb, skb->mac_len); >>> skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto, >>> skb_vlan_tag_get(skb)); >>> if (unlikely(!skb)) >>> return false; >>> >>> skb_pull(skb, ETH_HLEN); >>> + skb_reset_network_header(skb); >>> skb_reset_mac_len(skb); >>> *vid = 0; >>> tagged = false; >>> >> ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2019-08-08 8:34 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2019-08-05 15:37 [PATCH v2 0/1] Fix bridge mac_len handling Zahari Doychev 2019-08-05 15:37 ` [PATCH v2 1/1] net: bridge: use mac_len in bridge forwarding Zahari Doychev 2019-08-07 9:17 ` Nikolay Aleksandrov 2019-08-08 8:04 ` Zahari Doychev 2019-08-08 8:34 ` Nikolay Aleksandrov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox