xenserver: Various fixes for vif script
[openvswitch] / datapath / datapath.c
index 8de5614442ec9909e7df2b6ac908de346c91c7da..b6aefe892156fb3cbc887bd3d897c78140574bb4 100644 (file)
@@ -71,6 +71,7 @@ static DEFINE_MUTEX(dp_mutex);
 #define MAINT_SLEEP_MSECS 1000
 
 static int new_nbp(struct datapath *, struct net_device *, int port_no);
+static void compute_ip_summed(struct sk_buff *skb);
 
 /* Must be called with rcu_read_lock or dp_mutex. */
 struct datapath *get_dp(int dp_idx)
@@ -529,6 +530,8 @@ void dp_process_received_packet(struct sk_buff *skb, struct net_bridge_port *p)
 
        WARN_ON_ONCE(skb_shared(skb));
 
+       compute_ip_summed(skb);
+
        /* BHs are off so we don't have to use get_cpu()/put_cpu() here. */
        stats = percpu_ptr(dp->stats_percpu, smp_processor_id());
 
@@ -606,7 +609,7 @@ int vswitch_skb_checksum_setup(struct sk_buff *skb)
        if (skb->protocol != htons(ETH_P_IP))
                goto out;
 
-       if (!skb_pull_up_to(skb, skb_network_header(skb) + 1))
+       if (!skb_pull_up_to(skb, skb_network_header(skb) + sizeof(struct iphdr)))
                goto out;
 
        iph = ip_hdr(skb);
@@ -696,11 +699,33 @@ out:
  * skb_forward_csum().  It is slightly different because we are only concerned
  * with bridging and not other types of forwarding and can get away with
  * slightly more optimal behavior.*/
+static void
+compute_ip_summed(struct sk_buff *skb)
+{
+       OVS_CB(skb)->ip_summed = skb->ip_summed;
+
+#ifdef CHECKSUM_HW
+       /* In theory this could be either CHECKSUM_PARTIAL or CHECKSUM_COMPLETE.
+        * However, we should only get CHECKSUM_PARTIAL packets from Xen, which
+        * uses some special fields to represent this (see below).  Since we
+        * can only make one type work, pick the one that actually happens in
+        * practice. */
+       if (skb->ip_summed == CHECKSUM_HW)
+               OVS_CB(skb)->ip_summed = CSUM_COMPLETE;
+#endif
+#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
+       /* Xen has a special way of representing CHECKSUM_PARTIAL on older
+        * kernels. */
+       if (skb->proto_csum_blank)
+               OVS_CB(skb)->ip_summed = CSUM_PARTIAL;
+#endif
+}
+
 void
 forward_ip_summed(struct sk_buff *skb)
 {
 #ifdef CHECKSUM_HW
-       if (skb->ip_summed == CHECKSUM_HW)
+       if (OVS_CB(skb)->ip_summed == CSUM_COMPLETE)
                skb->ip_summed = CHECKSUM_NONE;
 #endif
 }
@@ -940,6 +965,7 @@ static int put_flow(struct datapath *dp, struct odp_flow_put __user *ufp)
        error = -EFAULT;
        if (copy_from_user(&uf, ufp, sizeof(struct odp_flow_put)))
                goto error;
+       memset(uf.flow.key.reserved, 0, sizeof uf.flow.key.reserved);
 
        table = rcu_dereference(dp->table);
        flow = dp_table_lookup(table, &uf.flow.key);
@@ -1084,6 +1110,7 @@ static int del_flow(struct datapath *dp, struct odp_flow __user *ufp)
        error = -EFAULT;
        if (copy_from_user(&uf, ufp, sizeof uf))
                goto error;
+       memset(uf.key.reserved, 0, sizeof uf.key.reserved);
 
        flow = dp_table_lookup(table, &uf.key);
        error = -ENOENT;
@@ -1119,6 +1146,7 @@ static int query_flows(struct datapath *dp, const struct odp_flowvec *flowvec)
 
                if (__copy_from_user(&uf, ufp, sizeof uf))
                        return -EFAULT;
+               memset(uf.key.reserved, 0, sizeof uf.key.reserved);
 
                flow = dp_table_lookup(table, &uf.key);
                if (!flow)