aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorVille Nuorvala <ville.nuorvala@gmail.com>2012-06-28 14:15:52 -0400
committerDavid S. Miller <davem@davemloft.net>2012-06-29 03:52:32 -0400
commitd0087b29f77176480c27c203988b5704847d617c (patch)
tree2b2395525633ce8dbeb1a9e13be906f73ffeb207 /net/ipv6
parent1e0b6eac6a150a35b45d019681b0021896354ae5 (diff)
ipv6_tunnel: Allow receiving packets on the fallback tunnel if they pass sanity checks
At Facebook, we do Layer-3 DSR via IP-in-IP tunneling. Our load balancers wrap an extra IP header on incoming packets so they can be routed to the backend. In the v4 tunnel driver, when these packets fall on the default tunl0 device, the behavior is to decapsulate them and drop them back on the stack. So our setup is that tunl0 has the VIP and eth0 has (obviously) the backend's real address. In IPv6 we do the same thing, but the v6 tunnel driver didn't have this same behavior - if you didn't have an explicit tunnel setup, it would drop the packet. This patch brings that v4 feature to the v6 driver. The same IPv6 address checks are performed as with any normal tunnel, but as the fallback tunnel endpoint addresses are unspecified, the checks must be performed on a per-packet basis, rather than at tunnel configuration time. [Patch description modified by phil@ipom.com] Signed-off-by: Ville Nuorvala <ville.nuorvala@gmail.com> Tested-by: Phil Dibowitz <phil@ipom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ip6_tunnel.c65
1 files changed, 38 insertions, 27 deletions
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index c9015fad8d6..04a3cba2c12 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -684,24 +684,50 @@ static void ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
684 IP6_ECN_set_ce(ipv6_hdr(skb)); 684 IP6_ECN_set_ce(ipv6_hdr(skb));
685} 685}
686 686
687static __u32 ip6_tnl_get_cap(struct ip6_tnl *t,
688 const struct in6_addr *laddr,
689 const struct in6_addr *raddr)
690{
691 struct ip6_tnl_parm *p = &t->parms;
692 int ltype = ipv6_addr_type(laddr);
693 int rtype = ipv6_addr_type(raddr);
694 __u32 flags = 0;
695
696 if (ltype == IPV6_ADDR_ANY || rtype == IPV6_ADDR_ANY) {
697 flags = IP6_TNL_F_CAP_PER_PACKET;
698 } else if (ltype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) &&
699 rtype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) &&
700 !((ltype|rtype) & IPV6_ADDR_LOOPBACK) &&
701 (!((ltype|rtype) & IPV6_ADDR_LINKLOCAL) || p->link)) {
702 if (ltype&IPV6_ADDR_UNICAST)
703 flags |= IP6_TNL_F_CAP_XMIT;
704 if (rtype&IPV6_ADDR_UNICAST)
705 flags |= IP6_TNL_F_CAP_RCV;
706 }
707 return flags;
708}
709
687/* called with rcu_read_lock() */ 710/* called with rcu_read_lock() */
688static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) 711static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
712 const struct in6_addr *laddr,
713 const struct in6_addr *raddr)
689{ 714{
690 struct ip6_tnl_parm *p = &t->parms; 715 struct ip6_tnl_parm *p = &t->parms;
691 int ret = 0; 716 int ret = 0;
692 struct net *net = dev_net(t->dev); 717 struct net *net = dev_net(t->dev);
693 718
694 if (p->flags & IP6_TNL_F_CAP_RCV) { 719 if ((p->flags & IP6_TNL_F_CAP_RCV) ||
720 ((p->flags & IP6_TNL_F_CAP_PER_PACKET) &&
721 (ip6_tnl_get_cap(t, laddr, raddr) & IP6_TNL_F_CAP_RCV))) {
695 struct net_device *ldev = NULL; 722 struct net_device *ldev = NULL;
696 723
697 if (p->link) 724 if (p->link)
698 ldev = dev_get_by_index_rcu(net, p->link); 725 ldev = dev_get_by_index_rcu(net, p->link);
699 726
700 if ((ipv6_addr_is_multicast(&p->laddr) || 727 if ((ipv6_addr_is_multicast(laddr) ||
701 likely(ipv6_chk_addr(net, &p->laddr, ldev, 0))) && 728 likely(ipv6_chk_addr(net, laddr, ldev, 0))) &&
702 likely(!ipv6_chk_addr(net, &p->raddr, NULL, 0))) 729 likely(!ipv6_chk_addr(net, raddr, NULL, 0)))
703 ret = 1; 730 ret = 1;
704
705 } 731 }
706 return ret; 732 return ret;
707} 733}
@@ -740,7 +766,7 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
740 goto discard; 766 goto discard;
741 } 767 }
742 768
743 if (!ip6_tnl_rcv_ctl(t)) { 769 if (!ip6_tnl_rcv_ctl(t, &ipv6h->daddr, &ipv6h->saddr)) {
744 t->dev->stats.rx_dropped++; 770 t->dev->stats.rx_dropped++;
745 rcu_read_unlock(); 771 rcu_read_unlock();
746 goto discard; 772 goto discard;
@@ -1114,25 +1140,6 @@ tx_err:
1114 return NETDEV_TX_OK; 1140 return NETDEV_TX_OK;
1115} 1141}
1116 1142
1117static void ip6_tnl_set_cap(struct ip6_tnl *t)
1118{
1119 struct ip6_tnl_parm *p = &t->parms;
1120 int ltype = ipv6_addr_type(&p->laddr);
1121 int rtype = ipv6_addr_type(&p->raddr);
1122
1123 p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV);
1124
1125 if (ltype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) &&
1126 rtype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) &&
1127 !((ltype|rtype) & IPV6_ADDR_LOOPBACK) &&
1128 (!((ltype|rtype) & IPV6_ADDR_LINKLOCAL) || p->link)) {
1129 if (ltype&IPV6_ADDR_UNICAST)
1130 p->flags |= IP6_TNL_F_CAP_XMIT;
1131 if (rtype&IPV6_ADDR_UNICAST)
1132 p->flags |= IP6_TNL_F_CAP_RCV;
1133 }
1134}
1135
1136static void ip6_tnl_link_config(struct ip6_tnl *t) 1143static void ip6_tnl_link_config(struct ip6_tnl *t)
1137{ 1144{
1138 struct net_device *dev = t->dev; 1145 struct net_device *dev = t->dev;
@@ -1153,7 +1160,8 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
1153 if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL)) 1160 if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
1154 fl6->flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo; 1161 fl6->flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo;
1155 1162
1156 ip6_tnl_set_cap(t); 1163 p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV|IP6_TNL_F_CAP_PER_PACKET);
1164 p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr);
1157 1165
1158 if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV) 1166 if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV)
1159 dev->flags |= IFF_POINTOPOINT; 1167 dev->flags |= IFF_POINTOPOINT;
@@ -1438,6 +1446,9 @@ static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
1438 1446
1439 t->parms.proto = IPPROTO_IPV6; 1447 t->parms.proto = IPPROTO_IPV6;
1440 dev_hold(dev); 1448 dev_hold(dev);
1449
1450 ip6_tnl_link_config(t);
1451
1441 rcu_assign_pointer(ip6n->tnls_wc[0], t); 1452 rcu_assign_pointer(ip6n->tnls_wc[0], t);
1442 return 0; 1453 return 0;
1443} 1454}