From: Ben Pfaff Date: Thu, 16 Apr 2009 22:10:26 +0000 (-0700) Subject: datapath: Fix VLAN tag insertion actions on Xen. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d0b1c78480ad95436631332a469e65650d2ac71f;p=openvswitch datapath: Fix VLAN tag insertion actions on Xen. On Xen, a VM can pass a packet that needs to be checksummed up to Dom0 for transmission on the wire. In this case, Dom0 is supposed to pick apart the packet, figure out the protocol, and checksum it before sending it out. However, this fails if we insert an 802.1Q header, because the Xen routine that picks apart packets (skb_checksum_setup() in net/core/dev.c) does not understand 802.1Q. Hence, we must call this function ourselves, before we add the 802.1Q header. Fixes bug #1215. --- diff --git a/datapath/actions.c b/datapath/actions.c index 17527931..86892e8d 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -75,10 +75,17 @@ modify_vlan_tci(struct sk_buff *skb, struct odp_flow_key *key, } else { /* Add vlan header */ - /* xxx The vlan_put_tag function, doesn't seem to work - * xxx reliably when it attempts to use the hardware-accelerated - * xxx version. We'll directly use the software version - * xxx until the problem can be diagnosed. + /* Set up checksumming pointers for checksum-deferred packets + * on Xen. Otherwise, dev_queue_xmit() will try to do this + * when we send the packet out on the wire, and it will fail at + * that point because skb_checksum_setup() will not look inside + * an 802.1Q header. */ + skb_checksum_setup(skb); + + /* The hardware-accelerated version of vlan_put_tag() works + * only for a device that has a VLAN group configured (with + * e.g. vconfig(8)), so call the software-only version + * __vlan_put_tag() directly instead. */ skb = __vlan_put_tag(skb, tci & mask); if (!skb) diff --git a/datapath/datapath.c b/datapath/datapath.c index 8b26d5a0..eb2c7db0 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -632,7 +632,7 @@ static int skb_pull_up_to(struct sk_buff *skb, void *ptr) } } -inline int skb_checksum_setup(struct sk_buff *skb) +int skb_checksum_setup(struct sk_buff *skb) { if (skb->proto_csum_blank) { if (skb->protocol != htons(ETH_P_IP)) diff --git a/datapath/datapath.h b/datapath/datapath.h index 886296c2..608e7437 100644 --- a/datapath/datapath.h +++ b/datapath/datapath.h @@ -117,4 +117,13 @@ void dp_set_origin(struct datapath *, u16, struct sk_buff *); /* Should hold at least RCU read lock when calling */ struct datapath *get_dp(int dp_idx); +#ifdef CONFIG_XEN +int skb_checksum_setup(struct sk_buff *skb); +#else +static inline int skb_checksum_setup(struct sk_buff *skb) +{ + return 0; +} +#endif + #endif /* datapath.h */