forked from mirrors/linux
		
	sit: allow to configure 6rd tunnels via netlink
This patch add the support of 6RD tunnels management via netlink. Note that netdev_state_change() is now called when 6RD parameters are updated. 6RD parameters are updated only if there is at least one 6RD attribute. Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									e4f67addf1
								
							
						
					
					
						commit
						e2f1f072db
					
				
					 2 changed files with 128 additions and 25 deletions
				
			
		| 
						 | 
				
			
			@ -49,6 +49,10 @@ enum {
 | 
			
		|||
	IFLA_IPTUN_FLAGS,
 | 
			
		||||
	IFLA_IPTUN_PROTO,
 | 
			
		||||
	IFLA_IPTUN_PMTUDISC,
 | 
			
		||||
	IFLA_IPTUN_6RD_PREFIX,
 | 
			
		||||
	IFLA_IPTUN_6RD_RELAY_PREFIX,
 | 
			
		||||
	IFLA_IPTUN_6RD_PREFIXLEN,
 | 
			
		||||
	IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
 | 
			
		||||
	__IFLA_IPTUN_MAX,
 | 
			
		||||
};
 | 
			
		||||
#define IFLA_IPTUN_MAX	(__IFLA_IPTUN_MAX - 1)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										149
									
								
								net/ipv6/sit.c
									
									
									
									
									
								
							
							
						
						
									
										149
									
								
								net/ipv6/sit.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -936,6 +936,38 @@ static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
 | 
			
		|||
	netdev_state_change(t->dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_IPV6_SIT_6RD
 | 
			
		||||
static int ipip6_tunnel_update_6rd(struct ip_tunnel *t,
 | 
			
		||||
				   struct ip_tunnel_6rd *ip6rd)
 | 
			
		||||
{
 | 
			
		||||
	struct in6_addr prefix;
 | 
			
		||||
	__be32 relay_prefix;
 | 
			
		||||
 | 
			
		||||
	if (ip6rd->relay_prefixlen > 32 ||
 | 
			
		||||
	    ip6rd->prefixlen + (32 - ip6rd->relay_prefixlen) > 64)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	ipv6_addr_prefix(&prefix, &ip6rd->prefix, ip6rd->prefixlen);
 | 
			
		||||
	if (!ipv6_addr_equal(&prefix, &ip6rd->prefix))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (ip6rd->relay_prefixlen)
 | 
			
		||||
		relay_prefix = ip6rd->relay_prefix &
 | 
			
		||||
			       htonl(0xffffffffUL <<
 | 
			
		||||
				     (32 - ip6rd->relay_prefixlen));
 | 
			
		||||
	else
 | 
			
		||||
		relay_prefix = 0;
 | 
			
		||||
	if (relay_prefix != ip6rd->relay_prefix)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	t->ip6rd.prefix = prefix;
 | 
			
		||||
	t->ip6rd.relay_prefix = relay_prefix;
 | 
			
		||||
	t->ip6rd.prefixlen = ip6rd->prefixlen;
 | 
			
		||||
	t->ip6rd.relay_prefixlen = ip6rd->relay_prefixlen;
 | 
			
		||||
	netdev_state_change(t->dev);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1105,31 +1137,9 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
 | 
			
		|||
		t = netdev_priv(dev);
 | 
			
		||||
 | 
			
		||||
		if (cmd != SIOCDEL6RD) {
 | 
			
		||||
			struct in6_addr prefix;
 | 
			
		||||
			__be32 relay_prefix;
 | 
			
		||||
 | 
			
		||||
			err = -EINVAL;
 | 
			
		||||
			if (ip6rd.relay_prefixlen > 32 ||
 | 
			
		||||
			    ip6rd.prefixlen + (32 - ip6rd.relay_prefixlen) > 64)
 | 
			
		||||
			err = ipip6_tunnel_update_6rd(t, &ip6rd);
 | 
			
		||||
			if (err < 0)
 | 
			
		||||
				goto done;
 | 
			
		||||
 | 
			
		||||
			ipv6_addr_prefix(&prefix, &ip6rd.prefix,
 | 
			
		||||
					 ip6rd.prefixlen);
 | 
			
		||||
			if (!ipv6_addr_equal(&prefix, &ip6rd.prefix))
 | 
			
		||||
				goto done;
 | 
			
		||||
			if (ip6rd.relay_prefixlen)
 | 
			
		||||
				relay_prefix = ip6rd.relay_prefix &
 | 
			
		||||
					       htonl(0xffffffffUL <<
 | 
			
		||||
						     (32 - ip6rd.relay_prefixlen));
 | 
			
		||||
			else
 | 
			
		||||
				relay_prefix = 0;
 | 
			
		||||
			if (relay_prefix != ip6rd.relay_prefix)
 | 
			
		||||
				goto done;
 | 
			
		||||
 | 
			
		||||
			t->ip6rd.prefix = prefix;
 | 
			
		||||
			t->ip6rd.relay_prefix = relay_prefix;
 | 
			
		||||
			t->ip6rd.prefixlen = ip6rd.prefixlen;
 | 
			
		||||
			t->ip6rd.relay_prefixlen = ip6rd.relay_prefixlen;
 | 
			
		||||
		} else
 | 
			
		||||
			ipip6_tunnel_clone_6rd(dev, sitn);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1261,11 +1271,53 @@ static void ipip6_netlink_parms(struct nlattr *data[],
 | 
			
		|||
		parms->i_flags = nla_get_be16(data[IFLA_IPTUN_FLAGS]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_IPV6_SIT_6RD
 | 
			
		||||
/* This function returns true when 6RD attributes are present in the nl msg */
 | 
			
		||||
static bool ipip6_netlink_6rd_parms(struct nlattr *data[],
 | 
			
		||||
				    struct ip_tunnel_6rd *ip6rd)
 | 
			
		||||
{
 | 
			
		||||
	bool ret = false;
 | 
			
		||||
	memset(ip6rd, 0, sizeof(*ip6rd));
 | 
			
		||||
 | 
			
		||||
	if (!data)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	if (data[IFLA_IPTUN_6RD_PREFIX]) {
 | 
			
		||||
		ret = true;
 | 
			
		||||
		nla_memcpy(&ip6rd->prefix, data[IFLA_IPTUN_6RD_PREFIX],
 | 
			
		||||
			   sizeof(struct in6_addr));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (data[IFLA_IPTUN_6RD_RELAY_PREFIX]) {
 | 
			
		||||
		ret = true;
 | 
			
		||||
		ip6rd->relay_prefix =
 | 
			
		||||
			nla_get_be32(data[IFLA_IPTUN_6RD_RELAY_PREFIX]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (data[IFLA_IPTUN_6RD_PREFIXLEN]) {
 | 
			
		||||
		ret = true;
 | 
			
		||||
		ip6rd->prefixlen = nla_get_u16(data[IFLA_IPTUN_6RD_PREFIXLEN]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) {
 | 
			
		||||
		ret = true;
 | 
			
		||||
		ip6rd->relay_prefixlen =
 | 
			
		||||
			nla_get_u16(data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int ipip6_newlink(struct net *src_net, struct net_device *dev,
 | 
			
		||||
			 struct nlattr *tb[], struct nlattr *data[])
 | 
			
		||||
{
 | 
			
		||||
	struct net *net = dev_net(dev);
 | 
			
		||||
	struct ip_tunnel *nt;
 | 
			
		||||
#ifdef CONFIG_IPV6_SIT_6RD
 | 
			
		||||
	struct ip_tunnel_6rd ip6rd;
 | 
			
		||||
#endif
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	nt = netdev_priv(dev);
 | 
			
		||||
	ipip6_netlink_parms(data, &nt->parms);
 | 
			
		||||
| 
						 | 
				
			
			@ -1273,7 +1325,16 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev,
 | 
			
		|||
	if (ipip6_tunnel_locate(net, &nt->parms, 0))
 | 
			
		||||
		return -EEXIST;
 | 
			
		||||
 | 
			
		||||
	return ipip6_tunnel_create(dev);
 | 
			
		||||
	err = ipip6_tunnel_create(dev);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_IPV6_SIT_6RD
 | 
			
		||||
	if (ipip6_netlink_6rd_parms(data, &ip6rd))
 | 
			
		||||
		err = ipip6_tunnel_update_6rd(nt, &ip6rd);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
 | 
			
		||||
| 
						 | 
				
			
			@ -1283,6 +1344,9 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
 | 
			
		|||
	struct ip_tunnel_parm p;
 | 
			
		||||
	struct net *net = dev_net(dev);
 | 
			
		||||
	struct sit_net *sitn = net_generic(net, sit_net_id);
 | 
			
		||||
#ifdef CONFIG_IPV6_SIT_6RD
 | 
			
		||||
	struct ip_tunnel_6rd ip6rd;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (dev == sitn->fb_tunnel_dev)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
| 
						 | 
				
			
			@ -1302,6 +1366,12 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
 | 
			
		|||
		t = netdev_priv(dev);
 | 
			
		||||
 | 
			
		||||
	ipip6_tunnel_update(t, &p);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_IPV6_SIT_6RD
 | 
			
		||||
	if (ipip6_netlink_6rd_parms(data, &ip6rd))
 | 
			
		||||
		return ipip6_tunnel_update_6rd(t, &ip6rd);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1322,6 +1392,16 @@ static size_t ipip6_get_size(const struct net_device *dev)
 | 
			
		|||
		nla_total_size(1) +
 | 
			
		||||
		/* IFLA_IPTUN_FLAGS */
 | 
			
		||||
		nla_total_size(2) +
 | 
			
		||||
#ifdef CONFIG_IPV6_SIT_6RD
 | 
			
		||||
		/* IFLA_IPTUN_6RD_PREFIX */
 | 
			
		||||
		nla_total_size(sizeof(struct in6_addr)) +
 | 
			
		||||
		/* IFLA_IPTUN_6RD_RELAY_PREFIX */
 | 
			
		||||
		nla_total_size(4) +
 | 
			
		||||
		/* IFLA_IPTUN_6RD_PREFIXLEN */
 | 
			
		||||
		nla_total_size(2) +
 | 
			
		||||
		/* IFLA_IPTUN_6RD_RELAY_PREFIXLEN */
 | 
			
		||||
		nla_total_size(2) +
 | 
			
		||||
#endif
 | 
			
		||||
		0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1339,6 +1419,19 @@ static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev)
 | 
			
		|||
		       !!(parm->iph.frag_off & htons(IP_DF))) ||
 | 
			
		||||
	    nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags))
 | 
			
		||||
		goto nla_put_failure;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_IPV6_SIT_6RD
 | 
			
		||||
	if (nla_put(skb, IFLA_IPTUN_6RD_PREFIX, sizeof(struct in6_addr),
 | 
			
		||||
		    &tunnel->ip6rd.prefix) ||
 | 
			
		||||
	    nla_put_be32(skb, IFLA_IPTUN_6RD_RELAY_PREFIX,
 | 
			
		||||
			 tunnel->ip6rd.relay_prefix) ||
 | 
			
		||||
	    nla_put_u16(skb, IFLA_IPTUN_6RD_PREFIXLEN,
 | 
			
		||||
			tunnel->ip6rd.prefixlen) ||
 | 
			
		||||
	    nla_put_u16(skb, IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
 | 
			
		||||
			tunnel->ip6rd.relay_prefixlen))
 | 
			
		||||
		goto nla_put_failure;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
nla_put_failure:
 | 
			
		||||
| 
						 | 
				
			
			@ -1353,6 +1446,12 @@ static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = {
 | 
			
		|||
	[IFLA_IPTUN_TOS]		= { .type = NLA_U8 },
 | 
			
		||||
	[IFLA_IPTUN_PMTUDISC]		= { .type = NLA_U8 },
 | 
			
		||||
	[IFLA_IPTUN_FLAGS]		= { .type = NLA_U16 },
 | 
			
		||||
#ifdef CONFIG_IPV6_SIT_6RD
 | 
			
		||||
	[IFLA_IPTUN_6RD_PREFIX]		= { .len = sizeof(struct in6_addr) },
 | 
			
		||||
	[IFLA_IPTUN_6RD_RELAY_PREFIX]	= { .type = NLA_U32 },
 | 
			
		||||
	[IFLA_IPTUN_6RD_PREFIXLEN]	= { .type = NLA_U16 },
 | 
			
		||||
	[IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 },
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct rtnl_link_ops sit_link_ops __read_mostly = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue