On 10/10/17 10:41 AM, David Ahern wrote: > @@ -988,16 +987,23 @@ ipv6_add_addr(struct inet6_dev *idev, const struct > in6_addr *addr, > goto out2; > } > > - i6vi.i6vi_addr = *addr; > - i6vi.i6vi_dev = idev; > - rcu_read_unlock_bh(); > + /* validator notifier needs to be blocking; > + * do not call in softirq context > + */ > + if (!in_softirq()) { > + struct in6_validator_info i6vi = { > + .i6vi_addr = *addr, > + .i6vi_dev = idev, > + }; > > - err = inet6addr_validator_notifier_call_chain(NETDEV_UP, &i6vi); > + rcu_read_unlock_bh(); > + err = inet6addr_validator_notifier_call_chain(NETDEV_UP, &i6vi); > + rcu_read_lock_bh(); > > - rcu_read_lock_bh(); > - err = notifier_to_errno(err); > - if (err) > - goto out2; > + err = notifier_to_errno(err); > + if (err) > + goto out2; > + } > > spin_lock(&addrconf_hash_lock); >
The rcu_read_unlock_bh needs to be done before the in_softirq check. With the change below I get the RIF overload with IPv6 addresses and I verified the validator is skipped for RAs. $ ip -batch vlan-ipv6-addr-batch Error: spectrum: Exceeded number of supported router interfaces. Command failed vlan-ipv6-addr-batch:683 diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 0bad4a800f73..d9c5b29a3b8b 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -988,6 +988,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, goto out2; } + rcu_read_unlock_bh(); + /* validator notifier needs to be blocking; * do not call in softirq context */ @@ -998,15 +1000,14 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, .extack = extack, }; - rcu_read_unlock_bh(); err = inet6addr_validator_notifier_call_chain(NETDEV_UP, &i6vi); - rcu_read_lock_bh(); - err = notifier_to_errno(err); if (err) - goto out2; + goto out1; } + rcu_read_lock_bh(); + spin_lock(&addrconf_hash_lock); /* Ignore adding duplicate addresses on an interface */ @@ -1079,7 +1080,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, write_unlock(&idev->lock); out2: rcu_read_unlock_bh(); - +out1: if (likely(err == 0)) inet6addr_notifier_call_chain(NETDEV_UP, ifa); else {