diff options
Diffstat (limited to 'net/ipv4/ip_gre.c')
-rw-r--r-- | net/ipv4/ip_gre.c | 131 |
1 files changed, 95 insertions, 36 deletions
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 0101521f366b..07a188afb3ac 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -164,67 +164,124 @@ static DEFINE_RWLOCK(ipgre_lock); | |||
164 | 164 | ||
165 | /* Given src, dst and key, find appropriate for input tunnel. */ | 165 | /* Given src, dst and key, find appropriate for input tunnel. */ |
166 | 166 | ||
167 | static struct ip_tunnel * ipgre_tunnel_lookup(struct net *net, | 167 | static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev, |
168 | __be32 remote, __be32 local, | 168 | __be32 remote, __be32 local, |
169 | __be32 key, __be16 gre_proto) | 169 | __be32 key, __be16 gre_proto) |
170 | { | 170 | { |
171 | struct net *net = dev_net(dev); | ||
172 | int link = dev->ifindex; | ||
171 | unsigned h0 = HASH(remote); | 173 | unsigned h0 = HASH(remote); |
172 | unsigned h1 = HASH(key); | 174 | unsigned h1 = HASH(key); |
173 | struct ip_tunnel *t; | 175 | struct ip_tunnel *t, *cand = NULL; |
174 | struct ip_tunnel *t2 = NULL; | ||
175 | struct ipgre_net *ign = net_generic(net, ipgre_net_id); | 176 | struct ipgre_net *ign = net_generic(net, ipgre_net_id); |
176 | int dev_type = (gre_proto == htons(ETH_P_TEB)) ? | 177 | int dev_type = (gre_proto == htons(ETH_P_TEB)) ? |
177 | ARPHRD_ETHER : ARPHRD_IPGRE; | 178 | ARPHRD_ETHER : ARPHRD_IPGRE; |
179 | int score, cand_score = 4; | ||
178 | 180 | ||
179 | 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) { |
180 | if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) { | 182 | if (local != t->parms.iph.saddr || |
181 | if (t->parms.i_key == key && t->dev->flags & IFF_UP) { | 183 | remote != t->parms.iph.daddr || |
182 | if (t->dev->type == dev_type) | 184 | key != t->parms.i_key || |
183 | return t; | 185 | !(t->dev->flags & IFF_UP)) |
184 | if (t->dev->type == ARPHRD_IPGRE && !t2) | 186 | continue; |
185 | t2 = t; | 187 | |
186 | } | 188 | if (t->dev->type != ARPHRD_IPGRE && |
189 | t->dev->type != dev_type) | ||
190 | continue; | ||
191 | |||
192 | score = 0; | ||
193 | if (t->parms.link != link) | ||
194 | score |= 1; | ||
195 | if (t->dev->type != dev_type) | ||
196 | score |= 2; | ||
197 | if (score == 0) | ||
198 | return t; | ||
199 | |||
200 | if (score < cand_score) { | ||
201 | cand = t; | ||
202 | cand_score = score; | ||
187 | } | 203 | } |
188 | } | 204 | } |
189 | 205 | ||
190 | for (t = ign->tunnels_r[h0^h1]; t; t = t->next) { | 206 | for (t = ign->tunnels_r[h0^h1]; t; t = t->next) { |
191 | if (remote == t->parms.iph.daddr) { | 207 | if (remote != t->parms.iph.daddr || |
192 | if (t->parms.i_key == key && t->dev->flags & IFF_UP) { | 208 | key != t->parms.i_key || |
193 | if (t->dev->type == dev_type) | 209 | !(t->dev->flags & IFF_UP)) |
194 | return t; | 210 | continue; |
195 | if (t->dev->type == ARPHRD_IPGRE && !t2) | 211 | |
196 | t2 = t; | 212 | if (t->dev->type != ARPHRD_IPGRE && |
197 | } | 213 | t->dev->type != dev_type) |
214 | continue; | ||
215 | |||
216 | score = 0; | ||
217 | if (t->parms.link != link) | ||
218 | score |= 1; | ||
219 | if (t->dev->type != dev_type) | ||
220 | score |= 2; | ||
221 | if (score == 0) | ||
222 | return t; | ||
223 | |||
224 | if (score < cand_score) { | ||
225 | cand = t; | ||
226 | cand_score = score; | ||
198 | } | 227 | } |
199 | } | 228 | } |
200 | 229 | ||
201 | for (t = ign->tunnels_l[h1]; t; t = t->next) { | 230 | for (t = ign->tunnels_l[h1]; t; t = t->next) { |
202 | if (local == t->parms.iph.saddr || | 231 | if ((local != t->parms.iph.saddr && |
203 | (local == t->parms.iph.daddr && | 232 | (local != t->parms.iph.daddr || |
204 | ipv4_is_multicast(local))) { | 233 | !ipv4_is_multicast(local))) || |
205 | if (t->parms.i_key == key && t->dev->flags & IFF_UP) { | 234 | key != t->parms.i_key || |
206 | if (t->dev->type == dev_type) | 235 | !(t->dev->flags & IFF_UP)) |
207 | return t; | 236 | continue; |
208 | if (t->dev->type == ARPHRD_IPGRE && !t2) | 237 | |
209 | t2 = t; | 238 | if (t->dev->type != ARPHRD_IPGRE && |
210 | } | 239 | t->dev->type != dev_type) |
240 | continue; | ||
241 | |||
242 | score = 0; | ||
243 | if (t->parms.link != link) | ||
244 | score |= 1; | ||
245 | if (t->dev->type != dev_type) | ||
246 | score |= 2; | ||
247 | if (score == 0) | ||
248 | return t; | ||
249 | |||
250 | if (score < cand_score) { | ||
251 | cand = t; | ||
252 | cand_score = score; | ||
211 | } | 253 | } |
212 | } | 254 | } |
213 | 255 | ||
214 | for (t = ign->tunnels_wc[h1]; t; t = t->next) { | 256 | for (t = ign->tunnels_wc[h1]; t; t = t->next) { |
215 | if (t->parms.i_key == key && t->dev->flags & IFF_UP) { | 257 | if (t->parms.i_key != key || |
216 | if (t->dev->type == dev_type) | 258 | !(t->dev->flags & IFF_UP)) |
217 | return t; | 259 | continue; |
218 | if (t->dev->type == ARPHRD_IPGRE && !t2) | 260 | |
219 | t2 = t; | 261 | if (t->dev->type != ARPHRD_IPGRE && |
262 | t->dev->type != dev_type) | ||
263 | continue; | ||
264 | |||
265 | score = 0; | ||
266 | if (t->parms.link != link) | ||
267 | score |= 1; | ||
268 | if (t->dev->type != dev_type) | ||
269 | score |= 2; | ||
270 | if (score == 0) | ||
271 | return t; | ||
272 | |||
273 | if (score < cand_score) { | ||
274 | cand = t; | ||
275 | cand_score = score; | ||
220 | } | 276 | } |
221 | } | 277 | } |
222 | 278 | ||
223 | if (t2) | 279 | if (cand != NULL) |
224 | return t2; | 280 | return cand; |
225 | 281 | ||
226 | if (ign->fb_tunnel_dev->flags&IFF_UP) | 282 | if (ign->fb_tunnel_dev->flags & IFF_UP) |
227 | return netdev_priv(ign->fb_tunnel_dev); | 283 | return netdev_priv(ign->fb_tunnel_dev); |
284 | |||
228 | return NULL; | 285 | return NULL; |
229 | } | 286 | } |
230 | 287 | ||
@@ -284,6 +341,7 @@ static struct ip_tunnel *ipgre_tunnel_find(struct net *net, | |||
284 | __be32 remote = parms->iph.daddr; | 341 | __be32 remote = parms->iph.daddr; |
285 | __be32 local = parms->iph.saddr; | 342 | __be32 local = parms->iph.saddr; |
286 | __be32 key = parms->i_key; | 343 | __be32 key = parms->i_key; |
344 | int link = parms->link; | ||
287 | struct ip_tunnel *t, **tp; | 345 | struct ip_tunnel *t, **tp; |
288 | struct ipgre_net *ign = net_generic(net, ipgre_net_id); | 346 | struct ipgre_net *ign = net_generic(net, ipgre_net_id); |
289 | 347 | ||
@@ -291,6 +349,7 @@ static struct ip_tunnel *ipgre_tunnel_find(struct net *net, | |||
291 | if (local == t->parms.iph.saddr && | 349 | if (local == t->parms.iph.saddr && |
292 | remote == t->parms.iph.daddr && | 350 | remote == t->parms.iph.daddr && |
293 | key == t->parms.i_key && | 351 | key == t->parms.i_key && |
352 | link == t->parms.link && | ||
294 | type == t->dev->type) | 353 | type == t->dev->type) |
295 | break; | 354 | break; |
296 | 355 | ||
@@ -421,7 +480,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info) | |||
421 | } | 480 | } |
422 | 481 | ||
423 | read_lock(&ipgre_lock); | 482 | read_lock(&ipgre_lock); |
424 | t = ipgre_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr, | 483 | t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr, |
425 | flags & GRE_KEY ? | 484 | flags & GRE_KEY ? |
426 | *(((__be32 *)p) + (grehlen / 4) - 1) : 0, | 485 | *(((__be32 *)p) + (grehlen / 4) - 1) : 0, |
427 | p[1]); | 486 | p[1]); |
@@ -518,7 +577,7 @@ static int ipgre_rcv(struct sk_buff *skb) | |||
518 | gre_proto = *(__be16 *)(h + 2); | 577 | gre_proto = *(__be16 *)(h + 2); |
519 | 578 | ||
520 | read_lock(&ipgre_lock); | 579 | read_lock(&ipgre_lock); |
521 | if ((tunnel = ipgre_tunnel_lookup(dev_net(skb->dev), | 580 | if ((tunnel = ipgre_tunnel_lookup(skb->dev, |
522 | iph->saddr, iph->daddr, key, | 581 | iph->saddr, iph->daddr, key, |
523 | gre_proto))) { | 582 | gre_proto))) { |
524 | struct net_device_stats *stats = &tunnel->dev->stats; | 583 | struct net_device_stats *stats = &tunnel->dev->stats; |