Skip to content

Commit c6c3345

Browse files
borkmanndavem330
authored andcommitted
bpf: support ipv6 for bpf_skb_{set,get}_tunnel_key
After IPv6 support has recently been added to metadata dst and related encaps, add support for populating/reading it from an eBPF program. Commit d3aa45c ("bpf: add helpers to access tunnel metadata") started with initial IPv4-only support back then (due to IPv6 metadata support not being available yet). To stay compatible with older programs, we need to test for the passed structure size. Also TOS and TTL support from the ip_tunnel_info key has been added. Tested with vxlan devs in collect meta data mode with IPv4, IPv6 and in compat mode over different network namespaces. Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 781c53b commit c6c3345

File tree

2 files changed

+71
-8
lines changed

2 files changed

+71
-8
lines changed

include/uapi/linux/bpf.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,9 @@ enum bpf_func_id {
289289
/* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
290290
#define BPF_F_INGRESS (1ULL << 0)
291291

292+
/* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */
293+
#define BPF_F_TUNINFO_IPV6 (1ULL << 0)
294+
292295
/* user accessible mirror of in-kernel sk_buff.
293296
* new fields can only be added to the end of this structure
294297
*/
@@ -312,7 +315,12 @@ struct __sk_buff {
312315

313316
struct bpf_tunnel_key {
314317
__u32 tunnel_id;
315-
__u32 remote_ipv4;
318+
union {
319+
__u32 remote_ipv4;
320+
__u32 remote_ipv6[4];
321+
};
322+
__u8 tunnel_tos;
323+
__u8 tunnel_ttl;
316324
};
317325

318326
#endif /* _UAPI__LINUX_BPF_H__ */

net/core/filter.c

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,19 +1680,49 @@ bool bpf_helper_changes_skb_data(void *func)
16801680
return false;
16811681
}
16821682

1683+
static unsigned short bpf_tunnel_key_af(u64 flags)
1684+
{
1685+
return flags & BPF_F_TUNINFO_IPV6 ? AF_INET6 : AF_INET;
1686+
}
1687+
16831688
static u64 bpf_skb_get_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
16841689
{
16851690
struct sk_buff *skb = (struct sk_buff *) (long) r1;
16861691
struct bpf_tunnel_key *to = (struct bpf_tunnel_key *) (long) r2;
1687-
struct ip_tunnel_info *info = skb_tunnel_info(skb);
1692+
const struct ip_tunnel_info *info = skb_tunnel_info(skb);
1693+
u8 compat[sizeof(struct bpf_tunnel_key)];
16881694

1689-
if (unlikely(size != sizeof(struct bpf_tunnel_key) || flags || !info))
1690-
return -EINVAL;
1691-
if (ip_tunnel_info_af(info) != AF_INET)
1695+
if (unlikely(!info || (flags & ~(BPF_F_TUNINFO_IPV6))))
16921696
return -EINVAL;
1697+
if (ip_tunnel_info_af(info) != bpf_tunnel_key_af(flags))
1698+
return -EPROTO;
1699+
if (unlikely(size != sizeof(struct bpf_tunnel_key))) {
1700+
switch (size) {
1701+
case offsetof(struct bpf_tunnel_key, remote_ipv6[1]):
1702+
/* Fixup deprecated structure layouts here, so we have
1703+
* a common path later on.
1704+
*/
1705+
if (ip_tunnel_info_af(info) != AF_INET)
1706+
return -EINVAL;
1707+
to = (struct bpf_tunnel_key *)compat;
1708+
break;
1709+
default:
1710+
return -EINVAL;
1711+
}
1712+
}
16931713

16941714
to->tunnel_id = be64_to_cpu(info->key.tun_id);
1695-
to->remote_ipv4 = be32_to_cpu(info->key.u.ipv4.src);
1715+
to->tunnel_tos = info->key.tos;
1716+
to->tunnel_ttl = info->key.ttl;
1717+
1718+
if (flags & BPF_F_TUNINFO_IPV6)
1719+
memcpy(to->remote_ipv6, &info->key.u.ipv6.src,
1720+
sizeof(to->remote_ipv6));
1721+
else
1722+
to->remote_ipv4 = be32_to_cpu(info->key.u.ipv4.src);
1723+
1724+
if (unlikely(size != sizeof(struct bpf_tunnel_key)))
1725+
memcpy((void *)(long) r2, to, size);
16961726

16971727
return 0;
16981728
}
@@ -1714,20 +1744,45 @@ static u64 bpf_skb_set_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
17141744
struct sk_buff *skb = (struct sk_buff *) (long) r1;
17151745
struct bpf_tunnel_key *from = (struct bpf_tunnel_key *) (long) r2;
17161746
struct metadata_dst *md = this_cpu_ptr(md_dst);
1747+
u8 compat[sizeof(struct bpf_tunnel_key)];
17171748
struct ip_tunnel_info *info;
17181749

1719-
if (unlikely(size != sizeof(struct bpf_tunnel_key) || flags))
1750+
if (unlikely(flags & ~(BPF_F_TUNINFO_IPV6)))
17201751
return -EINVAL;
1752+
if (unlikely(size != sizeof(struct bpf_tunnel_key))) {
1753+
switch (size) {
1754+
case offsetof(struct bpf_tunnel_key, remote_ipv6[1]):
1755+
/* Fixup deprecated structure layouts here, so we have
1756+
* a common path later on.
1757+
*/
1758+
memcpy(compat, from, size);
1759+
memset(compat + size, 0, sizeof(compat) - size);
1760+
from = (struct bpf_tunnel_key *)compat;
1761+
break;
1762+
default:
1763+
return -EINVAL;
1764+
}
1765+
}
17211766

17221767
skb_dst_drop(skb);
17231768
dst_hold((struct dst_entry *) md);
17241769
skb_dst_set(skb, (struct dst_entry *) md);
17251770

17261771
info = &md->u.tun_info;
17271772
info->mode = IP_TUNNEL_INFO_TX;
1773+
17281774
info->key.tun_flags = TUNNEL_KEY;
17291775
info->key.tun_id = cpu_to_be64(from->tunnel_id);
1730-
info->key.u.ipv4.dst = cpu_to_be32(from->remote_ipv4);
1776+
info->key.tos = from->tunnel_tos;
1777+
info->key.ttl = from->tunnel_ttl;
1778+
1779+
if (flags & BPF_F_TUNINFO_IPV6) {
1780+
info->mode |= IP_TUNNEL_INFO_IPV6;
1781+
memcpy(&info->key.u.ipv6.dst, from->remote_ipv6,
1782+
sizeof(from->remote_ipv6));
1783+
} else {
1784+
info->key.u.ipv4.dst = cpu_to_be32(from->remote_ipv4);
1785+
}
17311786

17321787
return 0;
17331788
}

0 commit comments

Comments
 (0)