aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ip_gre.c
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2009-01-19 20:22:12 -0500
committerDavid S. Miller <davem@davemloft.net>2009-01-21 17:34:54 -0500
commit749c10f931923451a4c59b4435d182aa9ae27a4f (patch)
tree1c715c26a58ccdf144f8ff5cd64d7ff5ab1bf36b /net/ipv4/ip_gre.c
parent57a574993d94671b495cdbe8aeb78b745abfe14f (diff)
gre: strict physical device binding
Check the device on receive path and allow otherwise identical devices as long as the physical device differs. This is useful for NBMA tunnels, where you want to use different gre IP for each public IP available via different physical devices. Signed-off-by: Timo Teras <timo.teras@iki.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/ip_gre.c')
-rw-r--r--net/ipv4/ip_gre.c128
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
167static struct ip_tunnel * ipgre_tunnel_lookup(struct net *net, 167static 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;