aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2009-01-26 23:56:10 -0500
committerDavid S. Miller <davem@davemloft.net>2009-01-26 23:56:10 -0500
commitafcf12422ec8236dc8b9238fef7a475876eea8da (patch)
tree26210e243faddf54da2b0c35cee81c0b27b6734b
parent3eacdf58c2c0b9507afedfc19108e98b992c31e4 (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.c69
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);