Skip to content
Permalink
Browse files
gtp: support GRO
This patch implements GRO callbacks for UDP-tunneled GTP traffic.

iperf3 numbers

Without GRO for GTP tunnels:

Accepted connection from 172.99.2.1, port 48783
[  5] local 172.99.0.1 port 5201 connected to 172.99.2.1 port 46095
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.00   sec   563 MBytes  576306 KBytes/sec
[  5]   1.00-2.00   sec   681 MBytes  697814 KBytes/sec
[  5]   2.00-3.00   sec   677 MBytes  693612 KBytes/sec
[  5]   3.00-4.00   sec   679 MBytes  695690 KBytes/sec
[  5]   4.00-5.00   sec   683 MBytes  699521 KBytes/sec
[  5]   5.00-6.00   sec   682 MBytes  698922 KBytes/sec
[  5]   6.00-7.00   sec   683 MBytes  699820 KBytes/sec
[  5]   7.00-8.00   sec   682 MBytes  698052 KBytes/sec
[  5]   8.00-9.00   sec   683 MBytes  699245 KBytes/sec
[  5]   9.00-10.00  sec   683 MBytes  699554 KBytes/sec
[  5]  10.00-10.00  sec   616 KBytes  687914 KBytes/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-10.00  sec  6.54 GBytes  685853 KBytes/sec                  receiver

With GRO for GTP tunnels:

Accepted connection from 172.99.2.1, port 40847
[  5] local 172.99.0.1 port 5201 connected to 172.99.2.1 port 55053
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.00   sec   989 MBytes  1012640 KBytes/sec
[  5]   1.00-2.00   sec  1.23 GBytes  1291408 KBytes/sec
[  5]   2.00-3.00   sec  1.26 GBytes  1320197 KBytes/sec
[  5]   3.00-4.00   sec  1.29 GBytes  1350097 KBytes/sec
[  5]   4.00-5.00   sec  1.23 GBytes  1284512 KBytes/sec
[  5]   5.00-6.00   sec  1.26 GBytes  1326329 KBytes/sec
[  5]   6.00-7.00   sec  1.28 GBytes  1338620 KBytes/sec
[  5]   7.00-8.00   sec  1.28 GBytes  1346391 KBytes/sec
[  5]   8.00-9.00   sec  1.30 GBytes  1366394 KBytes/sec
[  5]   9.00-10.00  sec  1.26 GBytes  1323848 KBytes/sec
[  5]  10.00-10.00  sec   384 KBytes  1113043 KBytes/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-10.00  sec  12.4 GBytes  1296036 KBytes/sec                  receiver

Signed-off-by: Jonas Bonn <jonas@norrbonn.se>
  • Loading branch information
Jonas Bonn authored and intel-lab-lkp committed Dec 11, 2020
1 parent c069077 commit de5669628a8f684dd7ed378aaf2a997221d243fa
Showing 1 changed file with 126 additions and 0 deletions.
@@ -361,6 +361,128 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
return ret;
}

static int gtp_gro_complete(struct sock *sk, struct sk_buff * skb, int nhoff)
{
size_t hdrlen;
char* gtphdr = skb->data + nhoff;
u8 version;
__be16 type;
struct packet_offload *ptype;
uint8_t ipver;
int err;

version = *gtphdr >> 5;
switch (version) {
case GTP_V0:
hdrlen = sizeof(struct gtp0_header);
break;
case GTP_V1:
hdrlen = sizeof(struct gtp1_header);
if (*gtphdr & GTP1_F_MASK)
hdrlen += 4;
break;
}

skb_set_inner_network_header(skb, nhoff + hdrlen);

ipver = inner_ip_hdr(skb)->version;
switch (ipver) {
case 4:
type = cpu_to_be16(ETH_P_IP);
break;
case 6:
type = cpu_to_be16(ETH_P_IPV6);
break;
default:
goto out;
}

rcu_read_lock();
ptype = gro_find_complete_by_type(type);
if (!ptype)
goto out_unlock;

err = ptype->callbacks.gro_complete(skb, nhoff + hdrlen);

skb_set_inner_mac_header(skb, nhoff + hdrlen);

out_unlock:
rcu_read_unlock();
out:

return err;

}

static struct sk_buff *gtp_gro_receive(struct sock *sk,
struct list_head *head,
struct sk_buff *skb)
{
size_t off, hdrlen;
char* gtphdr;
u8 version;
struct sk_buff *pp = NULL;
__be16 type;
struct packet_offload *ptype;

off = skb_gro_offset(skb);

gtphdr = skb_gro_header_fast(skb, off);
if (skb_gro_header_hard(skb, off+1)) {
gtphdr = skb_gro_header_slow(skb, off+1, off);
if (unlikely(!gtphdr))
goto out;
}

version = *gtphdr >> 5;
switch (version) {
case GTP_V0:
hdrlen = sizeof(struct gtp0_header);
break;
case GTP_V1:
hdrlen = sizeof(struct gtp1_header);
if (*gtphdr & GTP1_F_MASK)
hdrlen += 4;
break;
}

gtphdr = skb_gro_header_fast(skb, off);
if (skb_gro_header_hard(skb, off+hdrlen)) {
gtphdr = skb_gro_header_slow(skb, off+hdrlen, off);
if (unlikely(!gtphdr))
goto out;
}

skb_set_inner_network_header(skb, off + hdrlen);

switch(inner_ip_hdr(skb)->version) {
case 4:
type = cpu_to_be16(ETH_P_IP);
break;
case 6:
type = cpu_to_be16(ETH_P_IPV6);
break;
default:
goto out;
}

rcu_read_lock();
ptype = gro_find_receive_by_type(type);
if (!ptype)
goto out_unlock;

skb_gro_pull(skb, hdrlen);
skb_gro_postpull_rcsum(skb, gtphdr, hdrlen);

pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);

out_unlock:
rcu_read_unlock();
out:

return pp;
}

static int gtp_dev_init(struct net_device *dev)
{
struct gtp_dev *gtp = netdev_priv(dev);
@@ -622,7 +744,9 @@ static void gtp_link_setup(struct net_device *dev)

dev->priv_flags |= IFF_NO_QUEUE;
dev->features |= NETIF_F_LLTX;
dev->hw_features |= NETIF_F_RXCSUM;
dev->hw_features |= NETIF_F_SG | NETIF_F_GSO_SOFTWARE | NETIF_F_HW_CSUM;
dev->features |= NETIF_F_RXCSUM;
dev->features |= NETIF_F_SG | NETIF_F_GSO_SOFTWARE | NETIF_F_HW_CSUM;
netif_keep_dst(dev);

@@ -818,6 +942,8 @@ static struct sock *gtp_encap_enable_socket(int fd, int type,
tuncfg.encap_type = type;
tuncfg.encap_rcv = gtp_encap_recv;
tuncfg.encap_destroy = gtp_encap_destroy;
tuncfg.gro_receive = gtp_gro_receive;
tuncfg.gro_complete = gtp_gro_complete;

setup_udp_tunnel_sock(sock_net(sock->sk), sock, &tuncfg);

0 comments on commit de56696

Please sign in to comment.