Skip to content

Commit d500514

Browse files
klassertdavem330
authored andcommitted
ipv6: Allow sending packets through tunnels with wildcard endpoints
Currently we need the IP6_TNL_F_CAP_XMIT capabiltiy to transmit packets through an ipv6 tunnel. This capability is set when the tunnel gets configured, based on the tunnel endpoint addresses. On tunnels with wildcard tunnel endpoints, we need to do the capabiltiy checking on a per packet basis like it is done in the receive path. This patch extends ip6_tnl_xmit_ctl() to take local and remote addresses as parameters to allow for per packet capabiltiy checking. Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent e1b2cb6 commit d500514

File tree

4 files changed

+26
-12
lines changed

4 files changed

+26
-12
lines changed

include/net/ip6_tunnel.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ void ip6_tnl_dst_reset(struct ip6_tnl *t);
6565
void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst);
6666
int ip6_tnl_rcv_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
6767
const struct in6_addr *raddr);
68-
int ip6_tnl_xmit_ctl(struct ip6_tnl *t);
68+
int ip6_tnl_xmit_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
69+
const struct in6_addr *raddr);
6970
__u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw);
7071
__u32 ip6_tnl_get_cap(struct ip6_tnl *t, const struct in6_addr *laddr,
7172
const struct in6_addr *raddr);

net/ipv6/ip6_gre.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,7 @@ static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb,
902902
struct net_device_stats *stats = &t->dev->stats;
903903
int ret;
904904

905-
if (!ip6_tnl_xmit_ctl(t))
905+
if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr))
906906
goto tx_err;
907907

908908
switch (skb->protocol) {

net/ipv6/ip6_tunnel.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -909,24 +909,28 @@ ip6_tnl_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr)
909909
return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
910910
}
911911

912-
int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
912+
int ip6_tnl_xmit_ctl(struct ip6_tnl *t,
913+
const struct in6_addr *laddr,
914+
const struct in6_addr *raddr)
913915
{
914916
struct __ip6_tnl_parm *p = &t->parms;
915917
int ret = 0;
916918
struct net *net = t->net;
917919

918-
if (p->flags & IP6_TNL_F_CAP_XMIT) {
920+
if ((p->flags & IP6_TNL_F_CAP_XMIT) ||
921+
((p->flags & IP6_TNL_F_CAP_PER_PACKET) &&
922+
(ip6_tnl_get_cap(t, laddr, raddr) & IP6_TNL_F_CAP_XMIT))) {
919923
struct net_device *ldev = NULL;
920924

921925
rcu_read_lock();
922926
if (p->link)
923927
ldev = dev_get_by_index_rcu(net, p->link);
924928

925-
if (unlikely(!ipv6_chk_addr(net, &p->laddr, ldev, 0)))
929+
if (unlikely(!ipv6_chk_addr(net, laddr, ldev, 0)))
926930
pr_warn("%s xmit: Local address not yet configured!\n",
927931
p->name);
928-
else if (!ipv6_addr_is_multicast(&p->raddr) &&
929-
unlikely(ipv6_chk_addr(net, &p->raddr, NULL, 0)))
932+
else if (!ipv6_addr_is_multicast(raddr) &&
933+
unlikely(ipv6_chk_addr(net, raddr, NULL, 0)))
930934
pr_warn("%s xmit: Routing loop! Remote address found on this node!\n",
931935
p->name);
932936
else
@@ -977,6 +981,10 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
977981

978982
if (!fl6->flowi6_mark)
979983
dst = ip6_tnl_dst_check(t);
984+
985+
if (!ip6_tnl_xmit_ctl(t, &fl6->saddr, &fl6->daddr))
986+
goto tx_err_link_failure;
987+
980988
if (!dst) {
981989
ndst = ip6_route_output(net, NULL, fl6);
982990

@@ -1086,8 +1094,7 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
10861094
int err;
10871095

10881096
tproto = ACCESS_ONCE(t->parms.proto);
1089-
if ((tproto != IPPROTO_IPIP && tproto != 0) ||
1090-
!ip6_tnl_xmit_ctl(t))
1097+
if (tproto != IPPROTO_IPIP && tproto != 0)
10911098
return -1;
10921099

10931100
if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
@@ -1131,7 +1138,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
11311138

11321139
tproto = ACCESS_ONCE(t->parms.proto);
11331140
if ((tproto != IPPROTO_IPV6 && tproto != 0) ||
1134-
!ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h))
1141+
ip6_tnl_addr_conflict(t, ipv6h))
11351142
return -1;
11361143

11371144
offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));

net/ipv6/ip6_vti.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
416416
struct net_device_stats *stats = &t->dev->stats;
417417
struct dst_entry *dst = skb_dst(skb);
418418
struct net_device *tdev;
419+
struct xfrm_state *x;
419420
int err = -1;
420421

421422
if (!dst)
@@ -429,7 +430,12 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
429430
goto tx_err_link_failure;
430431
}
431432

432-
if (!vti6_state_check(dst->xfrm, &t->parms.raddr, &t->parms.laddr))
433+
x = dst->xfrm;
434+
if (!vti6_state_check(x, &t->parms.raddr, &t->parms.laddr))
435+
goto tx_err_link_failure;
436+
437+
if (!ip6_tnl_xmit_ctl(t, (const struct in6_addr *)&x->props.saddr,
438+
(const struct in6_addr *)&x->id.daddr))
433439
goto tx_err_link_failure;
434440

435441
tdev = dst->dev;
@@ -484,7 +490,7 @@ vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
484490
ipv6h = ipv6_hdr(skb);
485491

486492
if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
487-
!ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h))
493+
vti6_addr_conflict(t, ipv6h))
488494
goto tx_err;
489495

490496
xfrm_decode_session(skb, &fl, AF_INET6);

0 commit comments

Comments
 (0)