Skip to content

Commit 14ca075

Browse files
borkmanndavem330
authored andcommitted
bpf: support for access to tunnel options
After eBPF being able to programmatically access/manage tunnel key meta data via commit d3aa45c ("bpf: add helpers to access tunnel metadata") and more recently also for IPv6 through c6c3345 ("bpf: support ipv6 for bpf_skb_{set,get}_tunnel_key"), this work adds two complementary helpers to generically access their auxiliary tunnel options. Geneve and vxlan support this facility. For geneve, TLVs can be pushed, and for the vxlan case its GBP extension. I.e. setting tunnel key for geneve case only makes sense, if we can also read/write TLVs into it. In the GBP case, it provides the flexibility to easily map the group policy ID in combination with other helpers or maps. I chose to model this as two separate helpers, bpf_skb_{set,get}_tunnel_opt(), for a couple of reasons. bpf_skb_{set,get}_tunnel_key() is already rather complex by itself, and there may be cases for tunnel key backends where tunnel options are not always needed. If we would have integrated this into bpf_skb_{set,get}_tunnel_key() nevertheless, we are very limited with remaining helper arguments, so keeping compatibility on structs in case of passing in a flat buffer gets more cumbersome. Separating both also allows for more flexibility and future extensibility, f.e. options could be fed directly from a map, etc. Moreover, change geneve's xmit path to test only for info->options_len instead of TUNNEL_GENEVE_OPT flag. This makes it more consistent with vxlan's xmit path and allows for avoiding to specify a protocol flag in the API on xmit, so it can be protocol agnostic. Having info->options_len is enough information that is needed. Tested with vxlan and geneve. Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2208087 commit 14ca075

File tree

3 files changed

+90
-8
lines changed

3 files changed

+90
-8
lines changed

drivers/net/geneve.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,7 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
940940
u8 vni[3];
941941

942942
tunnel_id_to_vni(key->tun_id, vni);
943-
if (key->tun_flags & TUNNEL_GENEVE_OPT)
943+
if (info->options_len)
944944
opts = ip_tunnel_info_opts(info);
945945

946946
if (key->tun_flags & TUNNEL_CSUM)
@@ -1027,7 +1027,7 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
10271027
u8 vni[3];
10281028

10291029
tunnel_id_to_vni(key->tun_id, vni);
1030-
if (key->tun_flags & TUNNEL_GENEVE_OPT)
1030+
if (info->options_len)
10311031
opts = ip_tunnel_info_opts(info);
10321032

10331033
if (key->tun_flags & TUNNEL_CSUM)

include/uapi/linux/bpf.h

+11
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,17 @@ enum bpf_func_id {
298298
* Return: csum result
299299
*/
300300
BPF_FUNC_csum_diff,
301+
302+
/**
303+
* bpf_skb_[gs]et_tunnel_opt(skb, opt, size)
304+
* retrieve or populate tunnel options metadata
305+
* @skb: pointer to skb
306+
* @opt: pointer to raw tunnel option data
307+
* @size: size of @opt
308+
* Return: 0 on success for set, option size for get
309+
*/
310+
BPF_FUNC_skb_get_tunnel_opt,
311+
BPF_FUNC_skb_set_tunnel_opt,
301312
__BPF_FUNC_MAX_ID,
302313
};
303314

net/core/filter.c

+77-6
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,32 @@ static const struct bpf_func_proto bpf_skb_get_tunnel_key_proto = {
18091809
.arg4_type = ARG_ANYTHING,
18101810
};
18111811

1812+
static u64 bpf_skb_get_tunnel_opt(u64 r1, u64 r2, u64 size, u64 r4, u64 r5)
1813+
{
1814+
struct sk_buff *skb = (struct sk_buff *) (long) r1;
1815+
u8 *to = (u8 *) (long) r2;
1816+
const struct ip_tunnel_info *info = skb_tunnel_info(skb);
1817+
1818+
if (unlikely(!info ||
1819+
!(info->key.tun_flags & TUNNEL_OPTIONS_PRESENT)))
1820+
return -ENOENT;
1821+
if (unlikely(size < info->options_len))
1822+
return -ENOMEM;
1823+
1824+
ip_tunnel_info_opts_get(to, info);
1825+
1826+
return info->options_len;
1827+
}
1828+
1829+
static const struct bpf_func_proto bpf_skb_get_tunnel_opt_proto = {
1830+
.func = bpf_skb_get_tunnel_opt,
1831+
.gpl_only = false,
1832+
.ret_type = RET_INTEGER,
1833+
.arg1_type = ARG_PTR_TO_CTX,
1834+
.arg2_type = ARG_PTR_TO_STACK,
1835+
.arg3_type = ARG_CONST_STACK_SIZE,
1836+
};
1837+
18121838
static struct metadata_dst __percpu *md_dst;
18131839

18141840
static u64 bpf_skb_set_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
@@ -1875,17 +1901,58 @@ static const struct bpf_func_proto bpf_skb_set_tunnel_key_proto = {
18751901
.arg4_type = ARG_ANYTHING,
18761902
};
18771903

1878-
static const struct bpf_func_proto *bpf_get_skb_set_tunnel_key_proto(void)
1904+
#define BPF_TUNLEN_MAX 255
1905+
1906+
static u64 bpf_skb_set_tunnel_opt(u64 r1, u64 r2, u64 size, u64 r4, u64 r5)
1907+
{
1908+
struct sk_buff *skb = (struct sk_buff *) (long) r1;
1909+
u8 *from = (u8 *) (long) r2;
1910+
struct ip_tunnel_info *info = skb_tunnel_info(skb);
1911+
const struct metadata_dst *md = this_cpu_ptr(md_dst);
1912+
1913+
if (unlikely(info != &md->u.tun_info || (size & (sizeof(u32) - 1))))
1914+
return -EINVAL;
1915+
if (unlikely(size > BPF_TUNLEN_MAX))
1916+
return -ENOMEM;
1917+
1918+
ip_tunnel_info_opts_set(info, from, size);
1919+
1920+
return 0;
1921+
}
1922+
1923+
static const struct bpf_func_proto bpf_skb_set_tunnel_opt_proto = {
1924+
.func = bpf_skb_set_tunnel_opt,
1925+
.gpl_only = false,
1926+
.ret_type = RET_INTEGER,
1927+
.arg1_type = ARG_PTR_TO_CTX,
1928+
.arg2_type = ARG_PTR_TO_STACK,
1929+
.arg3_type = ARG_CONST_STACK_SIZE,
1930+
};
1931+
1932+
static const struct bpf_func_proto *
1933+
bpf_get_skb_set_tunnel_proto(enum bpf_func_id which)
18791934
{
18801935
if (!md_dst) {
1881-
/* race is not possible, since it's called from
1882-
* verifier that is holding verifier mutex
1936+
BUILD_BUG_ON(FIELD_SIZEOF(struct ip_tunnel_info,
1937+
options_len) != 1);
1938+
1939+
/* Race is not possible, since it's called from verifier
1940+
* that is holding verifier mutex.
18831941
*/
1884-
md_dst = metadata_dst_alloc_percpu(0, GFP_KERNEL);
1942+
md_dst = metadata_dst_alloc_percpu(BPF_TUNLEN_MAX,
1943+
GFP_KERNEL);
18851944
if (!md_dst)
18861945
return NULL;
18871946
}
1888-
return &bpf_skb_set_tunnel_key_proto;
1947+
1948+
switch (which) {
1949+
case BPF_FUNC_skb_set_tunnel_key:
1950+
return &bpf_skb_set_tunnel_key_proto;
1951+
case BPF_FUNC_skb_set_tunnel_opt:
1952+
return &bpf_skb_set_tunnel_opt_proto;
1953+
default:
1954+
return NULL;
1955+
}
18891956
}
18901957

18911958
static const struct bpf_func_proto *
@@ -1939,7 +2006,11 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
19392006
case BPF_FUNC_skb_get_tunnel_key:
19402007
return &bpf_skb_get_tunnel_key_proto;
19412008
case BPF_FUNC_skb_set_tunnel_key:
1942-
return bpf_get_skb_set_tunnel_key_proto();
2009+
return bpf_get_skb_set_tunnel_proto(func_id);
2010+
case BPF_FUNC_skb_get_tunnel_opt:
2011+
return &bpf_skb_get_tunnel_opt_proto;
2012+
case BPF_FUNC_skb_set_tunnel_opt:
2013+
return bpf_get_skb_set_tunnel_proto(func_id);
19432014
case BPF_FUNC_redirect:
19442015
return &bpf_redirect_proto;
19452016
case BPF_FUNC_get_route_realm:

0 commit comments

Comments
 (0)