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. 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.