IPv6: Add 'autoconf' and 'disable_ipv6' module parameters
Add 'autoconf' and 'disable_ipv6' parameters to the IPv6 module. The first controls if IPv6 addresses are autoconfigured from prefixes received in Router Advertisements. The IPv6 loopback (::1) and link-local addresses are still configured. The second controls if IPv6 addresses are desired at all. No IPv6 addresses will be added to any interfaces. Signed-off-by: Brian Haley <brian.haley@hp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
					parent
					
						
							
								0220ff7fc3
							
						
					
				
			
			
				commit
				
					
						56d417b12e
					
				
			
		
					 5 changed files with 145 additions and 10 deletions
				
			
		| 
						 | 
					@ -1057,6 +1057,13 @@ disable_ipv6 - BOOLEAN
 | 
				
			||||||
	address.
 | 
						address.
 | 
				
			||||||
	Default: FALSE (enable IPv6 operation)
 | 
						Default: FALSE (enable IPv6 operation)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						When this value is changed from 1 to 0 (IPv6 is being enabled),
 | 
				
			||||||
 | 
						it will dynamically create a link-local address on the given
 | 
				
			||||||
 | 
						interface and start Duplicate Address Detection, if necessary.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						When this value is changed from 0 to 1 (IPv6 is being disabled),
 | 
				
			||||||
 | 
						it will dynamically delete all address on the given interface.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
accept_dad - INTEGER
 | 
					accept_dad - INTEGER
 | 
				
			||||||
	Whether to accept DAD (Duplicate Address Detection).
 | 
						Whether to accept DAD (Duplicate Address Detection).
 | 
				
			||||||
	0: Disable DAD
 | 
						0: Disable DAD
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,3 +33,40 @@ disable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		A reboot is required to enable IPv6.
 | 
							A reboot is required to enable IPv6.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					autoconf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Specifies whether to enable IPv6 address autoconfiguration
 | 
				
			||||||
 | 
						on all interfaces.  This might be used when one does not wish
 | 
				
			||||||
 | 
						for addresses to be automatically generated from prefixes
 | 
				
			||||||
 | 
						received in Router Advertisements.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						The possible values and their effects are:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						0
 | 
				
			||||||
 | 
							IPv6 address autoconfiguration is disabled on all interfaces.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Only the IPv6 loopback address (::1) and link-local addresses
 | 
				
			||||||
 | 
							will be added to interfaces.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						1
 | 
				
			||||||
 | 
							IPv6 address autoconfiguration is enabled on all interfaces.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							This is the default value.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					disable_ipv6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Specifies whether to disable IPv6 on all interfaces.
 | 
				
			||||||
 | 
						This might be used when no IPv6 addresses are desired.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						The possible values and their effects are:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						0
 | 
				
			||||||
 | 
							IPv6 is enabled on all interfaces.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							This is the default value.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						1
 | 
				
			||||||
 | 
							IPv6 is disabled on all interfaces.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							No IPv6 addresses will be added to interfaces.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -169,6 +169,12 @@ struct ipv6_devconf {
 | 
				
			||||||
	__s32		accept_dad;
 | 
						__s32		accept_dad;
 | 
				
			||||||
	void		*sysctl;
 | 
						void		*sysctl;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ipv6_params {
 | 
				
			||||||
 | 
						__s32 disable_ipv6;
 | 
				
			||||||
 | 
						__s32 autoconf;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					extern struct ipv6_params ipv6_defaults;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* index values for the variables in ipv6_devconf */
 | 
					/* index values for the variables in ipv6_devconf */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -591,7 +591,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct inet6_ifaddr *ifa = NULL;
 | 
						struct inet6_ifaddr *ifa = NULL;
 | 
				
			||||||
	struct rt6_info *rt;
 | 
						struct rt6_info *rt;
 | 
				
			||||||
	struct net *net = dev_net(idev->dev);
 | 
					 | 
				
			||||||
	int hash;
 | 
						int hash;
 | 
				
			||||||
	int err = 0;
 | 
						int err = 0;
 | 
				
			||||||
	int addr_type = ipv6_addr_type(addr);
 | 
						int addr_type = ipv6_addr_type(addr);
 | 
				
			||||||
| 
						 | 
					@ -608,7 +607,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
 | 
				
			||||||
		goto out2;
 | 
							goto out2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (idev->cnf.disable_ipv6 || net->ipv6.devconf_all->disable_ipv6) {
 | 
						if (idev->cnf.disable_ipv6) {
 | 
				
			||||||
		err = -EACCES;
 | 
							err = -EACCES;
 | 
				
			||||||
		goto out2;
 | 
							goto out2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1752,6 +1751,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
 | 
				
			||||||
	__u32 prefered_lft;
 | 
						__u32 prefered_lft;
 | 
				
			||||||
	int addr_type;
 | 
						int addr_type;
 | 
				
			||||||
	struct inet6_dev *in6_dev;
 | 
						struct inet6_dev *in6_dev;
 | 
				
			||||||
 | 
						struct net *net = dev_net(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pinfo = (struct prefix_info *) opt;
 | 
						pinfo = (struct prefix_info *) opt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1809,7 +1809,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
 | 
				
			||||||
		if (addrconf_finite_timeout(rt_expires))
 | 
							if (addrconf_finite_timeout(rt_expires))
 | 
				
			||||||
			rt_expires *= HZ;
 | 
								rt_expires *= HZ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL,
 | 
							rt = rt6_lookup(net, &pinfo->prefix, NULL,
 | 
				
			||||||
				dev->ifindex, 1);
 | 
									dev->ifindex, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (rt && addrconf_is_prefix_route(rt)) {
 | 
							if (rt && addrconf_is_prefix_route(rt)) {
 | 
				
			||||||
| 
						 | 
					@ -1846,7 +1846,6 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
 | 
				
			||||||
		struct inet6_ifaddr * ifp;
 | 
							struct inet6_ifaddr * ifp;
 | 
				
			||||||
		struct in6_addr addr;
 | 
							struct in6_addr addr;
 | 
				
			||||||
		int create = 0, update_lft = 0;
 | 
							int create = 0, update_lft = 0;
 | 
				
			||||||
		struct net *net = dev_net(dev);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (pinfo->prefix_len == 64) {
 | 
							if (pinfo->prefix_len == 64) {
 | 
				
			||||||
			memcpy(&addr, &pinfo->prefix, 8);
 | 
								memcpy(&addr, &pinfo->prefix, 8);
 | 
				
			||||||
| 
						 | 
					@ -3988,6 +3987,75 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table,
 | 
				
			||||||
	return addrconf_fixup_forwarding(table, valp, val);
 | 
						return addrconf_fixup_forwarding(table, valp, val);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void dev_disable_change(struct inet6_dev *idev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!idev || !idev->dev)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (idev->cnf.disable_ipv6)
 | 
				
			||||||
 | 
							addrconf_notify(NULL, NETDEV_DOWN, idev->dev);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							addrconf_notify(NULL, NETDEV_UP, idev->dev);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void addrconf_disable_change(struct net *net, __s32 newf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct net_device *dev;
 | 
				
			||||||
 | 
						struct inet6_dev *idev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						read_lock(&dev_base_lock);
 | 
				
			||||||
 | 
						for_each_netdev(net, dev) {
 | 
				
			||||||
 | 
							rcu_read_lock();
 | 
				
			||||||
 | 
							idev = __in6_dev_get(dev);
 | 
				
			||||||
 | 
							if (idev) {
 | 
				
			||||||
 | 
								int changed = (!idev->cnf.disable_ipv6) ^ (!newf);
 | 
				
			||||||
 | 
								idev->cnf.disable_ipv6 = newf;
 | 
				
			||||||
 | 
								if (changed)
 | 
				
			||||||
 | 
									dev_disable_change(idev);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							rcu_read_unlock();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						read_unlock(&dev_base_lock);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct net *net;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						net = (struct net *)table->extra2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p == &net->ipv6.devconf_dflt->disable_ipv6)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!rtnl_trylock())
 | 
				
			||||||
 | 
							return restart_syscall();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p == &net->ipv6.devconf_all->disable_ipv6) {
 | 
				
			||||||
 | 
							__s32 newf = net->ipv6.devconf_all->disable_ipv6;
 | 
				
			||||||
 | 
							net->ipv6.devconf_dflt->disable_ipv6 = newf;
 | 
				
			||||||
 | 
							addrconf_disable_change(net, newf);
 | 
				
			||||||
 | 
						} else if ((!*p) ^ (!old))
 | 
				
			||||||
 | 
							dev_disable_change((struct inet6_dev *)table->extra1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtnl_unlock();
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static
 | 
				
			||||||
 | 
					int addrconf_sysctl_disable(ctl_table *ctl, int write, struct file * filp,
 | 
				
			||||||
 | 
								    void __user *buffer, size_t *lenp, loff_t *ppos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int *valp = ctl->data;
 | 
				
			||||||
 | 
						int val = *valp;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (write)
 | 
				
			||||||
 | 
							ret = addrconf_disable_ipv6(ctl, valp, val);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct addrconf_sysctl_table
 | 
					static struct addrconf_sysctl_table
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ctl_table_header *sysctl_header;
 | 
						struct ctl_table_header *sysctl_header;
 | 
				
			||||||
| 
						 | 
					@ -4225,7 +4293,8 @@ static struct addrconf_sysctl_table
 | 
				
			||||||
			.data		=	&ipv6_devconf.disable_ipv6,
 | 
								.data		=	&ipv6_devconf.disable_ipv6,
 | 
				
			||||||
			.maxlen		=	sizeof(int),
 | 
								.maxlen		=	sizeof(int),
 | 
				
			||||||
			.mode		=	0644,
 | 
								.mode		=	0644,
 | 
				
			||||||
			.proc_handler	=	proc_dointvec,
 | 
								.proc_handler	=	addrconf_sysctl_disable,
 | 
				
			||||||
 | 
								.strategy	=	sysctl_intvec,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			.ctl_name	=	CTL_UNNUMBERED,
 | 
								.ctl_name	=	CTL_UNNUMBERED,
 | 
				
			||||||
| 
						 | 
					@ -4346,6 +4415,10 @@ static int addrconf_init_net(struct net *net)
 | 
				
			||||||
		dflt = kmemdup(dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL);
 | 
							dflt = kmemdup(dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL);
 | 
				
			||||||
		if (dflt == NULL)
 | 
							if (dflt == NULL)
 | 
				
			||||||
			goto err_alloc_dflt;
 | 
								goto err_alloc_dflt;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* these will be inherited by all namespaces */
 | 
				
			||||||
 | 
							dflt->autoconf = ipv6_defaults.autoconf;
 | 
				
			||||||
 | 
							dflt->disable_ipv6 = ipv6_defaults.disable_ipv6;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	net->ipv6.devconf_all = all;
 | 
						net->ipv6.devconf_all = all;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,9 +72,21 @@ MODULE_LICENSE("GPL");
 | 
				
			||||||
static struct list_head inetsw6[SOCK_MAX];
 | 
					static struct list_head inetsw6[SOCK_MAX];
 | 
				
			||||||
static DEFINE_SPINLOCK(inetsw6_lock);
 | 
					static DEFINE_SPINLOCK(inetsw6_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int disable_ipv6 = 0;
 | 
					struct ipv6_params ipv6_defaults = {
 | 
				
			||||||
module_param_named(disable, disable_ipv6, int, 0);
 | 
						.disable_ipv6 = 0,
 | 
				
			||||||
MODULE_PARM_DESC(disable, "Disable IPv6 such that it is non-functional");
 | 
						.autoconf = 1,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int disable_ipv6_mod = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module_param_named(disable, disable_ipv6_mod, int, 0444);
 | 
				
			||||||
 | 
					MODULE_PARM_DESC(disable, "Disable IPv6 module such that it is non-functional");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module_param_named(disable_ipv6, ipv6_defaults.disable_ipv6, int, 0444);
 | 
				
			||||||
 | 
					MODULE_PARM_DESC(disable_ipv6, "Disable IPv6 on all interfaces");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module_param_named(autoconf, ipv6_defaults.autoconf, int, 0444);
 | 
				
			||||||
 | 
					MODULE_PARM_DESC(autoconf, "Enable IPv6 address autoconfiguration on all interfaces");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk)
 | 
					static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -1038,7 +1050,7 @@ static int __init inet6_init(void)
 | 
				
			||||||
	for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r)
 | 
						for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r)
 | 
				
			||||||
		INIT_LIST_HEAD(r);
 | 
							INIT_LIST_HEAD(r);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (disable_ipv6) {
 | 
						if (disable_ipv6_mod) {
 | 
				
			||||||
		printk(KERN_INFO
 | 
							printk(KERN_INFO
 | 
				
			||||||
		       "IPv6: Loaded, but administratively disabled, "
 | 
							       "IPv6: Loaded, but administratively disabled, "
 | 
				
			||||||
		       "reboot required to enable\n");
 | 
							       "reboot required to enable\n");
 | 
				
			||||||
| 
						 | 
					@ -1227,7 +1239,7 @@ module_init(inet6_init);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __exit inet6_exit(void)
 | 
					static void __exit inet6_exit(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (disable_ipv6)
 | 
						if (disable_ipv6_mod)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* First of all disallow new sockets creation. */
 | 
						/* First of all disallow new sockets creation. */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue