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:
David Forster 2017-02-23 16:27:18 +00:00 committed by David S. Miller
parent 88da73a3a5
commit df789fe752
3 changed files with 116 additions and 0 deletions

View File

@ -70,6 +70,7 @@ struct ipv6_devconf {
#endif
__u32 enhanced_dad;
__u32 addr_gen_mode;
__s32 disable_policy;
struct ctl_table_header *sysctl_header;
};

View File

@ -183,6 +183,7 @@ enum {
DEVCONF_SEG6_REQUIRE_HMAC,
DEVCONF_ENHANCED_DAD,
DEVCONF_ADDR_GEN_MODE,
DEVCONF_DISABLE_POLICY,
DEVCONF_MAX
};

View File

@ -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 */
}