From patchwork Tue Jan 24 15:28:33 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Schultz X-Patchwork-Id: 719193 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.osmocom.org (lists.osmocom.org [144.76.43.76]) by ozlabs.org (Postfix) with ESMTP id 3v7Bt75R1Kz9t0G for ; Wed, 25 Jan 2017 02:29:03 +1100 (AEDT) Received: from lists.osmocom.org (lists.osmocom.org [144.76.43.76]) by lists.osmocom.org (Postfix) with ESMTP id 2315B2802F; Tue, 24 Jan 2017 15:29:02 +0000 (UTC) Authentication-Results: lists.osmocom.org; dmarc=none header.from=tpip.net X-Original-To: openbsc@lists.osmocom.org Delivered-To: openbsc@lists.osmocom.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=92.43.49.48; helo=mail.tpip.net; envelope-from=aschultz@tpip.net; receiver=openbsc@lists.osmocom.org Authentication-Results: lists.osmocom.org; dmarc=none header.from=tpip.net Received: from mail.tpip.net (mail.tpip.net [92.43.49.48]) by lists.osmocom.org (Postfix) with ESMTP id 60C8729EF4 for ; Tue, 24 Jan 2017 15:28:54 +0000 (UTC) Received: from office.tpip.net (unknown [153.92.65.89]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.tpip.net (Postfix) with ESMTPS id E1F624F407; Tue, 24 Jan 2017 15:28:53 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by office.tpip.net (Postfix) with ESMTP id B8E61A2CD8; Tue, 24 Jan 2017 16:28:53 +0100 (CET) Received: from office.tpip.net ([127.0.0.1]) by localhost (office.tpip.net [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id Z91XwKa5DCv5; Tue, 24 Jan 2017 16:28:53 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by office.tpip.net (Postfix) with ESMTP id 20A2AA2CC1; Tue, 24 Jan 2017 16:28:53 +0100 (CET) X-Virus-Scanned: amavisd-new at tpip.net Received: from office.tpip.net ([127.0.0.1]) by localhost (office.tpip.net [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id Z26vvRSdC9l9; Tue, 24 Jan 2017 16:28:53 +0100 (CET) Received: from localhost.localdomain (pd95c9392.dip0.t-ipconnect.de [217.92.147.146]) by office.tpip.net (Postfix) with ESMTPSA id C5528A2CC2; Tue, 24 Jan 2017 16:28:52 +0100 (CET) From: Andreas Schultz To: Pablo Neira Subject: [PATCH v2 03/18] gtp: make GTP sockets in gtp_newlink optional Date: Tue, 24 Jan 2017 16:28:33 +0100 Message-Id: <20170124152848.6120-4-aschultz@tpip.net> X-Mailer: git-send-email 2.10.2 In-Reply-To: <20170124152848.6120-1-aschultz@tpip.net> References: <20170124152848.6120-1-aschultz@tpip.net> X-BeenThere: openbsc@lists.osmocom.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Development of OpenBSC, OsmoBSC, OsmoNITB, OsmoCSCN" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: netdev@vger.kernel.org, openbsc@lists.osmocom.org, Lionel Gauthier Errors-To: openbsc-bounces@lists.osmocom.org Sender: "OpenBSC" A fixed binding of gtp enabled socket to netdevice does not make sense (GTP TEID are unique per socket and not per L3 IP device). To untangle netdevice and gtp sockets without breaking the UAPI, make per netdevice sockets optional. Signed-off-by: Andreas Schultz --- drivers/net/gtp.c | 158 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 83 insertions(+), 75 deletions(-) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 1df54d6..60946b7 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -276,30 +276,6 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, return ret; } -static void gtp_encap_disable(struct gtp_dev *gtp) -{ - if (gtp->sock0 && gtp->sock0->sk) { - udp_sk(gtp->sock0->sk)->encap_type = 0; - rcu_assign_sk_user_data(gtp->sock0->sk, NULL); - } - if (gtp->sock1u && gtp->sock1u->sk) { - udp_sk(gtp->sock1u->sk)->encap_type = 0; - rcu_assign_sk_user_data(gtp->sock1u->sk, NULL); - } - - gtp->sock0 = NULL; - gtp->sock1u = NULL; -} - -static void gtp_encap_destroy(struct sock *sk) -{ - struct gtp_dev *gtp; - - gtp = rcu_dereference_sk_user_data(sk); - if (gtp) - gtp_encap_disable(gtp); -} - /* UDP encapsulation receive handler. See net/ipv4/udp.c. * Return codes: 0: success, <0: error, >0: pass up to userspace UDP socket. */ @@ -363,6 +339,17 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb) return 0; } +static void gtp_encap_destroy(struct sock *sk) +{ + struct gtp_dev *gtp; + + gtp = rcu_dereference_sk_user_data(sk); + if (gtp) { + udp_sk(sk)->encap_type = 0; + rcu_assign_sk_user_data(sk, NULL); + } +} + static int gtp_dev_init(struct net_device *dev) { struct gtp_dev *gtp = netdev_priv(dev); @@ -378,9 +365,6 @@ static int gtp_dev_init(struct net_device *dev) static void gtp_dev_uninit(struct net_device *dev) { - struct gtp_dev *gtp = netdev_priv(dev); - - gtp_encap_disable(gtp); free_percpu(dev->tstats); } @@ -658,35 +642,32 @@ static void gtp_link_setup(struct net_device *dev) static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize); static void gtp_hashtable_free(struct gtp_dev *gtp); static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp, - int fd_gtp0, int fd_gtp1, struct net *src_net); + struct net *src_net, struct nlattr *data[]); +static void gtp_encap_disable(struct gtp_dev *gtp); static int gtp_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { - int hashsize, err, fd0, fd1; + int hashsize, err; struct gtp_dev *gtp; struct gtp_net *gn; - if (!data[IFLA_GTP_FD0] || !data[IFLA_GTP_FD1]) - return -EINVAL; - gtp = netdev_priv(dev); - fd0 = nla_get_u32(data[IFLA_GTP_FD0]); - fd1 = nla_get_u32(data[IFLA_GTP_FD1]); - - err = gtp_encap_enable(dev, gtp, fd0, fd1, src_net); - if (err < 0) - goto out_err; - if (!data[IFLA_GTP_PDP_HASHSIZE]) hashsize = 1024; else hashsize = nla_get_u32(data[IFLA_GTP_PDP_HASHSIZE]); + if (data[IFLA_GTP_FD0] || data[IFLA_GTP_FD1]) { + err = gtp_encap_enable(dev, gtp, src_net, data); + if (err < 0) + goto out_err; + } + err = gtp_hashtable_new(gtp, hashsize); if (err < 0) - goto out_encap; + goto out_socket; err = register_netdevice(dev); if (err < 0) { @@ -703,7 +684,7 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, out_hashtable: gtp_hashtable_free(gtp); -out_encap: +out_socket: gtp_encap_disable(gtp); out_err: return err; @@ -713,8 +694,11 @@ static void gtp_dellink(struct net_device *dev, struct list_head *head) { struct gtp_dev *gtp = netdev_priv(dev); - gtp_encap_disable(gtp); gtp_hashtable_free(gtp); + if (gtp->sock0) + sockfd_put(gtp->sock0); + if (gtp->sock1u) + sockfd_put(gtp->sock1u); list_del_rcu(>p->list); unregister_netdevice_queue(dev, head); } @@ -820,38 +804,63 @@ static void gtp_hashtable_free(struct gtp_dev *gtp) kfree(gtp->tid_hash); } -static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp, - int fd_gtp0, int fd_gtp1, struct net *src_net) +static struct socket *gtp_encap_enable_socket(int fd, int type, + struct gtp_dev *gtp) { struct udp_tunnel_sock_cfg tuncfg = {NULL}; - struct socket *sock0, *sock1u; + struct socket *sock; int err; - netdev_dbg(dev, "enable gtp on %d, %d\n", fd_gtp0, fd_gtp1); + pr_debug("enable gtp on %d, %d\n", fd, type); - sock0 = sockfd_lookup(fd_gtp0, &err); - if (sock0 == NULL) { - netdev_dbg(dev, "socket fd=%d not found (gtp0)\n", fd_gtp0); - return -ENOENT; + sock = sockfd_lookup(fd, &err); + if (!sock) { + pr_debug("gtp socket fd=%d not found\n", fd); + return NULL; } - if (sock0->sk->sk_protocol != IPPROTO_UDP) { - netdev_dbg(dev, "socket fd=%d not UDP\n", fd_gtp0); + if (sock->sk->sk_protocol != IPPROTO_UDP) { + pr_debug("socket fd=%d not UDP\n", fd); err = -EINVAL; - goto err1; + goto out_sock; } - sock1u = sockfd_lookup(fd_gtp1, &err); - if (sock1u == NULL) { - netdev_dbg(dev, "socket fd=%d not found (gtp1u)\n", fd_gtp1); - err = -ENOENT; - goto err1; + tuncfg.sk_user_data = gtp; + tuncfg.encap_type = type; + tuncfg.encap_rcv = gtp_encap_recv; + tuncfg.encap_destroy = gtp_encap_destroy; + + setup_udp_tunnel_sock(sock_net(sock->sk), sock, &tuncfg); + return sock; + +out_sock: + sockfd_put(sock); + return ERR_PTR(err); +} + +static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp, + struct net *src_net, struct nlattr *data[]) +{ + struct socket *sock0 = NULL; + struct socket *sock1u = NULL; + + if (data[IFLA_GTP_FD0]) { + u32 fd0 = nla_get_u32(data[IFLA_GTP_FD0]); + + sock0 = gtp_encap_enable_socket(fd0, UDP_ENCAP_GTP0, gtp); + if (IS_ERR(sock0)) + return PTR_ERR(sock0); } - if (sock1u->sk->sk_protocol != IPPROTO_UDP) { - netdev_dbg(dev, "socket fd=%d not UDP\n", fd_gtp1); - err = -EINVAL; - goto err2; + if (data[IFLA_GTP_FD1]) { + u32 fd1 = nla_get_u32(data[IFLA_GTP_FD1]); + + sock1u = gtp_encap_enable_socket(fd1, UDP_ENCAP_GTP1U, gtp); + if (IS_ERR(sock1u)) { + if (sock0) + sockfd_put(sock0); + return PTR_ERR(sock1u); + } } netdev_dbg(dev, "enable gtp on %p, %p\n", sock0, sock1u); @@ -860,22 +869,21 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp, gtp->sock1u = sock1u; gtp->net = src_net; - tuncfg.sk_user_data = gtp; - tuncfg.encap_rcv = gtp_encap_recv; - tuncfg.encap_destroy = gtp_encap_destroy; + return 0; +} - tuncfg.encap_type = UDP_ENCAP_GTP0; - setup_udp_tunnel_sock(sock_net(gtp->sock0->sk), gtp->sock0, &tuncfg); +static void gtp_encap_disable_sock(struct socket *sock) +{ + if (!sock || !sock->sk) + return; - tuncfg.encap_type = UDP_ENCAP_GTP1U; - setup_udp_tunnel_sock(sock_net(gtp->sock1u->sk), gtp->sock1u, &tuncfg); + gtp_encap_destroy(sock->sk); +} - err = 0; -err2: - sockfd_put(sock1u); -err1: - sockfd_put(sock0); - return err; +static void gtp_encap_disable(struct gtp_dev *gtp) +{ + gtp_encap_disable_sock(gtp->sock0); + gtp_encap_disable_sock(gtp->sock1u); } static struct net_device *gtp_find_dev(struct net *net, int ifindex)