If an MPLS packet requires segmentation then use mpls_features to determine if the software implementation should be used.
As no driver advertises MPLS GSO segmentation this will always be the case. I had not noticed that this was necessary before as software MPLS GSO segmentation was already being used in my test environment. I believe that the reason for that is the skbs in question always had fragments and the driver I used does not advertise NETIF_F_FRAGLIST (which seems to be the case for most drivers). Thus Thus software segmentation was activated by skb_gso_ok(). Thanks to Jesse Gross for prompting me to investigate this. Cc: Jesse Gross <je...@nicira.com> Signed-off-by: Simon Horman <ho...@verge.net.au> --- net/core/dev.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/net/core/dev.c b/net/core/dev.c index 867adb2..ade6029 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2540,6 +2540,40 @@ netdev_features_t netif_skb_features(struct sk_buff *skb) } EXPORT_SYMBOL(netif_skb_features); +/* If MPLS offload request, verify we are testing hardware MPLS features + * instead of standard features for the netdev. + */ +#ifdef CONFIG_NET_MPLS_GSO +static inline netdev_features_t net_mpls_features(struct sk_buff *skb, + struct net_device *dev, netdev_features_t features) +{ + /* There is no support for MPLS LRO. So the only way that + * an MPLS skb could require GSO segmentation is if it + * was received as a non-MPLS skb and then became an MPLS skb. + * This may be effected by Open vSwitch in which case the + * mac_len will non-zero and not equal to skb_network_offset + * as the former indicates the end of L2 the latter indicates + * the beginning of L3 and there is a gap between them occupied + * by the MPLS label stack. + * + * Thus it is possible to avoid traversing any VLAN tags that are + * present to determine if the ethtype is MPLS. Instead the + * inequality of mac_llen and skb_network_offset are used to + * determine if a packet is MPLS for the purpose of determining + * offload features. + */ + if (skb->mac_len && skb->mac_len != skb_network_offset(skb)) + features &= dev->mpls_features; + return features; +} +#else +static inline netdev_features_t net_mpls_features(struct sk_buff *skb, + struct net_device *dev, netdev_features_t features) +{ + return features; +} +#endif + int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq) { @@ -2576,6 +2610,8 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, if (skb->encapsulation) features &= dev->hw_enc_features; + features = net_mpls_features(skb, dev, features); + if (netif_needs_gso(skb, features)) { if (unlikely(dev_gso_segment(skb, features))) goto out_kfree_skb; -- 1.8.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev