On Thu, Sep 19, 2013 at 12:31:51PM -0500, Jesse Gross wrote: > On Wed, Sep 18, 2013 at 5:07 PM, Simon Horman <ho...@verge.net.au> wrote: > > On Tue, Sep 17, 2013 at 11:38:18AM -0700, Pravin Shelar wrote: > >> On Mon, Sep 9, 2013 at 12:20 AM, Simon Horman <ho...@verge.net.au> wrote: > >> > diff --git a/datapath/datapath.h b/datapath/datapath.h > >> > index 5d50dd4..babae3b 100644 > >> > --- a/datapath/datapath.h > >> > +++ b/datapath/datapath.h > >> > @@ -36,6 +36,10 @@ > >> > > >> > #define SAMPLE_ACTION_DEPTH 3 > >> > > >> > +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) > >> > +#define HAVE_INNER_PROTOCOL > >> > +#endif > >> > + > >> > /** > >> > * struct dp_stats_percpu - per-cpu packet processing statistics for a > >> > given > >> > * datapath. > >> > @@ -93,11 +97,16 @@ struct datapath { > >> > * @pkt_key: The flow information extracted from the packet. Must be > >> > nonnull. > >> > * @tun_key: Key for the tunnel that encapsulated this packet. NULL if > >> > the > >> > * packet is not being tunneled. > >> > + * @inner_protocol: Provides a substitute for the skb->inner_protocol > >> > field on > >> > + * kernels before 3.11. > >> > */ > >> > struct ovs_skb_cb { > >> > struct sw_flow *flow; > >> > struct sw_flow_key *pkt_key; > >> > struct ovs_key_ipv4_tunnel *tun_key; > >> > +#ifndef HAVE_INNER_PROTOCOL > >> > + __be16 inner_protocol; > >> > +#endif > >> > }; > >> > #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) > >> > > >> Can you move this to compat struct ovs_gso_cb {} > > > > I think that you are correct and inner_protocol needs > > to be in struct ovs_gso_cb so that it can > > be accessed via skb_network_protocol() from > > rpl___skb_gso_segment(). > > > > However I think it may also need to be present in struct ovs_cb > > so that it can be set correctly. > > > > Currently it is set unconditionally > > in ovs_execute_actions() and Jesse has suggested setting > > it conditionally in pop_mpls() (which is called by do_execute_actions()). > > But regardless it seems to me that the field would need to be available > > in struct ovs_cb. > > Since the helper functions are also in the compat code, I think they > should have access to ovs_gso_cb.
Pravin also believes that is the case so I have moved inner_protocol to struct ovs_gso_cb as he requested. > >> I think we can simplify code by pushing vlan and then segmenting skb, > >> the way we do it for MPLS. > > > > Are you thinking of something like the following which applies > > prior to the MPLS code. > > This is basically what I was thinking about. We might actually be able > to move all of this to compat code by having a replacement for > dev_queue_xmit() similar to what we have for ip_local_out() in the > tunnel code. I would appreciate Pravin's opinion on this but it seems to me that it should be possible. The following applies on top of my previous proposed change in this thread - simplification of segmentation - and before the MPLS patch-set. Is this along the lines of what you were thinking of? From: Simon Horman <ho...@verge.net.au> datapath: Move segmentation compatibility code into a compatibility function *** Do not apply: for informational purposes only Move segmentation compatibility code out of netdev_send and into rpl_dev_queue_xmit(), a compatibility function used in place of dev_queue_xmit() as necessary. As suggested by Jesse Gross. Some minor though verbose implementation notes: * This rpl_dev_queue_xmit() endeavours to return a valid error code or zero on success as per dev_queue_xmit(). The exception is that when dev_queue_xmit() is called in a loop only the status of the last call is taken into account, thus ignoring any errors returned by previous calls. This is derived from the previous calls to dev_queue_xmit() in a loop where netdev_send() ignores the return value of dev_queue_xmit() entirely. * netdev_send() continues to ignore the value of dev_queue_xmit(). So the discussion of the return value of rpl_dev_queue_xmit() above is has no bearing on run-time behaviour. * The return value of netdev_send() may differ from the previous implementation in the case where segmentation is performed before calling the real dev_queue_xmit(). This is because previously in this case netdev_send() would return the combined length of the skbs resulting from segmentation. Whereas the current code always returns the length of the original skb. Compile tested only. Signed-off-by: Simon Horman <ho...@verge.net.au> --- datapath/linux/compat/gso.c | 80 +++++++++++++++++++++++++++++++++++++++++++++ datapath/linux/compat/gso.h | 5 +++ datapath/vport-netdev.c | 78 ++----------------------------------------- 3 files changed, 87 insertions(+), 76 deletions(-) diff --git a/datapath/linux/compat/gso.c b/datapath/linux/compat/gso.c index 30332a2..d7e92fb 100644 --- a/datapath/linux/compat/gso.c +++ b/datapath/linux/compat/gso.c @@ -36,6 +36,86 @@ #include "gso.h" +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) && \ + !defined(HAVE_VLAN_BUG_WORKAROUND) +#include <linux/module.h> + +static int vlan_tso __read_mostly; +module_param(vlan_tso, int, 0644); +MODULE_PARM_DESC(vlan_tso, "Enable TSO for VLAN packets"); +#else +#define vlan_tso true +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +static bool dev_supports_vlan_tx(struct net_device *dev) +{ +#if defined(HAVE_VLAN_BUG_WORKAROUND) + return dev->features & NETIF_F_HW_VLAN_TX; +#else + /* Assume that the driver is buggy. */ + return false; +#endif +} + +int rpl_dev_queue_xmit(struct sk_buff *skb) +{ +#undef dev_queue_xmit + int err = -ENOMEM; + + if (vlan_tx_tag_present(skb) && !dev_supports_vlan_tx(skb->dev)) { + int features; + + features = netif_skb_features(skb); + + if (!vlan_tso) + features &= ~(NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_UFO | NETIF_F_FSO); + + skb = __vlan_put_tag(skb, skb->vlan_proto, vlan_tx_tag_get(skb)); + if (unlikely(!skb)) + return err; + vlan_set_tci(skb, 0); + + if (netif_needs_gso(skb, features)) { + struct sk_buff *nskb; + + nskb = skb_gso_segment(skb, features); + if (!nskb) { + if (unlikely(skb_cloned(skb) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) + goto drop; + + skb_shinfo(skb)->gso_type &= ~SKB_GSO_DODGY; + goto xmit; + } + + if (IS_ERR(nskb)) { + err = PTR_ERR(nskb); + goto drop; + } + consume_skb(skb); + skb = nskb; + + do { + nskb = skb->next; + skb->next = NULL; + err = dev_queue_xmit(skb); + skb = nskb; + } while (skb); + + return err; + } + } +xmit: + return dev_queue_xmit(skb); + +drop: + kfree_skb(skb); + return err; +} +#endif /* kernel version < 3.6.37 */ + static __be16 __skb_network_protocol(struct sk_buff *skb) { __be16 type = skb->protocol; diff --git a/datapath/linux/compat/gso.h b/datapath/linux/compat/gso.h index 44fd213..af1aaed 100644 --- a/datapath/linux/compat/gso.h +++ b/datapath/linux/compat/gso.h @@ -69,4 +69,9 @@ static inline void skb_reset_inner_headers(struct sk_buff *skb) #define ip_local_out rpl_ip_local_out int ip_local_out(struct sk_buff *skb); + +#if 1 // LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +#define dev_queue_xmit rpl_dev_queue_xmit +#endif + #endif diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c index 31680fd..4d934b5 100644 --- a/datapath/vport-netdev.c +++ b/datapath/vport-netdev.c @@ -34,17 +34,6 @@ #include "vport-internal_dev.h" #include "vport-netdev.h" -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) && \ - !defined(HAVE_VLAN_BUG_WORKAROUND) -#include <linux/module.h> - -static int vlan_tso __read_mostly; -module_param(vlan_tso, int, 0644); -MODULE_PARM_DESC(vlan_tso, "Enable TSO for VLAN packets"); -#else -#define vlan_tso true -#endif - static void netdev_port_receive(struct vport *vport, struct sk_buff *skb); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) @@ -259,19 +248,6 @@ static unsigned int packet_length(const struct sk_buff *skb) return length; } -static bool dev_supports_vlan_tx(struct net_device *dev) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) - /* Software fallback means every device supports vlan_tci on TX. */ - return true; -#elif defined(HAVE_VLAN_BUG_WORKAROUND) - return dev->features & NETIF_F_HW_VLAN_TX; -#else - /* Assume that the driver is buggy. */ - return false; -#endif -} - static int netdev_send(struct vport *vport, struct sk_buff *skb) { struct netdev_vport *netdev_vport = netdev_vport_priv(vport); @@ -282,65 +258,15 @@ static int netdev_send(struct vport *vport, struct sk_buff *skb) net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n", netdev_vport->dev->name, packet_length(skb), mtu); - goto drop; + kfree_skb(skb); + return 0; } skb->dev = netdev_vport->dev; - - if (vlan_tx_tag_present(skb) && !dev_supports_vlan_tx(skb->dev)) { - int features; - - features = netif_skb_features(skb); - - if (!vlan_tso) - features &= ~(NETIF_F_TSO | NETIF_F_TSO6 | - NETIF_F_UFO | NETIF_F_FSO); - - skb = __vlan_put_tag(skb, skb->vlan_proto, vlan_tx_tag_get(skb)); - if (unlikely(!skb)) - return 0; - vlan_set_tci(skb, 0); - - if (netif_needs_gso(skb, features)) { - struct sk_buff *nskb; - - nskb = skb_gso_segment(skb, features); - if (!nskb) { - if (unlikely(skb_cloned(skb) && - pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) - goto drop; - - skb_shinfo(skb)->gso_type &= ~SKB_GSO_DODGY; - goto xmit; - } - - if (IS_ERR(nskb)) - goto drop; - consume_skb(skb); - skb = nskb; - - len = 0; - do { - nskb = skb->next; - skb->next = NULL; - len += skb->len; - dev_queue_xmit(skb); - skb = nskb; - } while (skb); - - return len; - } - } - -xmit: len = skb->len; dev_queue_xmit(skb); return len; - -drop: - kfree_skb(skb); - return 0; } /* Returns null if this device is not attached to a datapath. */ -- 1.8.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev