|
@@ -137,22 +137,12 @@ static void inet_hash_remove(struct in_ifaddr *ifa)
|
|
|
*/
|
|
|
struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
|
|
|
{
|
|
|
- u32 hash = inet_addr_hash(net, addr);
|
|
|
struct net_device *result = NULL;
|
|
|
struct in_ifaddr *ifa;
|
|
|
|
|
|
rcu_read_lock();
|
|
|
- hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash) {
|
|
|
- if (ifa->ifa_local == addr) {
|
|
|
- struct net_device *dev = ifa->ifa_dev->dev;
|
|
|
-
|
|
|
- if (!net_eq(dev_net(dev), net))
|
|
|
- continue;
|
|
|
- result = dev;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- if (!result) {
|
|
|
+ ifa = inet_lookup_ifaddr_rcu(net, addr);
|
|
|
+ if (!ifa) {
|
|
|
struct flowi4 fl4 = { .daddr = addr };
|
|
|
struct fib_result res = { 0 };
|
|
|
struct fib_table *local;
|
|
@@ -165,6 +155,8 @@ struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
|
|
|
!fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
|
|
|
res.type == RTN_LOCAL)
|
|
|
result = FIB_RES_DEV(res);
|
|
|
+ } else {
|
|
|
+ result = ifa->ifa_dev->dev;
|
|
|
}
|
|
|
if (result && devref)
|
|
|
dev_hold(result);
|
|
@@ -173,6 +165,20 @@ struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
|
|
|
}
|
|
|
EXPORT_SYMBOL(__ip_dev_find);
|
|
|
|
|
|
+/* called under RCU lock */
|
|
|
+struct in_ifaddr *inet_lookup_ifaddr_rcu(struct net *net, __be32 addr)
|
|
|
+{
|
|
|
+ u32 hash = inet_addr_hash(net, addr);
|
|
|
+ struct in_ifaddr *ifa;
|
|
|
+
|
|
|
+ hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash)
|
|
|
+ if (ifa->ifa_local == addr &&
|
|
|
+ net_eq(dev_net(ifa->ifa_dev->dev), net))
|
|
|
+ return ifa;
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
|
|
|
|
|
|
static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
|