aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Ahern <dsahern@gmail.com>2017-10-18 12:56:53 -0400
committerDavid S. Miller <davem@davemloft.net>2017-10-20 08:15:07 -0400
commitff7883ea60e7b021bcd6539b8211879554c8db9a (patch)
tree211fefe3e230730f2023492e44017c60e2c5f54e
parentf3d9832e56c48e4ca50bab0457e21bcaade4536d (diff)
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>
-rw-r--r--drivers/net/ipvlan/ipvlan_main.c4
-rw-r--r--net/ipv6/addrconf.c21
-rw-r--r--net/ipv6/addrconf_core.c9
3 files changed, 19 insertions, 15 deletions
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index 3cf67db513e2..6842739b6679 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -808,10 +808,6 @@ static int ipvlan_addr6_event(struct notifier_block *unused,
808 struct net_device *dev = (struct net_device *)if6->idev->dev; 808 struct net_device *dev = (struct net_device *)if6->idev->dev;
809 struct ipvl_dev *ipvlan = netdev_priv(dev); 809 struct ipvl_dev *ipvlan = netdev_priv(dev);
810 810
811 /* FIXME IPv6 autoconf calls us from bh without RTNL */
812 if (in_softirq())
813 return NOTIFY_DONE;
814
815 if (!netif_is_ipvlan(dev)) 811 if (!netif_is_ipvlan(dev))
816 return NOTIFY_DONE; 812 return NOTIFY_DONE;
817 813
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,
993 struct net *net = dev_net(idev->dev); 993 struct net *net = dev_net(idev->dev);
994 struct inet6_ifaddr *ifa = NULL; 994 struct inet6_ifaddr *ifa = NULL;
995 struct rt6_info *rt = NULL; 995 struct rt6_info *rt = NULL;
996 struct in6_validator_info i6vi;
997 int err = 0; 996 int err = 0;
998 int addr_type = ipv6_addr_type(addr); 997 int addr_type = ipv6_addr_type(addr);
999 998
@@ -1013,12 +1012,20 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
1013 goto out; 1012 goto out;
1014 } 1013 }
1015 1014
1016 i6vi.i6vi_addr = *addr; 1015 /* validator notifier needs to be blocking;
1017 i6vi.i6vi_dev = idev; 1016 * do not call in atomic context
1018 err = inet6addr_validator_notifier_call_chain(NETDEV_UP, &i6vi); 1017 */
1019 err = notifier_to_errno(err); 1018 if (can_block) {
1020 if (err < 0) 1019 struct in6_validator_info i6vi = {
1021 goto out; 1020 .i6vi_addr = *addr,
1021 .i6vi_dev = idev,
1022 };
1023
1024 err = inet6addr_validator_notifier_call_chain(NETDEV_UP, &i6vi);
1025 err = notifier_to_errno(err);
1026 if (err < 0)
1027 goto out;
1028 }
1022 1029
1023 ifa = kzalloc(sizeof(*ifa), gfp_flags); 1030 ifa = kzalloc(sizeof(*ifa), gfp_flags);
1024 if (!ifa) { 1031 if (!ifa) {
diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c
index 9e3488d50b15..32b564dfd02a 100644
--- a/net/ipv6/addrconf_core.c
+++ b/net/ipv6/addrconf_core.c
@@ -88,7 +88,7 @@ int __ipv6_addr_type(const struct in6_addr *addr)
88EXPORT_SYMBOL(__ipv6_addr_type); 88EXPORT_SYMBOL(__ipv6_addr_type);
89 89
90static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); 90static ATOMIC_NOTIFIER_HEAD(inet6addr_chain);
91static ATOMIC_NOTIFIER_HEAD(inet6addr_validator_chain); 91static BLOCKING_NOTIFIER_HEAD(inet6addr_validator_chain);
92 92
93int register_inet6addr_notifier(struct notifier_block *nb) 93int register_inet6addr_notifier(struct notifier_block *nb)
94{ 94{
@@ -110,19 +110,20 @@ EXPORT_SYMBOL(inet6addr_notifier_call_chain);
110 110
111int register_inet6addr_validator_notifier(struct notifier_block *nb) 111int register_inet6addr_validator_notifier(struct notifier_block *nb)
112{ 112{
113 return atomic_notifier_chain_register(&inet6addr_validator_chain, nb); 113 return blocking_notifier_chain_register(&inet6addr_validator_chain, nb);
114} 114}
115EXPORT_SYMBOL(register_inet6addr_validator_notifier); 115EXPORT_SYMBOL(register_inet6addr_validator_notifier);
116 116
117int unregister_inet6addr_validator_notifier(struct notifier_block *nb) 117int unregister_inet6addr_validator_notifier(struct notifier_block *nb)
118{ 118{
119 return atomic_notifier_chain_unregister(&inet6addr_validator_chain, nb); 119 return blocking_notifier_chain_unregister(&inet6addr_validator_chain,
120 nb);
120} 121}
121EXPORT_SYMBOL(unregister_inet6addr_validator_notifier); 122EXPORT_SYMBOL(unregister_inet6addr_validator_notifier);
122 123
123int inet6addr_validator_notifier_call_chain(unsigned long val, void *v) 124int inet6addr_validator_notifier_call_chain(unsigned long val, void *v)
124{ 125{
125 return atomic_notifier_call_chain(&inet6addr_validator_chain, val, v); 126 return blocking_notifier_call_chain(&inet6addr_validator_chain, val, v);
126} 127}
127EXPORT_SYMBOL(inet6addr_validator_notifier_call_chain); 128EXPORT_SYMBOL(inet6addr_validator_notifier_call_chain);
128 129