ipv4: Implement __ip_dev_find using new interface address hash.
authorDavid S. Miller <davem@davemloft.net>
Fri, 18 Feb 2011 20:43:09 +0000 (12:43 -0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 18 Feb 2011 20:43:09 +0000 (12:43 -0800)
Much quicker than going through the FIB tables.

Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/devinet.c
net/ipv4/fib_frontend.c

index 2fe50765a6723471736d636c533df9ee92c7f8b3..ee144a4fca411b88b3180df667326837bc4a6eb9 100644 (file)
@@ -125,6 +125,39 @@ static void inet_hash_remove(struct in_ifaddr *ifa)
        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 BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
index 2a49c061b34c382e32df1332d56e10967b04e7aa..ad0778a3fa531c154cbcd68e8af94384237884a3 100644 (file)
@@ -132,46 +132,6 @@ static void fib_flush(struct net *net)
                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
  * on_dev is NULL then all interfaces are taken into consideration.