Skip to content

Commit d0087b2

Browse files
SwissMaulwurfdavem330
authored andcommitted
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>
1 parent 1e0b6ea commit d0087b2

File tree

2 files changed

+40
-27
lines changed

2 files changed

+40
-27
lines changed

include/net/ip6_tunnel.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#define IP6_TNL_F_CAP_XMIT 0x10000
1010
/* capable of receiving packets */
1111
#define IP6_TNL_F_CAP_RCV 0x20000
12+
/* determine capability on a per-packet basis */
13+
#define IP6_TNL_F_CAP_PER_PACKET 0x40000
1214

1315
/* IPv6 tunnel */
1416

net/ipv6/ip6_tunnel.c

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -684,24 +684,50 @@ static void ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
684684
IP6_ECN_set_ce(ipv6_hdr(skb));
685685
}
686686

687+
static __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+
687710
/* called with rcu_read_lock() */
688-
static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t)
711+
static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
712+
const struct in6_addr *laddr,
713+
const struct in6_addr *raddr)
689714
{
690715
struct ip6_tnl_parm *p = &t->parms;
691716
int ret = 0;
692717
struct net *net = dev_net(t->dev);
693718

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))) {
695722
struct net_device *ldev = NULL;
696723

697724
if (p->link)
698725
ldev = dev_get_by_index_rcu(net, p->link);
699726

700-
if ((ipv6_addr_is_multicast(&p->laddr) ||
701-
likely(ipv6_chk_addr(net, &p->laddr, ldev, 0))) &&
702-
likely(!ipv6_chk_addr(net, &p->raddr, NULL, 0)))
727+
if ((ipv6_addr_is_multicast(laddr) ||
728+
likely(ipv6_chk_addr(net, laddr, ldev, 0))) &&
729+
likely(!ipv6_chk_addr(net, raddr, NULL, 0)))
703730
ret = 1;
704-
705731
}
706732
return ret;
707733
}
@@ -740,7 +766,7 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
740766
goto discard;
741767
}
742768

743-
if (!ip6_tnl_rcv_ctl(t)) {
769+
if (!ip6_tnl_rcv_ctl(t, &ipv6h->daddr, &ipv6h->saddr)) {
744770
t->dev->stats.rx_dropped++;
745771
rcu_read_unlock();
746772
goto discard;
@@ -1114,25 +1140,6 @@ ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
11141140
return NETDEV_TX_OK;
11151141
}
11161142

1117-
static 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-
11361143
static void ip6_tnl_link_config(struct ip6_tnl *t)
11371144
{
11381145
struct net_device *dev = t->dev;
@@ -1153,7 +1160,8 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
11531160
if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
11541161
fl6->flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo;
11551162

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);
11571165

11581166
if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV)
11591167
dev->flags |= IFF_POINTOPOINT;
@@ -1438,6 +1446,9 @@ static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
14381446

14391447
t->parms.proto = IPPROTO_IPV6;
14401448
dev_hold(dev);
1449+
1450+
ip6_tnl_link_config(t);
1451+
14411452
rcu_assign_pointer(ip6n->tnls_wc[0], t);
14421453
return 0;
14431454
}

0 commit comments

Comments
 (0)