diff options
author | Timo Teras <timo.teras@iki.fi> | 2009-01-26 23:56:10 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-01-26 23:56:10 -0500 |
commit | afcf12422ec8236dc8b9238fef7a475876eea8da (patch) | |
tree | 26210e243faddf54da2b0c35cee81c0b27b6734b | |
parent | 3eacdf58c2c0b9507afedfc19108e98b992c31e4 (diff) |
gre: optimize hash lookup
Instead of keeping candidate tunnel device from all categories,
keep only one candidate with best score. This optimizes stack
usage and speeds up exit code.
Signed-off-by: Timo Teras <timo.teras@iki.fi>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv4/ip_gre.c | 69 |
1 files changed, 40 insertions, 29 deletions
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 4a43739c9035..07a188afb3ac 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -172,11 +172,11 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev, | |||
172 | int link = dev->ifindex; | 172 | int link = dev->ifindex; |
173 | unsigned h0 = HASH(remote); | 173 | unsigned h0 = HASH(remote); |
174 | unsigned h1 = HASH(key); | 174 | unsigned h1 = HASH(key); |
175 | struct ip_tunnel *t, *sel[4] = { NULL, NULL, NULL, NULL }; | 175 | struct ip_tunnel *t, *cand = NULL; |
176 | struct ipgre_net *ign = net_generic(net, ipgre_net_id); | 176 | struct ipgre_net *ign = net_generic(net, ipgre_net_id); |
177 | int dev_type = (gre_proto == htons(ETH_P_TEB)) ? | 177 | int dev_type = (gre_proto == htons(ETH_P_TEB)) ? |
178 | ARPHRD_ETHER : ARPHRD_IPGRE; | 178 | ARPHRD_ETHER : ARPHRD_IPGRE; |
179 | int idx; | 179 | int score, cand_score = 4; |
180 | 180 | ||
181 | for (t = ign->tunnels_r_l[h0^h1]; t; t = t->next) { | 181 | for (t = ign->tunnels_r_l[h0^h1]; t; t = t->next) { |
182 | if (local != t->parms.iph.saddr || | 182 | if (local != t->parms.iph.saddr || |
@@ -189,15 +189,18 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev, | |||
189 | t->dev->type != dev_type) | 189 | t->dev->type != dev_type) |
190 | continue; | 190 | continue; |
191 | 191 | ||
192 | idx = 0; | 192 | score = 0; |
193 | if (t->parms.link != link) | 193 | if (t->parms.link != link) |
194 | idx |= 1; | 194 | score |= 1; |
195 | if (t->dev->type != dev_type) | 195 | if (t->dev->type != dev_type) |
196 | idx |= 2; | 196 | score |= 2; |
197 | if (idx == 0) | 197 | if (score == 0) |
198 | return t; | 198 | return t; |
199 | if (sel[idx] == NULL) | 199 | |
200 | sel[idx] = t; | 200 | if (score < cand_score) { |
201 | cand = t; | ||
202 | cand_score = score; | ||
203 | } | ||
201 | } | 204 | } |
202 | 205 | ||
203 | for (t = ign->tunnels_r[h0^h1]; t; t = t->next) { | 206 | for (t = ign->tunnels_r[h0^h1]; t; t = t->next) { |
@@ -210,15 +213,18 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev, | |||
210 | t->dev->type != dev_type) | 213 | t->dev->type != dev_type) |
211 | continue; | 214 | continue; |
212 | 215 | ||
213 | idx = 0; | 216 | score = 0; |
214 | if (t->parms.link != link) | 217 | if (t->parms.link != link) |
215 | idx |= 1; | 218 | score |= 1; |
216 | if (t->dev->type != dev_type) | 219 | if (t->dev->type != dev_type) |
217 | idx |= 2; | 220 | score |= 2; |
218 | if (idx == 0) | 221 | if (score == 0) |
219 | return t; | 222 | return t; |
220 | if (sel[idx] == NULL) | 223 | |
221 | sel[idx] = t; | 224 | if (score < cand_score) { |
225 | cand = t; | ||
226 | cand_score = score; | ||
227 | } | ||
222 | } | 228 | } |
223 | 229 | ||
224 | for (t = ign->tunnels_l[h1]; t; t = t->next) { | 230 | for (t = ign->tunnels_l[h1]; t; t = t->next) { |
@@ -233,15 +239,18 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev, | |||
233 | t->dev->type != dev_type) | 239 | t->dev->type != dev_type) |
234 | continue; | 240 | continue; |
235 | 241 | ||
236 | idx = 0; | 242 | score = 0; |
237 | if (t->parms.link != link) | 243 | if (t->parms.link != link) |
238 | idx |= 1; | 244 | score |= 1; |
239 | if (t->dev->type != dev_type) | 245 | if (t->dev->type != dev_type) |
240 | idx |= 2; | 246 | score |= 2; |
241 | if (idx == 0) | 247 | if (score == 0) |
242 | return t; | 248 | return t; |
243 | if (sel[idx] == NULL) | 249 | |
244 | sel[idx] = t; | 250 | if (score < cand_score) { |
251 | cand = t; | ||
252 | cand_score = score; | ||
253 | } | ||
245 | } | 254 | } |
246 | 255 | ||
247 | for (t = ign->tunnels_wc[h1]; t; t = t->next) { | 256 | for (t = ign->tunnels_wc[h1]; t; t = t->next) { |
@@ -253,20 +262,22 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev, | |||
253 | t->dev->type != dev_type) | 262 | t->dev->type != dev_type) |
254 | continue; | 263 | continue; |
255 | 264 | ||
256 | idx = 0; | 265 | score = 0; |
257 | if (t->parms.link != link) | 266 | if (t->parms.link != link) |
258 | idx |= 1; | 267 | score |= 1; |
259 | if (t->dev->type != dev_type) | 268 | if (t->dev->type != dev_type) |
260 | idx |= 2; | 269 | score |= 2; |
261 | if (idx == 0) | 270 | if (score == 0) |
262 | return t; | 271 | return t; |
263 | if (sel[idx] == NULL) | 272 | |
264 | sel[idx] = t; | 273 | if (score < cand_score) { |
274 | cand = t; | ||
275 | cand_score = score; | ||
276 | } | ||
265 | } | 277 | } |
266 | 278 | ||
267 | for (idx = 1; idx < ARRAY_SIZE(sel); idx++) | 279 | if (cand != NULL) |
268 | if (sel[idx] != NULL) | 280 | return cand; |
269 | return sel[idx]; | ||
270 | 281 | ||
271 | if (ign->fb_tunnel_dev->flags & IFF_UP) | 282 | if (ign->fb_tunnel_dev->flags & IFF_UP) |
272 | return netdev_priv(ign->fb_tunnel_dev); | 283 | return netdev_priv(ign->fb_tunnel_dev); |