mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	ipv6: Provide ipv6 version of "disable_policy" sysctl
This provides equivalent functionality to the existing ipv4 "disable_policy" systcl. ie. Allows IPsec processing to be skipped on terminating packets on a per-interface basis. Signed-off-by: David Forster <dforster@brocade.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									88da73a3a5
								
							
						
					
					
						commit
						df789fe752
					
				
					 3 changed files with 116 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -70,6 +70,7 @@ struct ipv6_devconf {
 | 
			
		|||
#endif
 | 
			
		||||
	__u32		enhanced_dad;
 | 
			
		||||
	__u32		addr_gen_mode;
 | 
			
		||||
	__s32		disable_policy;
 | 
			
		||||
 | 
			
		||||
	struct ctl_table_header *sysctl_header;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -183,6 +183,7 @@ enum {
 | 
			
		|||
	DEVCONF_SEG6_REQUIRE_HMAC,
 | 
			
		||||
	DEVCONF_ENHANCED_DAD,
 | 
			
		||||
	DEVCONF_ADDR_GEN_MODE,
 | 
			
		||||
	DEVCONF_DISABLE_POLICY,
 | 
			
		||||
	DEVCONF_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -245,6 +245,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
 | 
			
		|||
#endif
 | 
			
		||||
	.enhanced_dad           = 1,
 | 
			
		||||
	.addr_gen_mode		= IN6_ADDR_GEN_MODE_EUI64,
 | 
			
		||||
	.disable_policy		= 0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
 | 
			
		||||
| 
						 | 
				
			
			@ -297,6 +298,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
 | 
			
		|||
#endif
 | 
			
		||||
	.enhanced_dad           = 1,
 | 
			
		||||
	.addr_gen_mode		= IN6_ADDR_GEN_MODE_EUI64,
 | 
			
		||||
	.disable_policy		= 0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Check if a valid qdisc is available */
 | 
			
		||||
| 
						 | 
				
			
			@ -944,6 +946,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
 | 
			
		|||
	      const struct in6_addr *peer_addr, int pfxlen,
 | 
			
		||||
	      int scope, u32 flags, u32 valid_lft, u32 prefered_lft)
 | 
			
		||||
{
 | 
			
		||||
	struct net *net = dev_net(idev->dev);
 | 
			
		||||
	struct inet6_ifaddr *ifa = NULL;
 | 
			
		||||
	struct rt6_info *rt;
 | 
			
		||||
	unsigned int hash;
 | 
			
		||||
| 
						 | 
				
			
			@ -990,6 +993,10 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
 | 
			
		|||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (net->ipv6.devconf_all->disable_policy ||
 | 
			
		||||
	    idev->cnf.disable_policy)
 | 
			
		||||
		rt->dst.flags |= DST_NOPOLICY;
 | 
			
		||||
 | 
			
		||||
	neigh_parms_data_state_setall(idev->nd_parms);
 | 
			
		||||
 | 
			
		||||
	ifa->addr = *addr;
 | 
			
		||||
| 
						 | 
				
			
			@ -5003,6 +5010,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
 | 
			
		|||
#endif
 | 
			
		||||
	array[DEVCONF_ENHANCED_DAD] = cnf->enhanced_dad;
 | 
			
		||||
	array[DEVCONF_ADDR_GEN_MODE] = cnf->addr_gen_mode;
 | 
			
		||||
	array[DEVCONF_DISABLE_POLICY] = cnf->disable_policy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline size_t inet6_ifla6_size(void)
 | 
			
		||||
| 
						 | 
				
			
			@ -5827,6 +5835,105 @@ int addrconf_sysctl_ignore_routes_with_linkdown(struct ctl_table *ctl,
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void addrconf_set_nopolicy(struct rt6_info *rt, int action)
 | 
			
		||||
{
 | 
			
		||||
	if (rt) {
 | 
			
		||||
		if (action)
 | 
			
		||||
			rt->dst.flags |= DST_NOPOLICY;
 | 
			
		||||
		else
 | 
			
		||||
			rt->dst.flags &= ~DST_NOPOLICY;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void addrconf_disable_policy_idev(struct inet6_dev *idev, int val)
 | 
			
		||||
{
 | 
			
		||||
	struct inet6_ifaddr *ifa;
 | 
			
		||||
 | 
			
		||||
	read_lock_bh(&idev->lock);
 | 
			
		||||
	list_for_each_entry(ifa, &idev->addr_list, if_list) {
 | 
			
		||||
		spin_lock(&ifa->lock);
 | 
			
		||||
		if (ifa->rt) {
 | 
			
		||||
			struct rt6_info *rt = ifa->rt;
 | 
			
		||||
			struct fib6_table *table = rt->rt6i_table;
 | 
			
		||||
			int cpu;
 | 
			
		||||
 | 
			
		||||
			read_lock(&table->tb6_lock);
 | 
			
		||||
			addrconf_set_nopolicy(ifa->rt, val);
 | 
			
		||||
			if (rt->rt6i_pcpu) {
 | 
			
		||||
				for_each_possible_cpu(cpu) {
 | 
			
		||||
					struct rt6_info **rtp;
 | 
			
		||||
 | 
			
		||||
					rtp = per_cpu_ptr(rt->rt6i_pcpu, cpu);
 | 
			
		||||
					addrconf_set_nopolicy(*rtp, val);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			read_unlock(&table->tb6_lock);
 | 
			
		||||
		}
 | 
			
		||||
		spin_unlock(&ifa->lock);
 | 
			
		||||
	}
 | 
			
		||||
	read_unlock_bh(&idev->lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
int addrconf_disable_policy(struct ctl_table *ctl, int *valp, int val)
 | 
			
		||||
{
 | 
			
		||||
	struct inet6_dev *idev;
 | 
			
		||||
	struct net *net;
 | 
			
		||||
 | 
			
		||||
	if (!rtnl_trylock())
 | 
			
		||||
		return restart_syscall();
 | 
			
		||||
 | 
			
		||||
	*valp = val;
 | 
			
		||||
 | 
			
		||||
	net = (struct net *)ctl->extra2;
 | 
			
		||||
	if (valp == &net->ipv6.devconf_dflt->disable_policy) {
 | 
			
		||||
		rtnl_unlock();
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (valp == &net->ipv6.devconf_all->disable_policy)  {
 | 
			
		||||
		struct net_device *dev;
 | 
			
		||||
 | 
			
		||||
		for_each_netdev(net, dev) {
 | 
			
		||||
			idev = __in6_dev_get(dev);
 | 
			
		||||
			if (idev)
 | 
			
		||||
				addrconf_disable_policy_idev(idev, val);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		idev = (struct inet6_dev *)ctl->extra1;
 | 
			
		||||
		addrconf_disable_policy_idev(idev, val);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rtnl_unlock();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
int addrconf_sysctl_disable_policy(struct ctl_table *ctl, int write,
 | 
			
		||||
				   void __user *buffer, size_t *lenp,
 | 
			
		||||
				   loff_t *ppos)
 | 
			
		||||
{
 | 
			
		||||
	int *valp = ctl->data;
 | 
			
		||||
	int val = *valp;
 | 
			
		||||
	loff_t pos = *ppos;
 | 
			
		||||
	struct ctl_table lctl;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	lctl = *ctl;
 | 
			
		||||
	lctl.data = &val;
 | 
			
		||||
	ret = proc_dointvec(&lctl, write, buffer, lenp, ppos);
 | 
			
		||||
 | 
			
		||||
	if (write && (*valp != val))
 | 
			
		||||
		ret = addrconf_disable_policy(ctl, valp, val);
 | 
			
		||||
 | 
			
		||||
	if (ret)
 | 
			
		||||
		*ppos = pos;
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int minus_one = -1;
 | 
			
		||||
static const int one = 1;
 | 
			
		||||
static const int two_five_five = 255;
 | 
			
		||||
| 
						 | 
				
			
			@ -6184,6 +6291,13 @@ static const struct ctl_table addrconf_sysctl[] = {
 | 
			
		|||
		.mode			= 0644,
 | 
			
		||||
		.proc_handler	= addrconf_sysctl_addr_gen_mode,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.procname       = "disable_policy",
 | 
			
		||||
		.data           = &ipv6_devconf.disable_policy,
 | 
			
		||||
		.maxlen         = sizeof(int),
 | 
			
		||||
		.mode           = 0644,
 | 
			
		||||
		.proc_handler   = addrconf_sysctl_disable_policy,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		/* sentinel */
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue