Skip to content

Commit

Permalink
ip6gre: Add support for GSO
Browse files Browse the repository at this point in the history
This patch adds code borrowed from bits and pieces of other protocols to
the IPv6 GRE path so that we can support GSO over IPv6 based GRE tunnels.
By adding this support we are able to significantly improve the throughput
for GRE tunnels as we are able to make use of GSO.

Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Alexander Duyck authored and David S. Miller committed Apr 16, 2016
1 parent e0c2096 commit 3a80e1f
Showing 1 changed file with 33 additions and 23 deletions.
56 changes: 33 additions & 23 deletions net/ipv6/ip6_gre.c
Original file line number Diff line number Diff line change
Expand Up @@ -621,15 +621,14 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
struct net *net = tunnel->net;
struct net_device *tdev; /* Device to other host */
struct ipv6hdr *ipv6h; /* Our new IP header */
unsigned int max_headroom = 0; /* The extra header space needed */
unsigned int min_headroom = 0; /* The extra header space needed */
int gre_hlen;
struct ipv6_tel_txoption opt;
int mtu;
struct dst_entry *dst = NULL, *ndst = NULL;
struct net_device_stats *stats = &tunnel->dev->stats;
int err = -1;
u8 proto;
struct sk_buff *new_skb;
__be16 protocol;

if (dev->type == ARPHRD_ETHER)
Expand Down Expand Up @@ -672,14 +671,14 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,

mtu = dst_mtu(dst) - sizeof(*ipv6h);
if (encap_limit >= 0) {
max_headroom += 8;
min_headroom += 8;
mtu -= 8;
}
if (mtu < IPV6_MIN_MTU)
mtu = IPV6_MIN_MTU;
if (skb_dst(skb))
skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
if (skb->len > mtu) {
if (skb->len > mtu && !skb_is_gso(skb)) {
*pmtu = mtu;
err = -EMSGSIZE;
goto tx_err_dst_release;
Expand All @@ -697,20 +696,19 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,

skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(dev)));

max_headroom += LL_RESERVED_SPACE(tdev) + gre_hlen + dst->header_len;
min_headroom += LL_RESERVED_SPACE(tdev) + gre_hlen + dst->header_len;

if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
(skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
new_skb = skb_realloc_headroom(skb, max_headroom);
if (max_headroom > dev->needed_headroom)
dev->needed_headroom = max_headroom;
if (!new_skb)
goto tx_err_dst_release;
if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
int head_delta = SKB_DATA_ALIGN(min_headroom -
skb_headroom(skb) +
16);

if (skb->sk)
skb_set_owner_w(new_skb, skb->sk);
consume_skb(skb);
skb = new_skb;
err = pskb_expand_head(skb, max_t(int, head_delta, 0),
0, GFP_ATOMIC);
if (min_headroom > dev->needed_headroom)
dev->needed_headroom = min_headroom;
if (unlikely(err))
goto tx_err_dst_release;
}

if (!fl6->flowi6_mark && ndst)
Expand All @@ -723,10 +721,11 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL);
}

if (likely(!skb->encapsulation)) {
skb_reset_inner_headers(skb);
skb->encapsulation = 1;
}
err = iptunnel_handle_offloads(skb,
(tunnel->parms.o_flags & GRE_CSUM) ?
SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
if (err)
goto tx_err_dst_release;

skb_push(skb, gre_hlen);
skb_reset_network_header(skb);
Expand Down Expand Up @@ -760,7 +759,9 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
*ptr = tunnel->parms.o_key;
ptr--;
}
if (tunnel->parms.o_flags&GRE_CSUM) {
if ((tunnel->parms.o_flags & GRE_CSUM) &&
!(skb_shinfo(skb)->gso_type &
(SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) {
*ptr = 0;
*(__sum16 *)ptr = gre6_checksum(skb);
}
Expand Down Expand Up @@ -1559,9 +1560,18 @@ static int ip6gre_newlink(struct net *src_net, struct net_device *dev,
dev->features |= GRE6_FEATURES;
dev->hw_features |= GRE6_FEATURES;

/* Can use a lockless transmit, unless we generate output sequences */
if (!(nt->parms.o_flags & GRE_SEQ))
if (!(nt->parms.o_flags & GRE_SEQ)) {
/* TCP segmentation offload is not supported when we
* generate output sequences.
*/
dev->features |= NETIF_F_GSO_SOFTWARE;
dev->hw_features |= NETIF_F_GSO_SOFTWARE;

/* Can use a lockless transmit, unless we generate
* output sequences
*/
dev->features |= NETIF_F_LLTX;
}

err = register_netdevice(dev);
if (err)
Expand Down

0 comments on commit 3a80e1f

Please sign in to comment.