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 <jo...@norrbonn.se>
---
 drivers/net/gtp.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 126 insertions(+)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 7bbeec173113..86639fae8d45 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -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);
 
-- 
2.27.0

Reply via email to