The AF_PACKET raw socket implementation of sendmsg() doesn't initialize skb->protocol, but ovs_vport_receive() expects that skb->protocol to be valid. Thus, datapath code that depends on skb->protocol did not properly recognize packet type. This fixes the problem by always extracting the protocol from the packet directly at this entry point.
The only obvious use of skb->protocol in the datapath is to distinguish 802.1Q packets from other packets. Thus, this problem manifested as different behavior for VLAN packets that were the first in their flow (and thus processed through the "execute" path) versus those later in the same flow (and thus processed directly through the kernel flow table). I found scapy plus tcpreplay to be a useful to debug this. Without this patch, running tcpreplay a few times against the same VLAN packet produced different behavior for initial and subsequent packets; with this patch, they all had the same correct behavior. I sent the VLAN packet on a trunk port (br0) and expected to see the VLAN stripped when it was forwarded to an access port, but without the patch it was stripped only for the first packet in the flow (and remained for subsequent packets). Here's a scapy invocation to create an appropriate pcap file for tcpreplay: wrpcap('foo.pcap',(Ether()/Dot1Q(vlan=9)/IP()/TCP(),)) Bug #8961. Reported-by: Paul Ingram <p...@nicira.com> Signed-off-by: Ben Pfaff <b...@nicira.com> --- datapath/vport-internal_dev.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c index c56f3b2..31d55fc 100644 --- a/datapath/vport-internal_dev.c +++ b/datapath/vport-internal_dev.c @@ -94,11 +94,21 @@ static int internal_dev_mac_addr(struct net_device *dev, void *p) /* Called with rcu_read_lock_bh. */ static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev) { + struct ethhdr *eth; + if (unlikely(compute_ip_summed(skb, true))) { kfree_skb(skb); return 0; } + /* Set skb->protocol since some sources (e.g. AF_PACKET) don't. */ + skb_reset_mac_header(skb); + eth = eth_hdr(skb); + if (ntohs(eth->h_proto) >= 1536) + skb->protocol = eth->h_proto; + else + skb->protocol = htons(ETH_P_802_2); + vlan_copy_skb_tci(skb); OVS_CB(skb)->flow = NULL; -- 1.7.2.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev