datapath: Disable LRO from userspace instead of the kernel.
authorJustin Pettit <jpettit@nicira.com>
Sat, 27 Aug 2011 06:34:40 +0000 (23:34 -0700)
committerJustin Pettit <jpettit@nicira.com>
Mon, 29 Aug 2011 04:30:58 +0000 (21:30 -0700)
Whenever a port is added to the datapath, LRO is automatically disabled.
In the future, we may want to enable LRO in some circumstances, so have
userspace disable LRO through the ethtool ioctls.

As part of this change, the MTU and LRO checks are moved to
netdev-vport's send(), which is where they're actually needed.

Feature #6810

Signed-off-by: Justin Pettit <jpettit@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
datapath/vport-netdev.c
datapath/vport.c
lib/dpif-linux.c

index f1e9b09d0deab3fd49b3e94aad58a31aab526504..d1e61bbdfba1a5288e88f306f46ad56a71f591e4 100644 (file)
@@ -6,6 +6,8 @@
  * kernel, by Linus Torvalds and others.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/if_arp.h>
 #include <linux/if_bridge.h>
 #include <linux/if_vlan.h>
@@ -158,7 +160,9 @@ static struct vport *netdev_create(const struct vport_parms *parms)
                goto error_put;
 
        dev_set_promiscuity(netdev_vport->dev, 1);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
        dev_disable_lro(netdev_vport->dev);
+#endif
        netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH;
 
        return vport;
@@ -281,8 +285,6 @@ static void netdev_port_receive(struct vport *vport, struct sk_buff *skb)
        if (unlikely(!skb))
                return;
 
-       skb_warn_if_lro(skb);
-
        skb_push(skb, ETH_HLEN);
 
        if (unlikely(compute_ip_summed(skb, false))) {
@@ -294,6 +296,16 @@ static void netdev_port_receive(struct vport *vport, struct sk_buff *skb)
        vport_receive(vport, skb);
 }
 
+static inline unsigned packet_length(const struct sk_buff *skb)
+{
+       unsigned length = skb->len - ETH_HLEN;
+
+       if (skb->protocol == htons(ETH_P_8021Q))
+               length -= VLAN_HLEN;
+
+       return length;
+}
+
 static bool dev_supports_vlan_tx(struct net_device *dev)
 {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
@@ -310,8 +322,19 @@ static bool dev_supports_vlan_tx(struct net_device *dev)
 static int netdev_send(struct vport *vport, struct sk_buff *skb)
 {
        struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
+       int mtu = netdev_vport->dev->mtu;
        int len;
 
+       if (unlikely(packet_length(skb) > mtu && !skb_is_gso(skb))) {
+               if (net_ratelimit())
+                       pr_warn("%s: dropped over-mtu packet: %d > %d\n",
+                               dp_name(vport->dp), packet_length(skb), mtu);
+               goto error;
+       }
+
+       if (unlikely(skb_warn_if_lro(skb)))
+               goto error;
+
        skb->dev = netdev_vport->dev;
        forward_ip_summed(skb, true);
 
@@ -379,6 +402,11 @@ tag:
        dev_queue_xmit(skb);
 
        return len;
+
+error:
+       kfree_skb(skb);
+       vport_record_error(vport, VPORT_E_TX_DROPPED);
+       return 0;
 }
 
 /* Returns null if this device is not attached to a datapath. */
index 487d75241fe69e5b261ea052b9e35d9b72189e6e..2b5a0b4ed22e409a384ce06317a8c36487264d2b 100644 (file)
@@ -6,8 +6,6 @@
  * kernel, by Linus Torvalds and others.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/dcache.h>
 #include <linux/etherdevice.h>
 #include <linux/if.h>
@@ -687,16 +685,6 @@ void vport_receive(struct vport *vport, struct sk_buff *skb)
        dp_process_received_packet(vport, skb);
 }
 
-static inline unsigned packet_length(const struct sk_buff *skb)
-{
-       unsigned length = skb->len - ETH_HLEN;
-
-       if (skb->protocol == htons(ETH_P_8021Q))
-               length -= VLAN_HLEN;
-
-       return length;
-}
-
 /**
  *     vport_send - send a packet on a device
  *
@@ -708,18 +696,7 @@ static inline unsigned packet_length(const struct sk_buff *skb)
  */
 int vport_send(struct vport *vport, struct sk_buff *skb)
 {
-       int mtu;
-       int sent;
-
-       mtu = vport_get_mtu(vport);
-       if (mtu && unlikely(packet_length(skb) > mtu && !skb_is_gso(skb))) {
-               if (net_ratelimit())
-                       pr_warn("%s: dropped over-mtu packet: %d > %d\n",
-                               dp_name(vport->dp), packet_length(skb), mtu);
-               goto error;
-       }
-
-       sent = vport->ops->send(vport, skb);
+       int sent = vport->ops->send(vport, skb);
 
        if (vport->ops->flags & VPORT_F_GEN_STATS && sent > 0) {
                struct vport_percpu_stats *stats;
@@ -736,11 +713,6 @@ int vport_send(struct vport *vport, struct sk_buff *skb)
        }
 
        return sent;
-
-error:
-       kfree_skb(skb);
-       vport_record_error(vport, VPORT_E_TX_DROPPED);
-       return 0;
 }
 
 /**
index 55d22b40ca4845893c8d2da312b35875359df97c..da48c685a0ccbed91e6200bf1758892fe2fc5d54 100644 (file)
@@ -60,6 +60,10 @@ enum { LRU_MAX_PORTS = 1024 };
 enum { LRU_MASK = LRU_MAX_PORTS - 1};
 BUILD_ASSERT_DECL(IS_POW2(LRU_MAX_PORTS));
 
+/* This ethtool flag was introduced in Linux 2.6.24, so it might be
+ * missing if we have old headers. */
+#define ETH_FLAG_LRO      (1 << 15)    /* LRO is enabled */
+
 struct dpif_linux_dp {
     /* Generic Netlink header. */
     uint8_t cmd;
@@ -393,6 +397,10 @@ dpif_linux_port_add(struct dpif *dpif_, struct netdev *netdev,
         request.options_len = options->size;
     }
 
+    if (request.type == OVS_VPORT_TYPE_NETDEV) {
+        netdev_linux_ethtool_set_flag(netdev, ETH_FLAG_LRO, "LRO", false);
+    }
+
     /* Loop until we find a port that isn't used. */
     do {
         request.port_no = dpif_linux_pop_port(dpif);