{"id":815225,"url":"http://patchwork.ozlabs.org/api/patches/815225/?format=json","web_url":"http://patchwork.ozlabs.org/project/netdev/patch/20170919003904.5124-15-tom@quantonium.net/","project":{"id":7,"url":"http://patchwork.ozlabs.org/api/projects/7/?format=json","name":"Linux network development","link_name":"netdev","list_id":"netdev.vger.kernel.org","list_email":"netdev@vger.kernel.org","web_url":null,"scm_url":null,"webscm_url":null,"list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20170919003904.5124-15-tom@quantonium.net>","list_archive_url":null,"date":"2017-09-19T00:39:04","name":"[net-next,14/14] gtp: GSO support","commit_ref":null,"pull_url":null,"state":"changes-requested","archived":true,"hash":"5fcafd6912a24816e5c137933bd211d79d14d296","submitter":{"id":72064,"url":"http://patchwork.ozlabs.org/api/people/72064/?format=json","name":"Tom Herbert","email":"tom@quantonium.net"},"delegate":{"id":34,"url":"http://patchwork.ozlabs.org/api/users/34/?format=json","username":"davem","first_name":"David","last_name":"Miller","email":"davem@davemloft.net"},"mbox":"http://patchwork.ozlabs.org/project/netdev/patch/20170919003904.5124-15-tom@quantonium.net/mbox/","series":[{"id":3758,"url":"http://patchwork.ozlabs.org/api/series/3758/?format=json","web_url":"http://patchwork.ozlabs.org/project/netdev/list/?series=3758","date":"2017-09-19T00:38:50","name":"gtp: Additional feature support","version":1,"mbox":"http://patchwork.ozlabs.org/series/3758/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/815225/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/815225/checks/","tags":{},"related":[],"headers":{"Return-Path":"<netdev-owner@vger.kernel.org>","X-Original-To":"patchwork-incoming@ozlabs.org","Delivered-To":"patchwork-incoming@ozlabs.org","Authentication-Results":["ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=netdev-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)","ozlabs.org; dkim=pass (2048-bit key;\n\tunprotected) header.d=quantonium-net.20150623.gappssmtp.com\n\theader.i=@quantonium-net.20150623.gappssmtp.com\n\theader.b=\"BpoVEtDW\"; dkim-atps=neutral"],"Received":["from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3xx3tk5QpYz9s5L\n\tfor <patchwork-incoming@ozlabs.org>;\n\tTue, 19 Sep 2017 10:40:14 +1000 (AEST)","(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1751572AbdISAkM (ORCPT <rfc822;patchwork-incoming@ozlabs.org>);\n\tMon, 18 Sep 2017 20:40:12 -0400","from mail-pg0-f44.google.com ([74.125.83.44]:46875 \"EHLO\n\tmail-pg0-f44.google.com\" rhost-flags-OK-OK-OK-OK) by vger.kernel.org\n\twith ESMTP id S1750925AbdISAkF (ORCPT\n\t<rfc822;netdev@vger.kernel.org>); Mon, 18 Sep 2017 20:40:05 -0400","by mail-pg0-f44.google.com with SMTP id i130so1093747pgc.3\n\tfor <netdev@vger.kernel.org>; Mon, 18 Sep 2017 17:40:05 -0700 (PDT)","from localhost.localdomain (c-73-162-13-107.hsd1.ca.comcast.net.\n\t[73.162.13.107]) by smtp.gmail.com with ESMTPSA id\n\tk78sm662018pfb.157.2017.09.18.17.40.03\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n\tMon, 18 Sep 2017 17:40:04 -0700 (PDT)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=quantonium-net.20150623.gappssmtp.com; s=20150623;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references;\n\tbh=yD6rTQ88tAwG7ClRyMr2nyWuITRx1lwY2PD/sJZPSI8=;\n\tb=BpoVEtDWlfRnhNT8YynL0O7MZZq50XyHOc9IwYQcLl+/EQNpfc6PbBsD2em16KHEy8\n\t3FmZnEpw66lbjvLvIlXkKjAo4gqdSyjh9bG4ZfpRHmKIMCAo7/MrWVTJs5B0ZFA/OC1a\n\thcKmQZ7FQCueYVAr+kB/VMbmnm2OahDQQeILaZc+YtlyW2n27wGwmiUre55KvKJMgop0\n\t/khP2WnNAt8DJUJzN84QFBp0GsltLA9YY1HRiPlWmJWef373Esfk4/ky0ot13xHXhss8\n\tiW0aw1Lc65RzL12a44eADH78Or/SJatqoGnY8GqNDldNb1InatGu1vVpe4JCR8wz+L7C\n\tWajg==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=yD6rTQ88tAwG7ClRyMr2nyWuITRx1lwY2PD/sJZPSI8=;\n\tb=Tv+Mme4SeFl8OZcUfHAS9UBdcj8QCvLUJmUA0Y13uyFvhpVt17rpSZsWfbaOLkUvNV\n\tnZhaLQEmkUGrX61Y7xwPjjdlWHUb2hXoa3nTiunqcp8GFjvB7VIyRKOCEc20y4kV/BGP\n\tt2BcMhnPaFkTJ5U1v45QqGJulfibmyn9Sw8+Y8HhBXaA3HAsl0h/hFqx55X7BHsI2HOX\n\tcbDtlX7CwoHoHkcsB4mGmKQGpA+HDhFt5lvAu0fzMXdgOlkUSggawYi5WPYdY7A0uekb\n\tpBN+80DxvIOBkezgZi6jMVxZVztmF6uLrQZaYfzLSmcNEtf9hp5MXkETezvdBrVWxbF8\n\trRkA==","X-Gm-Message-State":"AHPjjUglDjcZWtajAho8DF1P3DxoKGChPD2BHf+yRX+RZy0dA7jqkxhn\n\tiBcv4O8Cp8WUpXcd","X-Google-Smtp-Source":"AOwi7QC49qujAUBPt/9PK/H+wZKPCm1OO4x7oHlotAJZFo2ZCmcJnjWpcxWn4ApBbnn8UZ+l2MPyRA==","X-Received":"by 10.99.53.3 with SMTP id c3mr365571pga.220.1505781605058;\n\tMon, 18 Sep 2017 17:40:05 -0700 (PDT)","From":"Tom Herbert <tom@quantonium.net>","To":"davem@davemloft.net","Cc":"netdev@vger.kernel.org, pablo@netfilter.org, laforge@gnumonks.org,\n\trohit@quantonium.net, Tom Herbert <tom@quantonium.net>","Subject":"[PATCH net-next 14/14] gtp: GSO support","Date":"Mon, 18 Sep 2017 17:39:04 -0700","Message-Id":"<20170919003904.5124-15-tom@quantonium.net>","X-Mailer":"git-send-email 2.11.0","In-Reply-To":"<20170919003904.5124-1-tom@quantonium.net>","References":"<20170919003904.5124-1-tom@quantonium.net>","Sender":"netdev-owner@vger.kernel.org","Precedence":"bulk","List-ID":"<netdev.vger.kernel.org>","X-Mailing-List":"netdev@vger.kernel.org"},"content":"Need to define a gtp_gso_segment since the GTP header includes a length\nfield that must be set per packet. Also, GPv0 header includes a sequence\nnumber that is incremented per packet.\n\nSigned-off-by: Tom Herbert <tom@quantonium.net>\n---\n drivers/net/gtp.c            | 176 +++++++++++++++++++++++++++++++++++++++----\n include/uapi/linux/if_link.h |   1 -\n 2 files changed, 163 insertions(+), 14 deletions(-)","diff":"diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c\nindex 2f9d810cf19f..a2c4d9804a8f 100644\n--- a/drivers/net/gtp.c\n+++ b/drivers/net/gtp.c\n@@ -120,6 +120,8 @@ static u32 gtp_h_initval;\n \n static void pdp_context_delete(struct pdp_ctx *pctx);\n \n+static int gtp_gso_type;\n+\n static inline u32 gtp0_hashfn(u64 tid)\n {\n \tu32 *tid32 = (u32 *) &tid;\n@@ -430,6 +432,69 @@ static int gtp1u_udp_encap_recv(struct sock *sk, struct sk_buff *skb)\n \treturn 1;\n }\n \n+static struct sk_buff *gtp_gso_segment(struct sk_buff *skb,\n+\t\t\t\t       netdev_features_t features)\n+{\n+\tstruct sk_buff *segs = ERR_PTR(-EINVAL);\n+\tint tnl_hlen = skb->mac_len;\n+\tstruct gtp0_header *gtp0;\n+\n+\tif (unlikely(!pskb_may_pull(skb, tnl_hlen)))\n+\t\treturn ERR_PTR(-EINVAL);\n+\n+\t/* Make sure we have a mininal GTP header */\n+\tif (unlikely(tnl_hlen < min_t(size_t, sizeof(struct gtp0_header),\n+\t\t\t\t      sizeof(struct gtp1_header))))\n+\t\treturn ERR_PTR(-EINVAL);\n+\n+\t/* Determine version */\n+\tgtp0 = (struct gtp0_header *)skb->data;\n+\tswitch (gtp0->flags >> 5) {\n+\tcase GTP_V0: {\n+\t\tu16 tx_seq;\n+\n+\t\tif (unlikely(tnl_hlen != sizeof(struct gtp0_header)))\n+\t\t\treturn ERR_PTR(-EINVAL);\n+\n+\t\ttx_seq = ntohs(gtp0->seq);\n+\n+\t\t/* segment inner packet. */\n+\t\tsegs = skb_mac_gso_segment(skb, features);\n+\t\tif (!IS_ERR_OR_NULL(segs)) {\n+\t\t\tskb = segs;\n+\t\t\tdo {\n+\t\t\t\tgtp0 = (struct gtp0_header *)\n+\t\t\t\t\t\tskb_mac_header(skb);\n+\t\t\t\tgtp0->length = ntohs(skb->len - tnl_hlen);\n+\t\t\t\tgtp0->seq = htons(tx_seq);\n+\t\t\t\ttx_seq++;\n+\t\t\t} while ((skb = skb->next));\n+\t\t}\n+\t\tbreak;\n+\t}\n+\tcase GTP_V1: {\n+\t\tstruct gtp1_header *gtp1;\n+\n+\t\tif (unlikely(tnl_hlen != sizeof(struct gtp1_header)))\n+\t\t\treturn ERR_PTR(-EINVAL);\n+\n+\t\t/* segment inner packet. */\n+\t\tsegs = skb_mac_gso_segment(skb, features);\n+\t\tif (!IS_ERR_OR_NULL(segs)) {\n+\t\t\tskb = segs;\n+\t\t\tdo {\n+\t\t\t\tgtp1 = (struct gtp1_header *)\n+\t\t\t\t\t\tskb_mac_header(skb);\n+\t\t\t\tgtp1->length = ntohs(skb->len - tnl_hlen);\n+\t\t\t} while ((skb = skb->next));\n+\t\t}\n+\t\tbreak;\n+\t}\n+\t}\n+\n+\treturn segs;\n+}\n+\n static struct sk_buff **gtp_gro_receive_finish(struct sock *sk,\n \t\t\t\t\t       struct sk_buff **head,\n \t\t\t\t\t       struct sk_buff *skb,\n@@ -688,18 +753,25 @@ static inline void gtp0_push_header(struct sk_buff *skb, struct pdp_ctx *pctx)\n {\n \tint payload_len = skb->len;\n \tstruct gtp0_header *gtp0;\n+\tu32 tx_seq;\n \n \tgtp0 = skb_push(skb, sizeof(*gtp0));\n \n \tgtp0->flags\t= 0x1e; /* v0, GTP-non-prime. */\n \tgtp0->type\t= GTP_TPDU;\n \tgtp0->length\t= htons(payload_len);\n-\tgtp0->seq\t= htons((atomic_inc_return(&pctx->tx_seq) - 1) %\n-\t\t\t\t0xffff);\n \tgtp0->flow\t= htons(pctx->u.v0.flow);\n \tgtp0->number\t= 0xff;\n \tgtp0->spare[0]\t= gtp0->spare[1] = gtp0->spare[2] = 0xff;\n \tgtp0->tid\t= cpu_to_be64(pctx->u.v0.tid);\n+\n+\t/* If skb is GSO allocate sequence numbers for all the segments */\n+\ttx_seq = skb_shinfo(skb)->gso_segs ?\n+\t\t\tatomic_add_return(skb_shinfo(skb)->gso_segs,\n+\t\t\t\t\t  &pctx->tx_seq) :\n+\t\t\tatomic_inc_return(&pctx->tx_seq);\n+\n+\tgtp0->seq\t= (htons((u16)tx_seq) - 1) & 0xffff;\n }\n \n static inline void gtp1_push_header(struct sk_buff *skb, struct pdp_ctx *pctx)\n@@ -737,6 +809,59 @@ static void gtp_push_header(struct sk_buff *skb, struct pdp_ctx *pctx)\n \t}\n }\n \n+static size_t gtp_max_header_len(int version)\n+\n+{\n+\tswitch (version) {\n+\tcase GTP_V0:\n+\t\treturn sizeof(struct gtp0_header);\n+\tcase GTP_V1:\n+\t\treturn sizeof(struct gtp1_header) + 4;\n+\t}\n+\n+\t/* Should not happen */\n+\treturn 0;\n+}\n+\n+static int gtp_build_skb(struct sk_buff *skb, struct dst_entry *dst,\n+\t\t\t struct pdp_ctx *pctx, bool xnet, int ip_hdr_len,\n+\t\t\t bool udp_sum)\n+{\n+\tint type = (udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL) |\n+\t\t   gtp_gso_type;\n+\tint min_headroom;\n+\tu16 protocol;\n+\tint err;\n+\n+\tskb_scrub_packet(skb, xnet);\n+\n+\tmin_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len +\n+\t\t       gtp_max_header_len(pctx->gtp_version) + ip_hdr_len;\n+\n+\terr = skb_cow_head(skb, min_headroom);\n+\tif (unlikely(err))\n+\t\tgoto free_dst;\n+\n+\terr = iptunnel_handle_offloads(skb, type);\n+\tif (err)\n+\t\tgoto free_dst;\n+\n+\tprotocol = ipver_to_eth(ip_hdr(skb));\n+\n+\tgtp_push_header(skb, pctx);\n+\n+\t/* GTP header is treated as inner MAC header */\n+\tskb_reset_inner_mac_header(skb);\n+\n+\tskb_set_inner_protocol(skb, protocol);\n+\n+\treturn 0;\n+\n+free_dst:\n+\tdst_release(dst);\n+\treturn err;\n+}\n+\n static int gtp_xmit(struct sk_buff *skb, struct net_device *dev,\n \t\t    struct pdp_ctx *pctx)\n {\n@@ -746,13 +871,6 @@ static int gtp_xmit(struct sk_buff *skb, struct net_device *dev,\n \tbool udp_csum;\n \tint err = 0;\n \n-\t/* Ensure there is sufficient headroom. */\n-\terr = skb_cow_head(skb, dev->needed_headroom);\n-\tif (unlikely(err))\n-\t\tgoto out_err;\n-\n-\tskb_reset_inner_headers(skb);\n-\n \tif (pctx->peer_af == AF_INET) {\n \t\t__be32 saddr = inet_sk(sk)->inet_saddr;\n \t\tstruct rtable *rt;\n@@ -768,9 +886,13 @@ static int gtp_xmit(struct sk_buff *skb, struct net_device *dev,\n \t\t\tgoto out_err;\n \t\t}\n \n-\t\tskb_dst_drop(skb);\n+\t\terr = gtp_build_skb(skb, &rt->dst, pctx, xnet,\n+\t\t\t\t    sizeof(struct iphdr),\n+\t\t\t\t    !(pctx->cfg_flags &\n+\t\t\t\t      GTP_F_UDP_ZERO_CSUM_TX));\n+\t\tif (err)\n+\t\t\tgoto out_err;\n \n-\t\tgtp_push_header(skb, pctx);\n \t\tudp_csum = !(pctx->cfg_flags & GTP_F_UDP_ZERO_CSUM_TX);\n \t\tudp_tunnel_xmit_skb(rt, sk, skb, saddr,\n \t\t\t\t    pctx->peer_addr_ip4.s_addr,\n@@ -797,9 +919,13 @@ static int gtp_xmit(struct sk_buff *skb, struct net_device *dev,\n \t\t\tgoto out_err;\n \t\t}\n \n-\t\tskb_dst_drop(skb);\n+\t\terr = gtp_build_skb(skb, dst, pctx, xnet,\n+\t\t\t\t    sizeof(struct ipv6hdr),\n+\t\t\t\t    !(pctx->cfg_flags &\n+\t\t\t\t      GTP_F_UDP_ZERO_CSUM6_TX));\n+\t\tif (err)\n+\t\t\tgoto out_err;\n \n-\t\tgtp_push_header(skb, pctx);\n \t\tudp_csum = !(pctx->cfg_flags & GTP_F_UDP_ZERO_CSUM6_TX);\n \t\tudp_tunnel6_xmit_skb(dst, sk, skb, dev,\n \t\t\t\t     &saddr, &pctx->peer_addr_ip6,\n@@ -898,6 +1024,12 @@ static const struct net_device_ops gtp_netdev_ops = {\n \t.ndo_get_stats64\t= ip_tunnel_get_stats64,\n };\n \n+#define GTP_FEATURES (NETIF_F_SG |\t\t\\\n+\t\t      NETIF_F_FRAGLIST |\t\\\n+\t\t      NETIF_F_HIGHDMA |\t\t\\\n+\t\t      NETIF_F_GSO_SOFTWARE |\t\\\n+\t\t      NETIF_F_HW_CSUM)\n+\n static void gtp_link_setup(struct net_device *dev)\n {\n \tstruct gtp_dev *gtp = netdev_priv(dev);\n@@ -912,7 +1044,13 @@ static void gtp_link_setup(struct net_device *dev)\n \tdev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;\n \n \tdev->priv_flags\t|= IFF_NO_QUEUE;\n+\n \tdev->features\t|= NETIF_F_LLTX;\n+\tdev->features\t|= GTP_FEATURES;\n+\n+\tdev->hw_features |= GTP_FEATURES;\n+\tdev->hw_features |= NETIF_F_GSO_SOFTWARE;\n+\n \tnetif_keep_dst(dev);\n \n \t/* Assume largest header, ie. GTPv0. */\n@@ -1903,6 +2041,11 @@ static struct pernet_operations gtp_net_ops = {\n \t.size\t= sizeof(struct gtp_net),\n };\n \n+static const struct skb_gso_app gtp_gso_app = {\n+\t.check_flags = SKB_GSO_UDP_TUNNEL | SKB_GSO_UDP_TUNNEL_CSUM,\n+\t.gso_segment = gtp_gso_segment,\n+};\n+\n static int __init gtp_init(void)\n {\n \tint err;\n@@ -1921,6 +2064,10 @@ static int __init gtp_init(void)\n \tif (err < 0)\n \t\tgoto unreg_genl_family;\n \n+\tgtp_gso_type = skb_gso_app_register(&gtp_gso_app);\n+\tif (!gtp_gso_type)\n+\t\tpr_warn(\"GTP unable to create UDP app gso type\");\n+\n \tpr_info(\"GTP module loaded (pdp ctx size %zd bytes)\\n\",\n \t\tsizeof(struct pdp_ctx));\n \treturn 0;\n@@ -1937,6 +2084,9 @@ late_initcall(gtp_init);\n \n static void __exit gtp_fini(void)\n {\n+\tif (gtp_gso_type)\n+\t\tskb_gso_app_unregister(gtp_gso_type, &gtp_gso_app);\n+\n \tunregister_pernet_subsys(&gtp_net_ops);\n \tgenl_unregister_family(&gtp_genl_family);\n \trtnl_link_unregister(&gtp_link_ops);\ndiff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h\nindex 14a32d745e24..7c15db44eab3 100644\n--- a/include/uapi/linux/if_link.h\n+++ b/include/uapi/linux/if_link.h\n@@ -558,7 +558,6 @@ enum {\n \tIFLA_GTP_UDP_CSUM,\n \tIFLA_GTP_UDP_ZERO_CSUM6_TX,\n \tIFLA_GTP_UDP_ZERO_CSUM6_RX,\n-\n \t__IFLA_GTP_MAX,\n };\n #define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1)\n","prefixes":["net-next","14/14"]}