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>
* kernel, by Linus Torvalds and others.
*/
* 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>
#include <linux/if_arp.h>
#include <linux/if_bridge.h>
#include <linux/if_vlan.h>
goto error_put;
dev_set_promiscuity(netdev_vport->dev, 1);
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);
dev_disable_lro(netdev_vport->dev);
netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH;
return vport;
netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH;
return vport;
if (unlikely(!skb))
return;
if (unlikely(!skb))
return;
- skb_warn_if_lro(skb);
-
skb_push(skb, ETH_HLEN);
if (unlikely(compute_ip_summed(skb, false))) {
skb_push(skb, ETH_HLEN);
if (unlikely(compute_ip_summed(skb, false))) {
vport_receive(vport, 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)
static bool dev_supports_vlan_tx(struct net_device *dev)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
static int netdev_send(struct vport *vport, struct sk_buff *skb)
{
struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
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;
+ 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);
skb->dev = netdev_vport->dev;
forward_ip_summed(skb, true);
dev_queue_xmit(skb);
return len;
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. */
}
/* Returns null if this device is not attached to a datapath. */
* kernel, by Linus Torvalds and others.
*/
* 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>
#include <linux/dcache.h>
#include <linux/etherdevice.h>
#include <linux/if.h>
dp_process_received_packet(vport, 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
*
/**
* vport_send - send a packet on a device
*
*/
int vport_send(struct vport *vport, 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;
if (vport->ops->flags & VPORT_F_GEN_STATS && sent > 0) {
struct vport_percpu_stats *stats;
-
-error:
- kfree_skb(skb);
- vport_record_error(vport, VPORT_E_TX_DROPPED);
- return 0;
enum { LRU_MASK = LRU_MAX_PORTS - 1};
BUILD_ASSERT_DECL(IS_POW2(LRU_MAX_PORTS));
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;
struct dpif_linux_dp {
/* Generic Netlink header. */
uint8_t cmd;
request.options_len = options->size;
}
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);
/* Loop until we find a port that isn't used. */
do {
request.port_no = dpif_linux_pop_port(dpif);