forked from mirrors/linux
		
	gtp: Allow to create GTP device without FDs
Currently, when the user wants to create GTP device, he has to provide file handles to the sockets created in userspace (IFLA_GTP_FD0, IFLA_GTP_FD1). This behaviour is not ideal, considering the option of adding support for GTP device creation through ip link. Ip link application is not a good place to create such sockets. This patch allows to create GTP device without providing IFLA_GTP_FD0 and IFLA_GTP_FD1 arguments. If the user sets IFLA_GTP_CREATE_SOCKETS attribute, then GTP module takes care of creating UDP sockets by itself. Sockets are created with the commonly known UDP ports used for GTP protocol (GTP0_PORT and GTP1U_PORT). In this case we don't have to provide encap_destroy because no extra deinitialization is needed, everything is covered by udp_tunnel_sock_release. Note: GTP instance created with only this change applied, does not handle GTP Echo Requests. This is implemented in the following patch. Signed-off-by: Wojciech Drewek <wojciech.drewek@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
This commit is contained in:
		
							parent
							
								
									59d5923536
								
							
						
					
					
						commit
						b20dc3c684
					
				
					 2 changed files with 85 additions and 17 deletions
				
			
		| 
						 | 
				
			
			@ -66,8 +66,10 @@ struct gtp_dev {
 | 
			
		|||
 | 
			
		||||
	struct sock		*sk0;
 | 
			
		||||
	struct sock		*sk1u;
 | 
			
		||||
	u8			sk_created;
 | 
			
		||||
 | 
			
		||||
	struct net_device	*dev;
 | 
			
		||||
	struct net		*net;
 | 
			
		||||
 | 
			
		||||
	unsigned int		role;
 | 
			
		||||
	unsigned int		hash_size;
 | 
			
		||||
| 
						 | 
				
			
			@ -320,9 +322,17 @@ static void gtp_encap_disable_sock(struct sock *sk)
 | 
			
		|||
 | 
			
		||||
static void gtp_encap_disable(struct gtp_dev *gtp)
 | 
			
		||||
{
 | 
			
		||||
	if (gtp->sk_created) {
 | 
			
		||||
		udp_tunnel_sock_release(gtp->sk0->sk_socket);
 | 
			
		||||
		udp_tunnel_sock_release(gtp->sk1u->sk_socket);
 | 
			
		||||
		gtp->sk_created = false;
 | 
			
		||||
		gtp->sk0 = NULL;
 | 
			
		||||
		gtp->sk1u = NULL;
 | 
			
		||||
	} else {
 | 
			
		||||
		gtp_encap_disable_sock(gtp->sk0);
 | 
			
		||||
		gtp_encap_disable_sock(gtp->sk1u);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* UDP encapsulation receive handler. See net/ipv4/udp.c.
 | 
			
		||||
 * Return codes: 0: success, <0: error, >0: pass up to userspace UDP socket.
 | 
			
		||||
| 
						 | 
				
			
			@ -656,17 +666,69 @@ static void gtp_destructor(struct net_device *dev)
 | 
			
		|||
	kfree(gtp->tid_hash);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct sock *gtp_create_sock(int type, struct gtp_dev *gtp)
 | 
			
		||||
{
 | 
			
		||||
	struct udp_tunnel_sock_cfg tuncfg = {};
 | 
			
		||||
	struct udp_port_cfg udp_conf = {
 | 
			
		||||
		.local_ip.s_addr	= htonl(INADDR_ANY),
 | 
			
		||||
		.family			= AF_INET,
 | 
			
		||||
	};
 | 
			
		||||
	struct net *net = gtp->net;
 | 
			
		||||
	struct socket *sock;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (type == UDP_ENCAP_GTP0)
 | 
			
		||||
		udp_conf.local_udp_port = htons(GTP0_PORT);
 | 
			
		||||
	else if (type == UDP_ENCAP_GTP1U)
 | 
			
		||||
		udp_conf.local_udp_port = htons(GTP1U_PORT);
 | 
			
		||||
	else
 | 
			
		||||
		return ERR_PTR(-EINVAL);
 | 
			
		||||
 | 
			
		||||
	err = udp_sock_create(net, &udp_conf, &sock);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return ERR_PTR(err);
 | 
			
		||||
 | 
			
		||||
	tuncfg.sk_user_data = gtp;
 | 
			
		||||
	tuncfg.encap_type = type;
 | 
			
		||||
	tuncfg.encap_rcv = gtp_encap_recv;
 | 
			
		||||
	tuncfg.encap_destroy = NULL;
 | 
			
		||||
 | 
			
		||||
	setup_udp_tunnel_sock(net, sock, &tuncfg);
 | 
			
		||||
 | 
			
		||||
	return sock->sk;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gtp_create_sockets(struct gtp_dev *gtp, struct nlattr *data[])
 | 
			
		||||
{
 | 
			
		||||
	struct sock *sk1u = NULL;
 | 
			
		||||
	struct sock *sk0 = NULL;
 | 
			
		||||
 | 
			
		||||
	sk0 = gtp_create_sock(UDP_ENCAP_GTP0, gtp);
 | 
			
		||||
	if (IS_ERR(sk0))
 | 
			
		||||
		return PTR_ERR(sk0);
 | 
			
		||||
 | 
			
		||||
	sk1u = gtp_create_sock(UDP_ENCAP_GTP1U, gtp);
 | 
			
		||||
	if (IS_ERR(sk1u)) {
 | 
			
		||||
		udp_tunnel_sock_release(sk0->sk_socket);
 | 
			
		||||
		return PTR_ERR(sk1u);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gtp->sk_created = true;
 | 
			
		||||
	gtp->sk0 = sk0;
 | 
			
		||||
	gtp->sk1u = sk1u;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gtp_newlink(struct net *src_net, struct net_device *dev,
 | 
			
		||||
		       struct nlattr *tb[], struct nlattr *data[],
 | 
			
		||||
		       struct netlink_ext_ack *extack)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int role = GTP_ROLE_GGSN;
 | 
			
		||||
	struct gtp_dev *gtp;
 | 
			
		||||
	struct gtp_net *gn;
 | 
			
		||||
	int hashsize, err;
 | 
			
		||||
 | 
			
		||||
	if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1])
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	gtp = netdev_priv(dev);
 | 
			
		||||
 | 
			
		||||
	if (!data[IFLA_GTP_PDP_HASHSIZE]) {
 | 
			
		||||
| 
						 | 
				
			
			@ -677,10 +739,22 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev,
 | 
			
		|||
			hashsize = 1024;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (data[IFLA_GTP_ROLE]) {
 | 
			
		||||
		role = nla_get_u32(data[IFLA_GTP_ROLE]);
 | 
			
		||||
		if (role > GTP_ROLE_SGSN)
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
	gtp->role = role;
 | 
			
		||||
 | 
			
		||||
	gtp->net = src_net;
 | 
			
		||||
 | 
			
		||||
	err = gtp_hashtable_new(gtp, hashsize);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	if (data[IFLA_GTP_CREATE_SOCKETS])
 | 
			
		||||
		err = gtp_create_sockets(gtp, data);
 | 
			
		||||
	else
 | 
			
		||||
		err = gtp_encap_enable(gtp, data);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		goto out_hashtable;
 | 
			
		||||
| 
						 | 
				
			
			@ -726,6 +800,7 @@ static const struct nla_policy gtp_policy[IFLA_GTP_MAX + 1] = {
 | 
			
		|||
	[IFLA_GTP_FD1]			= { .type = NLA_U32 },
 | 
			
		||||
	[IFLA_GTP_PDP_HASHSIZE]		= { .type = NLA_U32 },
 | 
			
		||||
	[IFLA_GTP_ROLE]			= { .type = NLA_U32 },
 | 
			
		||||
	[IFLA_GTP_CREATE_SOCKETS]	= { .type = NLA_U8 },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int gtp_validate(struct nlattr *tb[], struct nlattr *data[],
 | 
			
		||||
| 
						 | 
				
			
			@ -848,7 +923,9 @@ static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[])
 | 
			
		|||
{
 | 
			
		||||
	struct sock *sk1u = NULL;
 | 
			
		||||
	struct sock *sk0 = NULL;
 | 
			
		||||
	unsigned int role = GTP_ROLE_GGSN;
 | 
			
		||||
 | 
			
		||||
	if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1])
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (data[IFLA_GTP_FD0]) {
 | 
			
		||||
		u32 fd0 = nla_get_u32(data[IFLA_GTP_FD0]);
 | 
			
		||||
| 
						 | 
				
			
			@ -868,18 +945,8 @@ static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[])
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (data[IFLA_GTP_ROLE]) {
 | 
			
		||||
		role = nla_get_u32(data[IFLA_GTP_ROLE]);
 | 
			
		||||
		if (role > GTP_ROLE_SGSN) {
 | 
			
		||||
			gtp_encap_disable_sock(sk0);
 | 
			
		||||
			gtp_encap_disable_sock(sk1u);
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gtp->sk0 = sk0;
 | 
			
		||||
	gtp->sk1u = sk1u;
 | 
			
		||||
	gtp->role = role;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -887,6 +887,7 @@ enum {
 | 
			
		|||
	IFLA_GTP_FD1,
 | 
			
		||||
	IFLA_GTP_PDP_HASHSIZE,
 | 
			
		||||
	IFLA_GTP_ROLE,
 | 
			
		||||
	IFLA_GTP_CREATE_SOCKETS,
 | 
			
		||||
	__IFLA_GTP_MAX,
 | 
			
		||||
};
 | 
			
		||||
#define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue