diff options
author | Steffen Klassert <steffen.klassert@secunet.com> | 2014-11-05 02:03:50 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-11-06 14:19:20 -0500 |
commit | ea3dc9601bda69d8d695b57c4f7a997cd7039781 (patch) | |
tree | cebdab7c6b281e52d54a96e30738539825448f92 /net/ipv6/ip6_tunnel.c | |
parent | d50051407f136028108cfda068d55ef053a54fe1 (diff) |
ip6_tunnel: Add support for wildcard tunnel endpoints.
This patch adds support for tunnels with local or
remote wildcard endpoints. With this we get a
NBMA tunnel mode like we have it for ipv4 and
sit tunnels.
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/ip6_tunnel.c')
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index a8f94ff9c606..4550d08f44de 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -183,6 +183,7 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_ | |||
183 | unsigned int hash = HASH(remote, local); | 183 | unsigned int hash = HASH(remote, local); |
184 | struct ip6_tnl *t; | 184 | struct ip6_tnl *t; |
185 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 185 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
186 | struct in6_addr any; | ||
186 | 187 | ||
187 | for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { | 188 | for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { |
188 | if (ipv6_addr_equal(local, &t->parms.laddr) && | 189 | if (ipv6_addr_equal(local, &t->parms.laddr) && |
@@ -190,6 +191,22 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_ | |||
190 | (t->dev->flags & IFF_UP)) | 191 | (t->dev->flags & IFF_UP)) |
191 | return t; | 192 | return t; |
192 | } | 193 | } |
194 | |||
195 | memset(&any, 0, sizeof(any)); | ||
196 | hash = HASH(&any, local); | ||
197 | for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { | ||
198 | if (ipv6_addr_equal(local, &t->parms.laddr) && | ||
199 | (t->dev->flags & IFF_UP)) | ||
200 | return t; | ||
201 | } | ||
202 | |||
203 | hash = HASH(remote, &any); | ||
204 | for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { | ||
205 | if (ipv6_addr_equal(remote, &t->parms.raddr) && | ||
206 | (t->dev->flags & IFF_UP)) | ||
207 | return t; | ||
208 | } | ||
209 | |||
193 | t = rcu_dereference(ip6n->tnls_wc[0]); | 210 | t = rcu_dereference(ip6n->tnls_wc[0]); |
194 | if (t && (t->dev->flags & IFF_UP)) | 211 | if (t && (t->dev->flags & IFF_UP)) |
195 | return t; | 212 | return t; |
@@ -979,7 +996,29 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, | |||
979 | u8 proto; | 996 | u8 proto; |
980 | int err = -1; | 997 | int err = -1; |
981 | 998 | ||
982 | if (!fl6->flowi6_mark) | 999 | /* NBMA tunnel */ |
1000 | if (ipv6_addr_any(&t->parms.raddr)) { | ||
1001 | struct in6_addr *addr6; | ||
1002 | struct neighbour *neigh; | ||
1003 | int addr_type; | ||
1004 | |||
1005 | if (!skb_dst(skb)) | ||
1006 | goto tx_err_link_failure; | ||
1007 | |||
1008 | neigh = dst_neigh_lookup(skb_dst(skb), | ||
1009 | &ipv6_hdr(skb)->daddr); | ||
1010 | if (!neigh) | ||
1011 | goto tx_err_link_failure; | ||
1012 | |||
1013 | addr6 = (struct in6_addr *)&neigh->primary_key; | ||
1014 | addr_type = ipv6_addr_type(addr6); | ||
1015 | |||
1016 | if (addr_type == IPV6_ADDR_ANY) | ||
1017 | addr6 = &ipv6_hdr(skb)->daddr; | ||
1018 | |||
1019 | memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr)); | ||
1020 | neigh_release(neigh); | ||
1021 | } else if (!fl6->flowi6_mark) | ||
983 | dst = ip6_tnl_dst_check(t); | 1022 | dst = ip6_tnl_dst_check(t); |
984 | 1023 | ||
985 | if (!ip6_tnl_xmit_ctl(t, &fl6->saddr, &fl6->daddr)) | 1024 | if (!ip6_tnl_xmit_ctl(t, &fl6->saddr, &fl6->daddr)) |