Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+33 -40
+33
net/ipv4/devinet.c
··· 125 125 spin_unlock(&inet_addr_hash_lock); 126 126 } 127 127 128 + /** 129 + * __ip_dev_find - find the first device with a given source address. 130 + * @net: the net namespace 131 + * @addr: the source address 132 + * @devref: if true, take a reference on the found device 133 + * 134 + * If a caller uses devref=false, it should be protected by RCU, or RTNL 135 + */ 136 + struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref) 137 + { 138 + unsigned int hash = inet_addr_hash(net, addr); 139 + struct net_device *result = NULL; 140 + struct in_ifaddr *ifa; 141 + struct hlist_node *node; 142 + 143 + rcu_read_lock(); 144 + hlist_for_each_entry_rcu(ifa, node, &inet_addr_lst[hash], hash) { 145 + struct net_device *dev = ifa->ifa_dev->dev; 146 + 147 + if (!net_eq(dev_net(dev), net)) 148 + continue; 149 + if (ifa->ifa_address == addr) { 150 + result = dev; 151 + break; 152 + } 153 + } 154 + if (result && devref) 155 + dev_hold(result); 156 + rcu_read_unlock(); 157 + return result; 158 + } 159 + EXPORT_SYMBOL(__ip_dev_find); 160 + 128 161 static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32); 129 162 130 163 static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
-40
net/ipv4/fib_frontend.c
··· 132 132 rt_cache_flush(net, -1); 133 133 } 134 134 135 - /** 136 - * __ip_dev_find - find the first device with a given source address. 137 - * @net: the net namespace 138 - * @addr: the source address 139 - * @devref: if true, take a reference on the found device 140 - * 141 - * If a caller uses devref=false, it should be protected by RCU, or RTNL 142 - */ 143 - struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref) 144 - { 145 - struct flowi fl = { 146 - .fl4_dst = addr, 147 - }; 148 - struct fib_result res = { 0 }; 149 - struct net_device *dev = NULL; 150 - struct fib_table *local_table; 151 - 152 - #ifdef CONFIG_IP_MULTIPLE_TABLES 153 - res.r = NULL; 154 - #endif 155 - 156 - rcu_read_lock(); 157 - local_table = fib_get_table(net, RT_TABLE_LOCAL); 158 - if (!local_table || 159 - fib_table_lookup(local_table, &fl, &res, FIB_LOOKUP_NOREF)) { 160 - rcu_read_unlock(); 161 - return NULL; 162 - } 163 - if (res.type != RTN_LOCAL) 164 - goto out; 165 - dev = FIB_RES_DEV(res); 166 - 167 - if (dev && devref) 168 - dev_hold(dev); 169 - out: 170 - rcu_read_unlock(); 171 - return dev; 172 - } 173 - EXPORT_SYMBOL(__ip_dev_find); 174 - 175 135 /* 176 136 * Find address type as if only "dev" was present in the system. If 177 137 * on_dev is NULL then all interfaces are taken into consideration.