Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

openvswitch: upcall: Fix vlan handling.

Networking stack accelerate vlan tag handling by
keeping topmost vlan header in skb. This works as
long as packet remains in OVS datapath. But during
OVS upcall vlan header is pushed on to the packet.
When such packet is sent back to OVS datapath, core
networking stack might not handle it correctly. Following
patch avoids this issue by accelerating the vlan tag
during flow key extract. This simplifies datapath by
bringing uniform packet processing for packets from
all code paths.

Fixes: 5108bbaddc ("openvswitch: add processing of L3 packets").
CC: Jarno Rajahalme <jarno@ovn.org>
CC: Jiri Benc <jbenc@redhat.com>
Signed-off-by: Pravin B Shelar <pshelar@ovn.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

pravin shelar and committed by
David S. Miller
df30f740 56ab6b93

+27 -28
-1
net/openvswitch/datapath.c
··· 606 606 rcu_assign_pointer(flow->sf_acts, acts); 607 607 packet->priority = flow->key.phy.priority; 608 608 packet->mark = flow->key.phy.skb_mark; 609 - packet->protocol = flow->key.eth.type; 610 609 611 610 rcu_read_lock(); 612 611 dp = get_dp_rcu(net, ovs_header->dp_ifindex);
+27 -27
net/openvswitch/flow.c
··· 312 312 * Returns 0 if it encounters a non-vlan or incomplete packet. 313 313 * Returns 1 after successfully parsing vlan tag. 314 314 */ 315 - static int parse_vlan_tag(struct sk_buff *skb, struct vlan_head *key_vh) 315 + static int parse_vlan_tag(struct sk_buff *skb, struct vlan_head *key_vh, 316 + bool untag_vlan) 316 317 { 317 318 struct vlan_head *vh = (struct vlan_head *)skb->data; 318 319 ··· 331 330 key_vh->tci = vh->tci | htons(VLAN_TAG_PRESENT); 332 331 key_vh->tpid = vh->tpid; 333 332 334 - __skb_pull(skb, sizeof(struct vlan_head)); 333 + if (unlikely(untag_vlan)) { 334 + int offset = skb->data - skb_mac_header(skb); 335 + u16 tci; 336 + int err; 337 + 338 + __skb_push(skb, offset); 339 + err = __skb_vlan_pop(skb, &tci); 340 + __skb_pull(skb, offset); 341 + if (err) 342 + return err; 343 + __vlan_hwaccel_put_tag(skb, key_vh->tpid, tci); 344 + } else { 345 + __skb_pull(skb, sizeof(struct vlan_head)); 346 + } 335 347 return 1; 336 348 } 337 349 ··· 365 351 key->eth.vlan.tpid = skb->vlan_proto; 366 352 } else { 367 353 /* Parse outer vlan tag in the non-accelerated case. */ 368 - res = parse_vlan_tag(skb, &key->eth.vlan); 354 + res = parse_vlan_tag(skb, &key->eth.vlan, true); 369 355 if (res <= 0) 370 356 return res; 371 357 } 372 358 373 359 /* Parse inner vlan tag. */ 374 - res = parse_vlan_tag(skb, &key->eth.cvlan); 360 + res = parse_vlan_tag(skb, &key->eth.cvlan, false); 375 361 if (res <= 0) 376 362 return res; 377 363 ··· 814 800 if (err) 815 801 return err; 816 802 817 - if (ovs_key_mac_proto(key) == MAC_PROTO_NONE) { 818 - /* key_extract assumes that skb->protocol is set-up for 819 - * layer 3 packets which is the case for other callers, 820 - * in particular packets recieved from the network stack. 821 - * Here the correct value can be set from the metadata 822 - * extracted above. 823 - */ 824 - skb->protocol = key->eth.type; 825 - } else { 826 - struct ethhdr *eth; 803 + /* key_extract assumes that skb->protocol is set-up for 804 + * layer 3 packets which is the case for other callers, 805 + * in particular packets received from the network stack. 806 + * Here the correct value can be set from the metadata 807 + * extracted above. 808 + * For L2 packet key eth type would be zero. skb protocol 809 + * would be set to correct value later during key-extact. 810 + */ 827 811 828 - skb_reset_mac_header(skb); 829 - eth = eth_hdr(skb); 830 - 831 - /* Normally, setting the skb 'protocol' field would be 832 - * handled by a call to eth_type_trans(), but it assumes 833 - * there's a sending device, which we may not have. 834 - */ 835 - if (eth_proto_is_802_3(eth->h_proto)) 836 - skb->protocol = eth->h_proto; 837 - else 838 - skb->protocol = htons(ETH_P_802_2); 839 - } 840 - 812 + skb->protocol = key->eth.type; 841 813 return key_extract(skb, key); 842 814 }