On Wed, Aug 17, 2016 at 4:02 PM, Jiri Pirko <j...@resnulli.us> wrote: > Wed, Aug 17, 2016 at 01:05:33PM CEST, had...@dev.mellanox.co.il wrote: >>On Wed, Aug 17, 2016 at 1:46 PM, Jiri Pirko <j...@resnulli.us> wrote: >>> Wed, Aug 17, 2016 at 12:36:10PM CEST, had...@mellanox.com wrote: >>>>Early in the datapath skb_vlan_untag function is called, stripped >>>>the vlan from the skb and set skb->vlan_tci and skb->vlan_proto fields. >>>> >>>>The current dissection doesn't handle stripped vlan packets correctly. >>>>In some flows, vlan doesn't exist in skb->data anymore when applying >>>>flow dissection on the skb, fix that. >>>> >>>>In case vlan info wasn't stripped before applying flow_dissector (RPS >>>>flow for example), or in case of skb with multiple vlans (e.g. 802.1ad), >>>>get the vlan info from skb->data. The flow_dissector correctly skips >>>>any number of vlans and stores only the first level vlan. >>>> >>>>Fixes: 0744dd00c1b1 ('net: introduce skb_flow_dissect()') >>>>Signed-off-by: Hadar Hen Zion <had...@mellanox.com> >>>>--- >>>> net/core/flow_dissector.c | 34 ++++++++++++++++++++++++++-------- >>>> 1 file changed, 26 insertions(+), 8 deletions(-) >>>> >>>>diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c >>>>index 91028ae..362d693 100644 >>>>--- a/net/core/flow_dissector.c >>>>+++ b/net/core/flow_dissector.c >>>>@@ -119,12 +119,14 @@ bool __skb_flow_dissect(const struct sk_buff *skb, >>>> struct flow_dissector_key_ports *key_ports; >>>> struct flow_dissector_key_tags *key_tags; >>>> struct flow_dissector_key_keyid *key_keyid; >>>>+ bool skip_vlan = false; >>>> u8 ip_proto = 0; >>>> bool ret = false; >>>> >>>> if (!data) { >>>> data = skb->data; >>>>- proto = skb->protocol; >>>>+ proto = skb_vlan_tag_present(skb) ? >>>>+ skb->vlan_proto : skb->protocol; >>>> nhoff = skb_network_offset(skb); >>>> hlen = skb_headlen(skb); >>>> } >>>>@@ -243,23 +245,39 @@ ipv6: >>>> case htons(ETH_P_8021AD): >>>> case htons(ETH_P_8021Q): { >>>> const struct vlan_hdr *vlan; >>>>- struct vlan_hdr _vlan; >>>> >>>>- vlan = __skb_header_pointer(skb, nhoff, sizeof(_vlan), data, >>>>hlen, &_vlan); >>>>- if (!vlan) >>>>- goto out_bad; >>>>+ if (skb_vlan_tag_present(skb)) >>>>+ proto = skb->protocol; >>>>+ >>>>+ if (!skb_vlan_tag_present(skb) || >>>>+ proto == cpu_to_be16(ETH_P_8021Q) || >>>>+ proto == cpu_to_be16(ETH_P_8021AD)) { >>> >>> How this can happen? Could you give me an example? >>> >> >>This can happen in 2 cases: >> >>1. vlan wasn't stripped yet from the skb. >>In RPS flow for example, get_rps_cpu function is using flow-dissector >>before vlan_untag is called by __netif_receive_skb_core. > > right, sigh... > > >> >>2. skb with multiple vlan tags. >>Only the first vlan is stripped while the inner vlans are still in skb->data. >>In this case skb->vlan_proto is 802.1AD and skb->protocol is 802.1Q >>(for example) so I have to take the next header from skb->data. > > Hmm I think that whoever removes the outermost vlan from skb->vlan_* > should strip the next header into skb->vlan_*
The outermost vlan isn't removed from skb->vlan_* it stays there.