diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/ip_gre.c | 128 |
1 files changed, 88 insertions, 40 deletions
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 0101521f366b..4a43739c9035 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -164,67 +164,113 @@ 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, *sel[4] = { NULL, NULL, NULL, 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 idx; | ||
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 && |
187 | } | 189 | t->dev->type != dev_type) |
190 | continue; | ||
191 | |||
192 | idx = 0; | ||
193 | if (t->parms.link != link) | ||
194 | idx |= 1; | ||
195 | if (t->dev->type != dev_type) | ||
196 | idx |= 2; | ||
197 | if (idx == 0) | ||
198 | return t; | ||
199 | if (sel[idx] == NULL) | ||
200 | sel[idx] = t; | ||
188 | } | 201 | } |
189 | 202 | ||
190 | for (t = ign->tunnels_r[h0^h1]; t; t = t->next) { | 203 | for (t = ign->tunnels_r[h0^h1]; t; t = t->next) { |
191 | if (remote == t->parms.iph.daddr) { | 204 | if (remote != t->parms.iph.daddr || |
192 | if (t->parms.i_key == key && t->dev->flags & IFF_UP) { | 205 | key != t->parms.i_key || |
193 | if (t->dev->type == dev_type) | 206 | !(t->dev->flags & IFF_UP)) |
194 | return t; | 207 | continue; |
195 | if (t->dev->type == ARPHRD_IPGRE && !t2) | 208 | |
196 | t2 = t; | 209 | if (t->dev->type != ARPHRD_IPGRE && |
197 | } | 210 | t->dev->type != dev_type) |
198 | } | 211 | continue; |
212 | |||
213 | idx = 0; | ||
214 | if (t->parms.link != link) | ||
215 | idx |= 1; | ||
216 | if (t->dev->type != dev_type) | ||
217 | idx |= 2; | ||
218 | if (idx == 0) | ||
219 | return t; | ||
220 | if (sel[idx] == NULL) | ||
221 | sel[idx] = t; | ||
199 | } | 222 | } |
200 | 223 | ||
201 | for (t = ign->tunnels_l[h1]; t; t = t->next) { | 224 | for (t = ign->tunnels_l[h1]; t; t = t->next) { |
202 | if (local == t->parms.iph.saddr || | 225 | if ((local != t->parms.iph.saddr && |
203 | (local == t->parms.iph.daddr && | 226 | (local != t->parms.iph.daddr || |
204 | ipv4_is_multicast(local))) { | 227 | !ipv4_is_multicast(local))) || |
205 | if (t->parms.i_key == key && t->dev->flags & IFF_UP) { | 228 | key != t->parms.i_key || |
206 | if (t->dev->type == dev_type) | 229 | !(t->dev->flags & IFF_UP)) |
207 | return t; | 230 | continue; |
208 | if (t->dev->type == ARPHRD_IPGRE && !t2) | 231 | |
209 | t2 = t; | 232 | if (t->dev->type != ARPHRD_IPGRE && |
210 | } | 233 | t->dev->type != dev_type) |
211 | } | 234 | continue; |
235 | |||
236 | idx = 0; | ||
237 | if (t->parms.link != link) | ||
238 | idx |= 1; | ||
239 | if (t->dev->type != dev_type) | ||
240 | idx |= 2; | ||
241 | if (idx == 0) | ||
242 | return t; | ||
243 | if (sel[idx] == NULL) | ||
244 | sel[idx] = t; | ||
212 | } | 245 | } |
213 | 246 | ||
214 | for (t = ign->tunnels_wc[h1]; t; t = t->next) { | 247 | for (t = ign->tunnels_wc[h1]; t; t = t->next) { |
215 | if (t->parms.i_key == key && t->dev->flags & IFF_UP) { | 248 | if (t->parms.i_key != key || |
216 | if (t->dev->type == dev_type) | 249 | !(t->dev->flags & IFF_UP)) |
217 | return t; | 250 | continue; |
218 | if (t->dev->type == ARPHRD_IPGRE && !t2) | 251 | |
219 | t2 = t; | 252 | if (t->dev->type != ARPHRD_IPGRE && |
220 | } | 253 | t->dev->type != dev_type) |
254 | continue; | ||
255 | |||
256 | idx = 0; | ||
257 | if (t->parms.link != link) | ||
258 | idx |= 1; | ||
259 | if (t->dev->type != dev_type) | ||
260 | idx |= 2; | ||
261 | if (idx == 0) | ||
262 | return t; | ||
263 | if (sel[idx] == NULL) | ||
264 | sel[idx] = t; | ||
221 | } | 265 | } |
222 | 266 | ||
223 | if (t2) | 267 | for (idx = 1; idx < ARRAY_SIZE(sel); idx++) |
224 | return t2; | 268 | if (sel[idx] != NULL) |
269 | return sel[idx]; | ||
225 | 270 | ||
226 | if (ign->fb_tunnel_dev->flags&IFF_UP) | 271 | if (ign->fb_tunnel_dev->flags & IFF_UP) |
227 | return netdev_priv(ign->fb_tunnel_dev); | 272 | return netdev_priv(ign->fb_tunnel_dev); |
273 | |||
228 | return NULL; | 274 | return NULL; |
229 | } | 275 | } |
230 | 276 | ||
@@ -284,6 +330,7 @@ static struct ip_tunnel *ipgre_tunnel_find(struct net *net, | |||
284 | __be32 remote = parms->iph.daddr; | 330 | __be32 remote = parms->iph.daddr; |
285 | __be32 local = parms->iph.saddr; | 331 | __be32 local = parms->iph.saddr; |
286 | __be32 key = parms->i_key; | 332 | __be32 key = parms->i_key; |
333 | int link = parms->link; | ||
287 | struct ip_tunnel *t, **tp; | 334 | struct ip_tunnel *t, **tp; |
288 | struct ipgre_net *ign = net_generic(net, ipgre_net_id); | 335 | struct ipgre_net *ign = net_generic(net, ipgre_net_id); |
289 | 336 | ||
@@ -291,6 +338,7 @@ static struct ip_tunnel *ipgre_tunnel_find(struct net *net, | |||
291 | if (local == t->parms.iph.saddr && | 338 | if (local == t->parms.iph.saddr && |
292 | remote == t->parms.iph.daddr && | 339 | remote == t->parms.iph.daddr && |
293 | key == t->parms.i_key && | 340 | key == t->parms.i_key && |
341 | link == t->parms.link && | ||
294 | type == t->dev->type) | 342 | type == t->dev->type) |
295 | break; | 343 | break; |
296 | 344 | ||
@@ -421,7 +469,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info) | |||
421 | } | 469 | } |
422 | 470 | ||
423 | read_lock(&ipgre_lock); | 471 | read_lock(&ipgre_lock); |
424 | t = ipgre_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr, | 472 | t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr, |
425 | flags & GRE_KEY ? | 473 | flags & GRE_KEY ? |
426 | *(((__be32 *)p) + (grehlen / 4) - 1) : 0, | 474 | *(((__be32 *)p) + (grehlen / 4) - 1) : 0, |
427 | p[1]); | 475 | p[1]); |
@@ -518,7 +566,7 @@ static int ipgre_rcv(struct sk_buff *skb) | |||
518 | gre_proto = *(__be16 *)(h + 2); | 566 | gre_proto = *(__be16 *)(h + 2); |
519 | 567 | ||
520 | read_lock(&ipgre_lock); | 568 | read_lock(&ipgre_lock); |
521 | if ((tunnel = ipgre_tunnel_lookup(dev_net(skb->dev), | 569 | if ((tunnel = ipgre_tunnel_lookup(skb->dev, |
522 | iph->saddr, iph->daddr, key, | 570 | iph->saddr, iph->daddr, key, |
523 | gre_proto))) { | 571 | gre_proto))) { |
524 | struct net_device_stats *stats = &tunnel->dev->stats; | 572 | struct net_device_stats *stats = &tunnel->dev->stats; |