aboutsummaryrefslogtreecommitdiffstats
path: root/main/linux-grsec/0002-linux-2.6.28.5-ipgre-optimize-hash-lookup.patch
blob: fbfef33b9bd81c02337c646562aa0badf2db42d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
From: Timo Teras <timo.teras@iki.fi>
Date: Tue, 27 Jan 2009 04:56:10 +0000 (-0800)
Subject: gre: optimize hash lookup
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fdavem%2Fnet-next-2.6.git;a=commitdiff_plain;h=afcf12422ec8236dc8b9238fef7a475876eea8da;hp=3eacdf58c2c0b9507afedfc19108e98b992c31e4

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>
---

diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 4a43739..07a188a 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,
 	int link = dev->ifindex;
 	unsigned h0 = HASH(remote);
 	unsigned h1 = HASH(key);
-	struct ip_tunnel *t, *sel[4] = { NULL, NULL, NULL, NULL };
+	struct ip_tunnel *t, *cand = NULL;
 	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
 	int dev_type = (gre_proto == htons(ETH_P_TEB)) ?
 		       ARPHRD_ETHER : ARPHRD_IPGRE;
-	int idx;
+	int score, cand_score = 4;
 
 	for (t = ign->tunnels_r_l[h0^h1]; t; t = t->next) {
 		if (local != t->parms.iph.saddr ||
@@ -189,15 +189,18 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
 		    t->dev->type != dev_type)
 			continue;
 
-		idx = 0;
+		score = 0;
 		if (t->parms.link != link)
-			idx |= 1;
+			score |= 1;
 		if (t->dev->type != dev_type)
-			idx |= 2;
-		if (idx == 0)
+			score |= 2;
+		if (score == 0)
 			return t;
-		if (sel[idx] == NULL)
-			sel[idx] = t;
+
+		if (score < cand_score) {
+			cand = t;
+			cand_score = score;
+		}
 	}
 
 	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,
 		    t->dev->type != dev_type)
 			continue;
 
-		idx = 0;
+		score = 0;
 		if (t->parms.link != link)
-			idx |= 1;
+			score |= 1;
 		if (t->dev->type != dev_type)
-			idx |= 2;
-		if (idx == 0)
+			score |= 2;
+		if (score == 0)
 			return t;
-		if (sel[idx] == NULL)
-			sel[idx] = t;
+
+		if (score < cand_score) {
+			cand = t;
+			cand_score = score;
+		}
 	}
 
 	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,
 		    t->dev->type != dev_type)
 			continue;
 
-		idx = 0;
+		score = 0;
 		if (t->parms.link != link)
-			idx |= 1;
+			score |= 1;
 		if (t->dev->type != dev_type)
-			idx |= 2;
-		if (idx == 0)
+			score |= 2;
+		if (score == 0)
 			return t;
-		if (sel[idx] == NULL)
-			sel[idx] = t;
+
+		if (score < cand_score) {
+			cand = t;
+			cand_score = score;
+		}
 	}
 
 	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,
 		    t->dev->type != dev_type)
 			continue;
 
-		idx = 0;
+		score = 0;
 		if (t->parms.link != link)
-			idx |= 1;
+			score |= 1;
 		if (t->dev->type != dev_type)
-			idx |= 2;
-		if (idx == 0)
+			score |= 2;
+		if (score == 0)
 			return t;
-		if (sel[idx] == NULL)
-			sel[idx] = t;
+
+		if (score < cand_score) {
+			cand = t;
+			cand_score = score;
+		}
 	}
 
-	for (idx = 1; idx < ARRAY_SIZE(sel); idx++)
-		if (sel[idx] != NULL)
-			return sel[idx];
+	if (cand != NULL)
+		return cand;
 
 	if (ign->fb_tunnel_dev->flags & IFF_UP)
 		return netdev_priv(ign->fb_tunnel_dev);