summaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
authorDavid Ahern2017-10-18 18:56:53 +0200
committerDavid S. Miller2017-10-20 14:15:07 +0200
commitff7883ea60e7b021bcd6539b8211879554c8db9a (patch)
tree211fefe3e230730f2023492e44017c60e2c5f54e /net/ipv6/addrconf.c
parentipv6: addrconf: cleanup locking in ipv6_add_addr (diff)
downloadkernel-qcow2-linux-ff7883ea60e7b021bcd6539b8211879554c8db9a.tar.gz
kernel-qcow2-linux-ff7883ea60e7b021bcd6539b8211879554c8db9a.tar.xz
kernel-qcow2-linux-ff7883ea60e7b021bcd6539b8211879554c8db9a.zip
net: ipv6: Make inet6addr_validator a blocking notifier
inet6addr_validator chain was added by commit 3ad7d2468f79f ("Ipvlan should return an error when an address is already in use") to allow address validation before changes are committed and to be able to fail the address change with an error back to the user. The address validation is not done for addresses received from router advertisements. Handling RAs in softirq context is the only reason for the notifier chain to be atomic versus blocking. Since the only current user, ipvlan, of the validator chain ignores softirq context, the notifier can be made blocking and simply not invoked for softirq path. The blocking option is needed by spectrum for example to validate resources for an adding an address to an interface. Signed-off-by: David Ahern <dsahern@gmail.com> Reviewed-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index a8d202b1b919..dd9c0c435f71 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -993,7 +993,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
struct net *net = dev_net(idev->dev);
struct inet6_ifaddr *ifa = NULL;
struct rt6_info *rt = NULL;
- struct in6_validator_info i6vi;
int err = 0;
int addr_type = ipv6_addr_type(addr);
@@ -1013,12 +1012,20 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
goto out;
}
- i6vi.i6vi_addr = *addr;
- i6vi.i6vi_dev = idev;
- err = inet6addr_validator_notifier_call_chain(NETDEV_UP, &i6vi);
- err = notifier_to_errno(err);
- if (err < 0)
- goto out;
+ /* validator notifier needs to be blocking;
+ * do not call in atomic context
+ */
+ if (can_block) {
+ struct in6_validator_info i6vi = {
+ .i6vi_addr = *addr,
+ .i6vi_dev = idev,
+ };
+
+ err = inet6addr_validator_notifier_call_chain(NETDEV_UP, &i6vi);
+ err = notifier_to_errno(err);
+ if (err < 0)
+ goto out;
+ }
ifa = kzalloc(sizeof(*ifa), gfp_flags);
if (!ifa) {