[04/16] gtp: select netns based on NL attribute
diff mbox

Message ID 1447686417-3979-5-git-send-email-aschultz@tpip.net
State Changes Requested
Delegated to: Pablo Neira
Headers show

Commit Message

Andreas Schultz Nov. 16, 2015, 3:06 p.m. UTC
This permits a split namespace setup where the GTP transport
sockets are in one namespace the gtp tunnel interface is in
another namespace.

The target namespece is selected by the new GTPA_NET_NS_FD NL
attributes. It fall back to the netns of the GTP-U sockets if
the NL attr is not present.

Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
 gtp.c    | 41 +++++++++++++++++++++++++++++++++++++----
 gtp_nl.h |  1 +
 2 files changed, 38 insertions(+), 4 deletions(-)

Comments

Pablo Neira Ayuso Nov. 16, 2015, 5:41 p.m. UTC | #1
On Mon, Nov 16, 2015 at 04:06:45PM +0100, Andreas Schultz wrote:
> This permits a split namespace setup where the GTP transport
> sockets are in one namespace the gtp tunnel interface is in
> another namespace.
> 
> The target namespece is selected by the new GTPA_NET_NS_FD NL
> attributes. It fall back to the netns of the GTP-U sockets if
> the NL attr is not present.
> 
> Signed-off-by: Andreas Schultz <aschultz@tpip.net>
> ---
>  gtp.c    | 41 +++++++++++++++++++++++++++++++++++++----
>  gtp_nl.h |  1 +
>  2 files changed, 38 insertions(+), 4 deletions(-)
> 
> diff --git a/gtp.c b/gtp.c
> index 7c61e61..11f8fad 100644
> --- a/gtp.c
> +++ b/gtp.c
> @@ -330,6 +330,8 @@ static int gtp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
>  	if (!gti)
>  		goto user;
>  
> +	netdev_dbg(gti->dev, "encap_recv %p\n", sk);
> +
>  	switch (udp_sk(sk)->encap_type) {
>  	case UDP_ENCAP_GTP0:
>  		netdev_dbg(gti->dev, "received GTP0 packet\n");
> @@ -738,7 +740,7 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti,
>  static int gtp_newlink(struct net *src_net, struct net_device *dev,
>  			struct nlattr *tb[], struct nlattr *data[])
>  {
> -	struct gtp_net *gn = net_generic(src_net, gtp_net_id);
> +	struct gtp_net *gn;
>  	struct net_device *real_dev;
>  	struct gtp_instance *gti;
>  	int hashsize, err, fd0, fd1;
> @@ -778,6 +780,7 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev,
>  	if (err < 0)
>  		goto err1;
>  
> +	gn = net_generic(dev_net(dev), gtp_net_id);
>  	list_add_rcu(&gti->list, &gn->gtp_instance_list);
>  
>  	netdev_dbg(dev, "registered new interface\n");
> @@ -845,6 +848,19 @@ static struct rtnl_link_ops gtp_link_ops __read_mostly = {
>  	.fill_info	= gtp_fill_info,
>  };
>  
> +static struct net *gtp_genl_get_net(struct net *src_net, struct nlattr *tb[])
> +{
> +	struct net *net;
> +	/* Examine the link attributes and figure out which
> +	 * network namespace we are talking about.
> +	 */
> +	if (tb[GTPA_NET_NS_FD])
> +		net = get_net_ns_by_fd(nla_get_u32(tb[GTPA_NET_NS_FD]));

I can see this returns ERR_PTR() so...

> +	else
> +		net = get_net(src_net);
> +	return net;
> +}
> +
>  static int gtp_hashtable_new(struct gtp_instance *gti, int hsize)
>  {
>  	int i;
> @@ -893,6 +909,8 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti,
>  	struct socket *sock0, *sock1u;
>  	struct sock *sk;
>  
> +	netdev_dbg(dev, "enable gtp on %d, %d\n", fd_gtp0, fd_gtp1);
> +
>  	sock0 = sockfd_lookup(fd_gtp0, &err);
>  	if (sock0 == NULL) {
>  		netdev_dbg(dev, "socket fd=%d not found (gtp0)\n", fd_gtp0);
> @@ -918,6 +936,8 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti,
>  		goto err2;
>  	}
>  
> +	netdev_dbg(dev, "enable gtp on %p, %p\n", sock0, sock1u);
> +
>  	gti->sock0 = sock0;
>  	gti->sock1u = sock1u;
>  
> @@ -1059,7 +1079,7 @@ static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info)
>  
>  static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info)
>  {
> -	struct net *net = sock_net(skb->sk);
> +	struct net *net;
>  	struct net_device *dev;
>  
>  	if (!info->attrs[GTPA_VERSION] ||
> @@ -1069,6 +1089,10 @@ static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info)
>  	    !info->attrs[GTPA_TID])
>  		return -EINVAL;
>  
> +	net = gtp_genl_get_net(sock_net(skb->sk), info->attrs);
> +	if (net == NULL)

This has to be IS_ERR().

> +		return -EINVAL;
> +
>  	/* Check if there's an existing gtpX device to configure */
>  	dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK]));
>  	if (dev == NULL)
> @@ -1079,7 +1103,7 @@ static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info)
>  
>  static int gtp_genl_tunnel_delete(struct sk_buff *skb, struct genl_info *info)
>  {
> -	struct net *net = sock_net(skb->sk);
> +	struct net *net;
>  	struct gtp_instance *gti;
>  	struct net_device *dev;
>  	struct pdp_ctx *pctx;
> @@ -1107,6 +1131,10 @@ static int gtp_genl_tunnel_delete(struct sk_buff *skb, struct genl_info *info)
>  	if (gtp_version == GTP_V1 && tid > UINT_MAX)
>  		return -EINVAL;
>  
> +	net = gtp_genl_get_net(sock_net(skb->sk), info->attrs);
> +	if (net == NULL)

This one too.

> +		return -EINVAL;
> +
>  	/* Check if there's an existing gtpX device to configure */
>  	dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK]));
>  	if (dev == NULL)
> @@ -1175,7 +1203,7 @@ nla_put_failure:
>  
>  static int gtp_genl_tunnel_get(struct sk_buff *skb, struct genl_info *info)
>  {
> -	struct net *net = sock_net(skb->sk);
> +	struct net *net;
>  	struct net_device *dev;
>  	struct gtp_instance *gti;
>  	struct pdp_ctx *pctx = NULL;
> @@ -1196,6 +1224,10 @@ static int gtp_genl_tunnel_get(struct sk_buff *skb, struct genl_info *info)
>  		return -EINVAL;
>  	}
>  
> +	net = gtp_genl_get_net(sock_net(skb->sk), info->attrs);
> +	if (net == NULL)

And here.

BTW, I'd appreciate if you can add netdev_dbg stuff in a separated
patch.
Andreas Schultz Nov. 16, 2015, 5:49 p.m. UTC | #2
----- Original Message -----
> From: "Pablo Neira Ayuso" <pablo@soleta.eu>
> To: "Andreas Schultz" <aschultz@tpip.net>
> Cc: openbsc@lists.osmocom.org, "Harald Welte" <laforge@gnumonks.org>
> Sent: Monday, November 16, 2015 6:41:34 PM
> Subject: Re: [PATCH 04/16] gtp: select netns based on NL attribute

> On Mon, Nov 16, 2015 at 04:06:45PM +0100, Andreas Schultz wrote:

[...]
> 
> This has to be IS_ERR().
> 

Didn't know that, thanks for the explanation. I'll send a new patch
soon.

> BTW, I'd appreciate if you can add netdev_dbg stuff in a separated
> patch.

Will do.

Andreas

Patch
diff mbox

diff --git a/gtp.c b/gtp.c
index 7c61e61..11f8fad 100644
--- a/gtp.c
+++ b/gtp.c
@@ -330,6 +330,8 @@  static int gtp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 	if (!gti)
 		goto user;
 
+	netdev_dbg(gti->dev, "encap_recv %p\n", sk);
+
 	switch (udp_sk(sk)->encap_type) {
 	case UDP_ENCAP_GTP0:
 		netdev_dbg(gti->dev, "received GTP0 packet\n");
@@ -738,7 +740,7 @@  static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti,
 static int gtp_newlink(struct net *src_net, struct net_device *dev,
 			struct nlattr *tb[], struct nlattr *data[])
 {
-	struct gtp_net *gn = net_generic(src_net, gtp_net_id);
+	struct gtp_net *gn;
 	struct net_device *real_dev;
 	struct gtp_instance *gti;
 	int hashsize, err, fd0, fd1;
@@ -778,6 +780,7 @@  static int gtp_newlink(struct net *src_net, struct net_device *dev,
 	if (err < 0)
 		goto err1;
 
+	gn = net_generic(dev_net(dev), gtp_net_id);
 	list_add_rcu(&gti->list, &gn->gtp_instance_list);
 
 	netdev_dbg(dev, "registered new interface\n");
@@ -845,6 +848,19 @@  static struct rtnl_link_ops gtp_link_ops __read_mostly = {
 	.fill_info	= gtp_fill_info,
 };
 
+static struct net *gtp_genl_get_net(struct net *src_net, struct nlattr *tb[])
+{
+	struct net *net;
+	/* Examine the link attributes and figure out which
+	 * network namespace we are talking about.
+	 */
+	if (tb[GTPA_NET_NS_FD])
+		net = get_net_ns_by_fd(nla_get_u32(tb[GTPA_NET_NS_FD]));
+	else
+		net = get_net(src_net);
+	return net;
+}
+
 static int gtp_hashtable_new(struct gtp_instance *gti, int hsize)
 {
 	int i;
@@ -893,6 +909,8 @@  static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti,
 	struct socket *sock0, *sock1u;
 	struct sock *sk;
 
+	netdev_dbg(dev, "enable gtp on %d, %d\n", fd_gtp0, fd_gtp1);
+
 	sock0 = sockfd_lookup(fd_gtp0, &err);
 	if (sock0 == NULL) {
 		netdev_dbg(dev, "socket fd=%d not found (gtp0)\n", fd_gtp0);
@@ -918,6 +936,8 @@  static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti,
 		goto err2;
 	}
 
+	netdev_dbg(dev, "enable gtp on %p, %p\n", sock0, sock1u);
+
 	gti->sock0 = sock0;
 	gti->sock1u = sock1u;
 
@@ -1059,7 +1079,7 @@  static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info)
 
 static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info)
 {
-	struct net *net = sock_net(skb->sk);
+	struct net *net;
 	struct net_device *dev;
 
 	if (!info->attrs[GTPA_VERSION] ||
@@ -1069,6 +1089,10 @@  static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info)
 	    !info->attrs[GTPA_TID])
 		return -EINVAL;
 
+	net = gtp_genl_get_net(sock_net(skb->sk), info->attrs);
+	if (net == NULL)
+		return -EINVAL;
+
 	/* Check if there's an existing gtpX device to configure */
 	dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK]));
 	if (dev == NULL)
@@ -1079,7 +1103,7 @@  static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info)
 
 static int gtp_genl_tunnel_delete(struct sk_buff *skb, struct genl_info *info)
 {
-	struct net *net = sock_net(skb->sk);
+	struct net *net;
 	struct gtp_instance *gti;
 	struct net_device *dev;
 	struct pdp_ctx *pctx;
@@ -1107,6 +1131,10 @@  static int gtp_genl_tunnel_delete(struct sk_buff *skb, struct genl_info *info)
 	if (gtp_version == GTP_V1 && tid > UINT_MAX)
 		return -EINVAL;
 
+	net = gtp_genl_get_net(sock_net(skb->sk), info->attrs);
+	if (net == NULL)
+		return -EINVAL;
+
 	/* Check if there's an existing gtpX device to configure */
 	dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK]));
 	if (dev == NULL)
@@ -1175,7 +1203,7 @@  nla_put_failure:
 
 static int gtp_genl_tunnel_get(struct sk_buff *skb, struct genl_info *info)
 {
-	struct net *net = sock_net(skb->sk);
+	struct net *net;
 	struct net_device *dev;
 	struct gtp_instance *gti;
 	struct pdp_ctx *pctx = NULL;
@@ -1196,6 +1224,10 @@  static int gtp_genl_tunnel_get(struct sk_buff *skb, struct genl_info *info)
 		return -EINVAL;
 	}
 
+	net = gtp_genl_get_net(sock_net(skb->sk), info->attrs);
+	if (net == NULL)
+		return -EINVAL;
+
 	/* Check if there's an existing gtpX device to configure */
 	dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK]));
 	if (dev == NULL)
@@ -1304,6 +1336,7 @@  static struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = {
 	[GTPA_SGSN_ADDRESS]	= { .type = NLA_NESTED, },
 	[GTPA_MS_ADDRESS]	= { .type = NLA_NESTED, },
 	[GTPA_FLOW]		= { .type = NLA_U16, },
+	[GTPA_NET_NS_FD]	= { .type = NLA_U32, },
 };
 
 static const struct genl_ops gtp_genl_ops[] = {
diff --git a/gtp_nl.h b/gtp_nl.h
index 7bdd2f5..c20666d 100644
--- a/gtp_nl.h
+++ b/gtp_nl.h
@@ -40,6 +40,7 @@  enum gtp_attrs {
 	GTPA_SGSN_ADDRESS,
 	GTPA_MS_ADDRESS,
 	GTPA_FLOW,
+	GTPA_NET_NS_FD,
 	__GTPA_MAX,
 };
 #define GTPA_MAX (__GTPA_MAX + 1)