timeval: Always log true poll interval instead of rounding off.
[openvswitch] / datapath / datapath.c
index 34d2c9bc2bb1df13eea46a468870f8344ef90bd2..6365f9474564dbac9c7be08d6c697a416bda155b 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/rculist.h>
 #include <linux/workqueue.h>
 #include <linux/dmi.h>
+#include <net/inet_ecn.h>
 #include <net/llc.h>
 
 #include "openvswitch/datapath-protocol.h"
@@ -358,6 +359,7 @@ static int new_nbp(struct datapath *dp, struct net_device *dev, int port_no)
                 * in dp_frame_hook().  In turn dp_frame_hook() can reject them
                 * back to network stack, but that's a waste of time. */
        }
+       dev_disable_lro(dev);
        rcu_assign_pointer(dp->ports[port_no], p);
        list_add_rcu(&p->node, &dp->port_list);
        dp->n_ports++;
@@ -505,6 +507,11 @@ out:
 static void
 do_port_input(struct net_bridge_port *p, struct sk_buff *skb) 
 {
+       /* LRO isn't suitable for bridging.  We turn it off but make sure
+        * that it wasn't reactivated. */
+       if (skb_warn_if_lro(skb))
+               return;
+
        /* Make our own copy of the packet.  Otherwise we will mangle the
         * packet for anyone who came before us (e.g. tcpdump via AF_PACKET).
         * (No one comes after us, since we tell handle_bridge() that we took
@@ -529,6 +536,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, false);
+
        /* 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 +615,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 +705,65 @@ 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.*/
+void
+compute_ip_summed(struct sk_buff *skb, bool xmit)
+{
+       /* For our convenience these defines change repeatedly between kernel
+        * versions, so we can't just copy them over... */
+       switch (skb->ip_summed) {
+       case CHECKSUM_NONE:
+               OVS_CB(skb)->ip_summed = OVS_CSUM_NONE;
+               break;
+       case CHECKSUM_UNNECESSARY:
+               OVS_CB(skb)->ip_summed = OVS_CSUM_UNNECESSARY;
+               break;
+#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.
+        *
+        * The one exception to this is if we are on the transmit path
+        * (basically after skb_checksum_setup() has been run) the type has
+        * already been converted, so we should stay with that. */
+       case CHECKSUM_HW:
+               if (!xmit)
+                       OVS_CB(skb)->ip_summed = OVS_CSUM_COMPLETE;
+               else
+                       OVS_CB(skb)->ip_summed = OVS_CSUM_PARTIAL;
+
+               break;
+#else
+       case CHECKSUM_COMPLETE:
+               OVS_CB(skb)->ip_summed = OVS_CSUM_COMPLETE;
+               break;
+       case CHECKSUM_PARTIAL:
+               OVS_CB(skb)->ip_summed = OVS_CSUM_PARTIAL;
+               break;
+#endif
+       default:
+               printk(KERN_ERR "openvswitch: unknown checksum type %d\n",
+                      skb->ip_summed);
+               /* None seems the safest... */
+               OVS_CB(skb)->ip_summed = OVS_CSUM_NONE;
+       }       
+
+#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
+       /* Xen has a special way of representing CHECKSUM_PARTIAL on older
+        * kernels. It should not be set on the transmit path though. */
+       if (skb->proto_csum_blank)
+               OVS_CB(skb)->ip_summed = OVS_CSUM_PARTIAL;
+
+       WARN_ON_ONCE(skb->proto_csum_blank && xmit);
+#endif
+}
+
 void
 forward_ip_summed(struct sk_buff *skb)
 {
 #ifdef CHECKSUM_HW
-       if (skb->ip_summed == CHECKSUM_HW)
+       if (OVS_CB(skb)->ip_summed == OVS_CSUM_COMPLETE)
                skb->ip_summed = CHECKSUM_NONE;
 #endif
 }
@@ -868,6 +931,11 @@ static int validate_actions(const struct sw_flow_actions *actions)
                                return -EINVAL;
                        break;
 
+               case ODPAT_SET_NW_TOS:
+                       if (a->nw_tos.nw_tos & INET_ECN_MASK)
+                               return -EINVAL;
+                       break;
+
                default:
                        if (a->type >= ODPAT_N_ACTIONS)
                                return -EOPNOTSUPP;