From patchwork Mon Jan 23 11:56:52 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Schultz X-Patchwork-Id: 718493 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.osmocom.org (lists.osmocom.org [IPv6:2a01:4f8:191:444b::2:7]) by ozlabs.org (Postfix) with ESMTP id 3v6VT6586dz9s2s for ; Mon, 23 Jan 2017 23:08:26 +1100 (AEDT) Received: from lists.osmocom.org (lists.osmocom.org [144.76.43.76]) by lists.osmocom.org (Postfix) with ESMTP id 6287D21F8; Mon, 23 Jan 2017 12:08:25 +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 49BA92057 for ; Mon, 23 Jan 2017 12:06:53 +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 9C7064F407; Mon, 23 Jan 2017 11:57:11 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by office.tpip.net (Postfix) with ESMTP id 6F793A2CC2; Mon, 23 Jan 2017 12:57:11 +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 P0m0o9znRdt3; Mon, 23 Jan 2017 12:57:10 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by office.tpip.net (Postfix) with ESMTP id D5C83A2CC0; Mon, 23 Jan 2017 12:57:10 +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 jbolMEMTpRTd; Mon, 23 Jan 2017 12:57:10 +0100 (CET) Received: from localhost.localdomain (pd95c9392.dip0.t-ipconnect.de [217.92.147.146]) by office.tpip.net (Postfix) with ESMTPSA id 8E09EA2C97; Mon, 23 Jan 2017 12:57:10 +0100 (CET) From: Andreas Schultz To: Pablo Neira Subject: [PATCH 03/17] gtp: make GTP sockets in gtp_newlink optional Date: Mon, 23 Jan 2017 12:56:52 +0100 Message-Id: <20170123115706.4354-4-aschultz@tpip.net> X-Mailer: git-send-email 2.10.2 In-Reply-To: <20170123115706.4354-1-aschultz@tpip.net> References: <20170123115706.4354-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, Lionel Gauthier , openbsc@lists.osmocom.org 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)