]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - net/ipv4/devinet.c
net: avoid a full fib lookup when rp_filter is disabled.
[mirror_ubuntu-bionic-kernel.git] / net / ipv4 / devinet.c
index d7adc06165998947efc6cda8bed31c77c0976d14..7ce22a2c07ce07ac2cd4cafb5aff6ec8d074531f 100644 (file)
@@ -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);