From patchwork Thu Oct 26 19:09:26 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Herbert X-Patchwork-Id: 830894 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=quantonium-net.20150623.gappssmtp.com header.i=@quantonium-net.20150623.gappssmtp.com header.b="KWdJ/B+g"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yNGmd1XSGz9s7f for ; Fri, 27 Oct 2017 06:10:25 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752006AbdJZTKW (ORCPT ); Thu, 26 Oct 2017 15:10:22 -0400 Received: from mail-pf0-f194.google.com ([209.85.192.194]:52939 "EHLO mail-pf0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751984AbdJZTKT (ORCPT ); Thu, 26 Oct 2017 15:10:19 -0400 Received: by mail-pf0-f194.google.com with SMTP id e64so3174162pfk.9 for ; Thu, 26 Oct 2017 12:10:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quantonium-net.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=1jPs//2PQQ6nFjehrosWRdlrzA317lfzDVLuu7P/x9Q=; b=KWdJ/B+gzZ0WOV4F5QI27Xc88WXaYsEPGb+w4NLwUj5MvkAXf0HXLJv71WYu/mIJNz 0blnfpd4jijLREmAuPLHZyT4Bhg8dL5LekPcyh5AmAtpzEMm1oQTYcN97IXh6CsdP0AN Xan70azeW8mNJrnNfHy/5HImyH8F0APZaR2gVAg7UBTMJdOh/LGPHU1k6I1eoG3gO4ig w8A+x3uY/N/UJCaQi6tPMEzM2gNMM72irxA4DVk0fUd0hItEnkSvjl2x9lS9F4YarFKR Ib3DdWUkADfdnx1pVk682MkcUkDyg3/AyTxrSU48eYMt7bNW7OIs9Ipgvrgk7Tphnbk+ 4Qiw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=1jPs//2PQQ6nFjehrosWRdlrzA317lfzDVLuu7P/x9Q=; b=bxroAWIAH21xzvy5Jbn3xP6/nFDFQ/R8CAhk61OiuqvSr+NRcEJk6KPh69RxxbltVj tHbaD/Kwfkte9J0feZWQA3coGrf3wAo4jADphj0cOVGMu1eLB5XJ0slKAoRR+iWeg/mb LlL+lTJdJ+B/7ECI8xefUbJSASrAUTRrmDQH8267ZwiVY1rbibP+PjRsreCSW9C0iAVe +LxwBUJC/CdWSFb1uaehFzntMGIDLD6tuRm/dYV2WeaoNlUwKm9/xJjpSZEc9h/Ratb2 31W4DX+1mERQSsDYIGLez4kh8azUKftEqBQ5K+H/51WO+A7o4aM6ze704T4NfrFn57h2 ZlHA== X-Gm-Message-State: AMCzsaXyFTSIrJ8VKoeAdo2PJy3lZq6qeDn+MMaAos+3cB3KQLTYD13q VWP/kXFxaKai9s5z1jSVpehuMQ== X-Google-Smtp-Source: ABhQp+T6YR1ZxsWt4TprD19d+o+FfvWuWntgklv3dG7Hf6zMibgt0d8wOZtEPYRS5qcD4IQhh9BQGA== X-Received: by 10.98.107.133 with SMTP id g127mr6363244pfc.228.1509045018620; Thu, 26 Oct 2017 12:10:18 -0700 (PDT) Received: from localhost.localdomain (67-207-98-108.static.wiline.com. [67.207.98.108]) by smtp.gmail.com with ESMTPSA id j1sm11071502pfc.169.2017.10.26.12.10.16 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 26 Oct 2017 12:10:17 -0700 (PDT) From: Tom Herbert To: davem@davemloft.net Cc: pablo@netfilter.org, laforge@gnumonks.org, aschultz@tpip.net, netdev@vger.kernel.org, rohit@quantonium.net, Tom Herbert Subject: [PATCH v6 net-next 09/12] gtp: Eliminate pktinfo and add port configuration Date: Thu, 26 Oct 2017 12:09:26 -0700 Message-Id: <20171026190929.11619-10-tom@quantonium.net> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20171026190929.11619-1-tom@quantonium.net> References: <20171026190929.11619-1-tom@quantonium.net> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The gtp pktinfo structure is unnecessary and needs a lot of code to manage it. Remove it. Also, add per pdp port configuration for transmit. Signed-off-by: Tom Herbert --- drivers/net/gtp.c | 177 +++++++++++++++++++++-------------------------- include/uapi/linux/gtp.h | 1 + 2 files changed, 80 insertions(+), 98 deletions(-) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index bbb08f8849d3..44844eba8df2 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -54,6 +54,7 @@ struct pdp_ctx { } u; u8 gtp_version; u8 hlen; + __be16 gtp_port; u16 af; struct in_addr ms_addr_ip4; @@ -420,73 +421,36 @@ static inline void gtp1_push_header(struct sk_buff *skb, struct pdp_ctx *pctx) */ } -struct gtp_pktinfo { - struct sock *sk; - struct iphdr *iph; - struct flowi4 fl4; - struct rtable *rt; - struct pdp_ctx *pctx; - struct net_device *dev; - __be16 gtph_port; -}; - -static void gtp_push_header(struct sk_buff *skb, struct gtp_pktinfo *pktinfo) +static void gtp_push_header(struct sk_buff *skb, struct pdp_ctx *pctx) { - switch (pktinfo->pctx->gtp_version) { + switch (pctx->gtp_version) { case GTP_V0: - pktinfo->gtph_port = htons(GTP0_PORT); - gtp0_push_header(skb, pktinfo->pctx); + gtp0_push_header(skb, pctx); break; case GTP_V1: - pktinfo->gtph_port = htons(GTP1U_PORT); - gtp1_push_header(skb, pktinfo->pctx); + gtp1_push_header(skb, pctx); break; } } -static inline void gtp_set_pktinfo_ipv4(struct gtp_pktinfo *pktinfo, - struct sock *sk, struct iphdr *iph, - struct pdp_ctx *pctx, struct rtable *rt, - struct flowi4 *fl4, - struct net_device *dev) -{ - pktinfo->sk = sk; - pktinfo->iph = iph; - pktinfo->pctx = pctx; - pktinfo->rt = rt; - pktinfo->fl4 = *fl4; - pktinfo->dev = dev; -} - -static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev, - struct gtp_pktinfo *pktinfo) +static int gtp_xmit(struct sk_buff *skb, struct net_device *dev, + struct pdp_ctx *pctx) { - struct gtp_dev *gtp = netdev_priv(dev); - struct pdp_ctx *pctx; + struct iphdr *inner_iph = NULL; + struct sock *sk = pctx->sk; + __be32 saddr = inet_sk(sk)->inet_saddr; struct rtable *rt; - struct flowi4 fl4; - struct iphdr *iph; - struct sock *sk; - __be32 saddr; + int err = 0; - /* Read the IP destination address and resolve the PDP context. - * Prepend PDP header with TEI/TID from PDP ctx. - */ - iph = ip_hdr(skb); - if (gtp->role == GTP_ROLE_SGSN) - pctx = ipv4_pdp_find(gtp, iph->saddr); - else - pctx = ipv4_pdp_find(gtp, iph->daddr); + if (skb->protocol == ETH_P_IP) + inner_iph = ip_hdr(skb); - if (!pctx) { - netdev_dbg(dev, "no PDP ctx found for %pI4, skip\n", - &iph->daddr); - return -ENOENT; - } - netdev_dbg(dev, "found PDP context %p\n", pctx); + /* Ensure there is sufficient headroom. */ + err = skb_cow_head(skb, dev->needed_headroom); + if (unlikely(err)) + goto out_err; - sk = pctx->sk; - saddr = inet_sk(sk)->inet_saddr; + skb_reset_inner_headers(skb); /* Source address returned by route lookup is ignored since * we get the address from a socket. @@ -494,81 +458,89 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev, rt = ip_tunnel_get_route(dev, skb, sk->sk_protocol, sk->sk_bound_dev_if, RT_CONN_FLAGS(sk), pctx->peer_addr_ip4.s_addr, &saddr, - pktinfo->gtph_port, pktinfo->gtph_port, + pctx->gtp_port, pctx->gtp_port, &pctx->dst_cache, NULL); if (IS_ERR(rt)) { - if (rt == ERR_PTR(-ELOOP)) { - netdev_dbg(dev, "circular route to SSGN %pI4\n", - &pctx->peer_addr_ip4.s_addr); - dev->stats.collisions++; - goto err_rt; - } else { - netdev_dbg(dev, "no route to SSGN %pI4\n", - &pctx->peer_addr_ip4.s_addr); - dev->stats.tx_carrier_errors++; - goto err; - } + err = PTR_ERR(rt); + goto out_err; } skb_dst_drop(skb); - gtp_set_pktinfo_ipv4(pktinfo, sk, iph, pctx, rt, &fl4, dev); - gtp_push_header(skb, pktinfo); + gtp_push_header(skb, pctx); + + if (inner_iph) + __iptunnel_update_pmtu(dev, skb, &rt->dst, + !!inner_iph->frag_off, + inner_iph, pctx->hlen, + pctx->peer_addr_ip4.s_addr); - __iptunnel_update_pmtu(dev, skb, &rt->dst, !!iph->frag_off, iph, - pctx->hlen, pctx->peer_addr_ip4.s_addr); + udp_tunnel_xmit_skb(rt, sk, skb, saddr, + pctx->peer_addr_ip4.s_addr, + 0, ip4_dst_hoplimit(&rt->dst), 0, + pctx->gtp_port, pctx->gtp_port, + false, false); + + netdev_dbg(dev, "gtp -> IP src: %pI4 dst: %pI4\n", + &saddr, &pctx->peer_addr_ip4.s_addr); return 0; -err_rt: - ip_rt_put(rt); -err: - return -EBADMSG; + +out_err: + if (err == -ELOOP) + dev->stats.collisions++; + else + dev->stats.tx_carrier_errors++; + + return err; } static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned int proto = ntohs(skb->protocol); - struct gtp_pktinfo pktinfo; + struct gtp_dev *gtp = netdev_priv(dev); + struct pdp_ctx *pctx; int err; - /* Ensure there is sufficient headroom. */ - if (skb_cow_head(skb, dev->needed_headroom)) - goto tx_err; - - skb_reset_inner_headers(skb); - /* PDP context lookups in gtp_build_skb_*() need rcu read-side lock. */ rcu_read_lock(); switch (proto) { - case ETH_P_IP: - err = gtp_build_skb_ip4(skb, dev, &pktinfo); + case ETH_P_IP: { + struct iphdr *iph = ip_hdr(skb); + + if (gtp->role == GTP_ROLE_SGSN) + pctx = ipv4_pdp_find(gtp, iph->saddr); + else + pctx = ipv4_pdp_find(gtp, iph->daddr); + + if (!pctx) { + netdev_dbg(dev, "no PDP ctx found for %pI4, skip\n", + &iph->daddr); + err = -ENOENT; + goto tx_err; + } + break; + } default: err = -EOPNOTSUPP; - break; + goto tx_err; } - rcu_read_unlock(); + + netdev_dbg(dev, "found PDP context %p\n", pctx); + + err = gtp_xmit(skb, dev, pctx); if (err < 0) goto tx_err; - switch (proto) { - case ETH_P_IP: - netdev_dbg(pktinfo.dev, "gtp -> IP src: %pI4 dst: %pI4\n", - &pktinfo.iph->saddr, &pktinfo.iph->daddr); - udp_tunnel_xmit_skb(pktinfo.rt, pktinfo.sk, skb, - pktinfo.fl4.saddr, pktinfo.fl4.daddr, - pktinfo.iph->tos, - ip4_dst_hoplimit(&pktinfo.rt->dst), - 0, - pktinfo.gtph_port, pktinfo.gtph_port, - true, false); - break; - } + rcu_read_unlock(); return NETDEV_TX_OK; + tx_err: + rcu_read_unlock(); dev->stats.tx_errors++; dev_kfree_skb(skb); return NETDEV_TX_OK; @@ -874,6 +846,8 @@ static struct gtp_dev *gtp_find_dev(struct net *src_net, struct nlattr *nla[]) static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info) { + __be16 default_port = 0; + pctx->gtp_version = nla_get_u32(info->attrs[GTPA_VERSION]); pctx->af = AF_INET; pctx->peer_addr_ip4.s_addr = @@ -890,15 +864,22 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info) pctx->u.v0.tid = nla_get_u64(info->attrs[GTPA_TID]); pctx->u.v0.flow = nla_get_u16(info->attrs[GTPA_FLOW]); pctx->hlen = sizeof(struct udphdr) + sizeof(struct gtp0_header); + default_port = htons(GTP0_PORT); break; case GTP_V1: pctx->u.v1.i_tei = nla_get_u32(info->attrs[GTPA_I_TEI]); pctx->u.v1.o_tei = nla_get_u32(info->attrs[GTPA_O_TEI]); pctx->hlen = sizeof(struct udphdr) + sizeof(struct gtp1_header); + default_port = htons(GTP1U_PORT); break; default: break; } + + if (info->attrs[GTPA_PORT]) + pctx->gtp_port = nla_get_u16(info->attrs[GTPA_PORT]); + else + pctx->gtp_port = default_port; } static int ipv4_pdp_add(struct gtp_dev *gtp, struct sock *sk, diff --git a/include/uapi/linux/gtp.h b/include/uapi/linux/gtp.h index 57d1edb8efd9..b2283a5c6d7f 100644 --- a/include/uapi/linux/gtp.h +++ b/include/uapi/linux/gtp.h @@ -27,6 +27,7 @@ enum gtp_attrs { GTPA_I_TEI, /* for GTPv1 only */ GTPA_O_TEI, /* for GTPv1 only */ GTPA_PAD, + GTPA_PORT, __GTPA_MAX, }; #define GTPA_MAX (__GTPA_MAX + 1)