Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 352478
b: refs/heads/master
c: 68c3316
h: refs/heads/master
v: v3
  • Loading branch information
Pravin B Shelar authored and David S. Miller committed Feb 15, 2013
1 parent 0d4603a commit 5b3b202
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 12 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 05e8ef4ab2d8087d360e814d14da20b9f7fb2283
refs/heads/master: 68c331631143f5f039baac99a650e0b9e1ea02b6
3 changes: 2 additions & 1 deletion trunk/include/linux/netdev_features.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ enum {
NETIF_F_TSO_ECN_BIT, /* ... TCP ECN support */
NETIF_F_TSO6_BIT, /* ... TCPv6 segmentation */
NETIF_F_FSO_BIT, /* ... FCoE segmentation */
NETIF_F_GSO_RESERVED1, /* ... free (fill GSO_MASK to 8 bits) */
NETIF_F_GSO_GRE_BIT, /* ... GRE with TSO */
/**/NETIF_F_GSO_LAST, /* [can't be last bit, see GSO_MASK] */
NETIF_F_GSO_RESERVED2 /* ... free (fill GSO_MASK to 8 bits) */
= NETIF_F_GSO_LAST,
Expand Down Expand Up @@ -102,6 +102,7 @@ enum {
#define NETIF_F_VLAN_CHALLENGED __NETIF_F(VLAN_CHALLENGED)
#define NETIF_F_RXFCS __NETIF_F(RXFCS)
#define NETIF_F_RXALL __NETIF_F(RXALL)
#define NETIF_F_GRE_GSO __NETIF_F(GSO_GRE)

/* Features valid for ethtool to change */
/* = all defined minus driver/device-class-related */
Expand Down
17 changes: 17 additions & 0 deletions trunk/include/linux/skbuff.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,8 @@ enum {
SKB_GSO_TCPV6 = 1 << 4,

SKB_GSO_FCOE = 1 << 5,

SKB_GSO_GRE = 1 << 6,
};

#if BITS_PER_LONG > 32
Expand Down Expand Up @@ -2732,6 +2734,21 @@ static inline struct sec_path *skb_sec_path(struct sk_buff *skb)
}
#endif

/* Keeps track of mac header offset relative to skb->head.
* It is useful for TSO of Tunneling protocol. e.g. GRE.
* For non-tunnel skb it points to skb_mac_header() and for
* tunnel skb it points to outer mac header. */
struct skb_gso_cb {
int mac_offset;
};
#define SKB_GSO_CB(skb) ((struct skb_gso_cb *)(skb)->cb)

static inline int skb_tnl_header_len(const struct sk_buff *inner_skb)
{
return (skb_mac_header(inner_skb) - inner_skb->head) -
SKB_GSO_CB(inner_skb)->mac_offset;
}

static inline bool skb_is_gso(const struct sk_buff *skb)
{
return skb_shinfo(skb)->gso_size;
Expand Down
1 change: 1 addition & 0 deletions trunk/net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -2413,6 +2413,7 @@ struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
return ERR_PTR(err);
}

SKB_GSO_CB(skb)->mac_offset = skb_headroom(skb);
skb_reset_mac_header(skb);
skb_reset_mac_len(skb);

Expand Down
1 change: 1 addition & 0 deletions trunk/net/core/ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
[NETIF_F_TSO_ECN_BIT] = "tx-tcp-ecn-segmentation",
[NETIF_F_TSO6_BIT] = "tx-tcp6-segmentation",
[NETIF_F_FSO_BIT] = "tx-fcoe-segmentation",
[NETIF_F_GSO_GRE_BIT] = "tx-gre-segmentation",

[NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc",
[NETIF_F_SCTP_CSUM_BIT] = "tx-checksum-sctp",
Expand Down
6 changes: 5 additions & 1 deletion trunk/net/core/skbuff.c
Original file line number Diff line number Diff line change
Expand Up @@ -2738,6 +2738,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
unsigned int mss = skb_shinfo(skb)->gso_size;
unsigned int doffset = skb->data - skb_mac_header(skb);
unsigned int offset = doffset;
unsigned int tnl_hlen = skb_tnl_header_len(skb);
unsigned int headroom;
unsigned int len;
int sg = !!(features & NETIF_F_SG);
Expand Down Expand Up @@ -2814,7 +2815,10 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
skb_set_network_header(nskb, skb->mac_len);
nskb->transport_header = (nskb->network_header +
skb_network_header_len(skb));
skb_copy_from_linear_data(skb, nskb->data, doffset);

skb_copy_from_linear_data_offset(skb, -tnl_hlen,
nskb->data - tnl_hlen,
doffset + tnl_hlen);

if (fskb != skb_shinfo(skb)->frag_list)
continue;
Expand Down
1 change: 1 addition & 0 deletions trunk/net/ipv4/af_inet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1287,6 +1287,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
SKB_GSO_UDP |
SKB_GSO_DODGY |
SKB_GSO_TCP_ECN |
SKB_GSO_GRE |
0)))
goto out;

Expand Down
118 changes: 118 additions & 0 deletions trunk/net/ipv4/gre.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,19 @@
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/netdevice.h>
#include <linux/if_tunnel.h>
#include <linux/spinlock.h>
#include <net/protocol.h>
#include <net/gre.h>


static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
static DEFINE_SPINLOCK(gre_proto_lock);
struct gre_base_hdr {
__be16 flags;
__be16 protocol;
};
#define GRE_HEADER_SECTION 4

int gre_add_protocol(const struct gre_protocol *proto, u8 version)
{
Expand Down Expand Up @@ -112,12 +118,117 @@ static void gre_err(struct sk_buff *skb, u32 info)
rcu_read_unlock();
}

static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
netdev_features_t features)
{
struct sk_buff *segs = ERR_PTR(-EINVAL);
netdev_features_t enc_features;
int ghl = GRE_HEADER_SECTION;
struct gre_base_hdr *greh;
int mac_len = skb->mac_len;
int tnl_hlen;
bool csum;

if (unlikely(skb_shinfo(skb)->gso_type &
~(SKB_GSO_TCPV4 |
SKB_GSO_TCPV6 |
SKB_GSO_UDP |
SKB_GSO_DODGY |
SKB_GSO_TCP_ECN |
SKB_GSO_GRE)))
goto out;

if (unlikely(!pskb_may_pull(skb, sizeof(*greh))))
goto out;

greh = (struct gre_base_hdr *)skb_transport_header(skb);

if (greh->flags & GRE_KEY)
ghl += GRE_HEADER_SECTION;
if (greh->flags & GRE_SEQ)
ghl += GRE_HEADER_SECTION;
if (greh->flags & GRE_CSUM) {
ghl += GRE_HEADER_SECTION;
csum = true;
} else
csum = false;

/* setup inner skb. */
if (greh->protocol == htons(ETH_P_TEB)) {
struct ethhdr *eth = eth_hdr(skb);
skb->protocol = eth->h_proto;
} else {
skb->protocol = greh->protocol;
}

skb->encapsulation = 0;

if (unlikely(!pskb_may_pull(skb, ghl)))
goto out;
__skb_pull(skb, ghl);
skb_reset_mac_header(skb);
skb_set_network_header(skb, skb_inner_network_offset(skb));
skb->mac_len = skb_inner_network_offset(skb);

/* segment inner packet. */
enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
segs = skb_mac_gso_segment(skb, enc_features);
if (!segs || IS_ERR(segs))
goto out;

skb = segs;
tnl_hlen = skb_tnl_header_len(skb);
do {
__skb_push(skb, ghl);
if (csum) {
__be32 *pcsum;

if (skb_has_shared_frag(skb)) {
int err;

err = __skb_linearize(skb);
if (err) {
kfree_skb(segs);
segs = ERR_PTR(err);
goto out;
}
}

greh = (struct gre_base_hdr *)(skb->data);
pcsum = (__be32 *)(greh + 1);
*pcsum = 0;
*(__sum16 *)pcsum = csum_fold(skb_checksum(skb, 0, skb->len, 0));
}
__skb_push(skb, tnl_hlen - ghl);

skb_reset_mac_header(skb);
skb_set_network_header(skb, mac_len);
skb->mac_len = mac_len;
} while ((skb = skb->next));
out:
return segs;
}

static int gre_gso_send_check(struct sk_buff *skb)
{
if (!skb->encapsulation)
return -EINVAL;
return 0;
}

static const struct net_protocol net_gre_protocol = {
.handler = gre_rcv,
.err_handler = gre_err,
.netns_ok = 1,
};

static const struct net_offload gre_offload = {
.callbacks = {
.gso_send_check = gre_gso_send_check,
.gso_segment = gre_gso_segment,
},
};

static int __init gre_init(void)
{
pr_info("GRE over IPv4 demultiplexor driver\n");
Expand All @@ -127,11 +238,18 @@ static int __init gre_init(void)
return -EAGAIN;
}

if (inet_add_offload(&gre_offload, IPPROTO_GRE)) {
pr_err("can't add protocol offload\n");
inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
return -EAGAIN;
}

return 0;
}

static void __exit gre_exit(void)
{
inet_del_offload(&gre_offload, IPPROTO_GRE);
inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
}

Expand Down
Loading

0 comments on commit 5b3b202

Please sign in to comment.