ipv4: Implement __ip_dev_find using new interface address hash.
Much quicker than going through the FIB tables. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
fd23c3b311
Коммит
9435eb1cf0
|
@ -125,6 +125,39 @@ static void inet_hash_remove(struct in_ifaddr *ifa)
|
||||||
spin_unlock(&inet_addr_hash_lock);
|
spin_unlock(&inet_addr_hash_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __ip_dev_find - find the first device with a given source address.
|
||||||
|
* @net: the net namespace
|
||||||
|
* @addr: the source address
|
||||||
|
* @devref: if true, take a reference on the found device
|
||||||
|
*
|
||||||
|
* If a caller uses devref=false, it should be protected by RCU, or RTNL
|
||||||
|
*/
|
||||||
|
struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
|
||||||
|
{
|
||||||
|
unsigned int hash = inet_addr_hash(net, addr);
|
||||||
|
struct net_device *result = NULL;
|
||||||
|
struct in_ifaddr *ifa;
|
||||||
|
struct hlist_node *node;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
hlist_for_each_entry_rcu(ifa, node, &inet_addr_lst[hash], hash) {
|
||||||
|
struct net_device *dev = ifa->ifa_dev->dev;
|
||||||
|
|
||||||
|
if (!net_eq(dev_net(dev), net))
|
||||||
|
continue;
|
||||||
|
if (ifa->ifa_address == addr) {
|
||||||
|
result = dev;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result && devref)
|
||||||
|
dev_hold(result);
|
||||||
|
rcu_read_unlock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(__ip_dev_find);
|
||||||
|
|
||||||
static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
|
static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
|
||||||
|
|
||||||
static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
|
static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
|
||||||
|
|
|
@ -132,46 +132,6 @@ static void fib_flush(struct net *net)
|
||||||
rt_cache_flush(net, -1);
|
rt_cache_flush(net, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* __ip_dev_find - find the first device with a given source address.
|
|
||||||
* @net: the net namespace
|
|
||||||
* @addr: the source address
|
|
||||||
* @devref: if true, take a reference on the found device
|
|
||||||
*
|
|
||||||
* If a caller uses devref=false, it should be protected by RCU, or RTNL
|
|
||||||
*/
|
|
||||||
struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
|
|
||||||
{
|
|
||||||
struct flowi fl = {
|
|
||||||
.fl4_dst = addr,
|
|
||||||
};
|
|
||||||
struct fib_result res = { 0 };
|
|
||||||
struct net_device *dev = NULL;
|
|
||||||
struct fib_table *local_table;
|
|
||||||
|
|
||||||
#ifdef CONFIG_IP_MULTIPLE_TABLES
|
|
||||||
res.r = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
local_table = fib_get_table(net, RT_TABLE_LOCAL);
|
|
||||||
if (!local_table ||
|
|
||||||
fib_table_lookup(local_table, &fl, &res, FIB_LOOKUP_NOREF)) {
|
|
||||||
rcu_read_unlock();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (res.type != RTN_LOCAL)
|
|
||||||
goto out;
|
|
||||||
dev = FIB_RES_DEV(res);
|
|
||||||
|
|
||||||
if (dev && devref)
|
|
||||||
dev_hold(dev);
|
|
||||||
out:
|
|
||||||
rcu_read_unlock();
|
|
||||||
return dev;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(__ip_dev_find);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find address type as if only "dev" was present in the system. If
|
* Find address type as if only "dev" was present in the system. If
|
||||||
* on_dev is NULL then all interfaces are taken into consideration.
|
* on_dev is NULL then all interfaces are taken into consideration.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче