Skip to content

Commit 12bed76

Browse files
ebirgerborkmann
authored andcommitted
bpf: add helper for getting xfrm states
This commit introduces a helper which allows fetching xfrm state parameters by eBPF programs attached to TC. Prototype: bpf_skb_get_xfrm_state(skb, index, xfrm_state, size, flags) skb: pointer to skb index: the index in the skb xfrm_state secpath array xfrm_state: pointer to 'struct bpf_xfrm_state' size: size of 'struct bpf_xfrm_state' flags: reserved for future extensions The helper returns 0 on success. Non zero if no xfrm state at the index is found - or non exists at all. struct bpf_xfrm_state currently includes the SPI, peer IPv4/IPv6 address and the reqid; it can be further extended by adding elements to its end - indicating the populated fields by the 'size' argument - keeping backwards compatibility. Typical usage: struct bpf_xfrm_state x = {}; bpf_skb_get_xfrm_state(skb, 0, &x, sizeof(x), 0); ... Signed-off-by: Eyal Birger <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]>
1 parent fbcf93e commit 12bed76

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

include/uapi/linux/bpf.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,15 @@ union bpf_attr {
774774
* @xdp_md: pointer to xdp_md
775775
* @delta: A negative integer to be added to xdp_md.data_end
776776
* Return: 0 on success or negative on error
777+
*
778+
* int bpf_skb_get_xfrm_state(skb, index, xfrm_state, size, flags)
779+
* retrieve XFRM state
780+
* @skb: pointer to skb
781+
* @index: index of the xfrm state in the secpath
782+
* @key: pointer to 'struct bpf_xfrm_state'
783+
* @size: size of 'struct bpf_xfrm_state'
784+
* @flags: room for future extensions
785+
* Return: 0 on success or negative error
777786
*/
778787
#define __BPF_FUNC_MAPPER(FN) \
779788
FN(unspec), \
@@ -841,7 +850,8 @@ union bpf_attr {
841850
FN(msg_cork_bytes), \
842851
FN(msg_pull_data), \
843852
FN(bind), \
844-
FN(xdp_adjust_tail),
853+
FN(xdp_adjust_tail), \
854+
FN(skb_get_xfrm_state),
845855

846856
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
847857
* function eBPF program intends to call
@@ -947,6 +957,19 @@ struct bpf_tunnel_key {
947957
__u32 tunnel_label;
948958
};
949959

960+
/* user accessible mirror of in-kernel xfrm_state.
961+
* new fields can only be added to the end of this structure
962+
*/
963+
struct bpf_xfrm_state {
964+
__u32 reqid;
965+
__u32 spi; /* Stored in network byte order */
966+
__u16 family;
967+
union {
968+
__u32 remote_ipv4; /* Stored in network byte order */
969+
__u32 remote_ipv6[4]; /* Stored in network byte order */
970+
};
971+
};
972+
950973
/* Generic BPF return codes which all BPF program types may support.
951974
* The values are binary compatible with their TC_ACT_* counter-part to
952975
* provide backwards compatibility with existing SCHED_CLS and SCHED_ACT

net/core/filter.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include <net/sock_reuseport.h>
5858
#include <net/busy_poll.h>
5959
#include <net/tcp.h>
60+
#include <net/xfrm.h>
6061
#include <linux/bpf_trace.h>
6162

6263
/**
@@ -3743,6 +3744,49 @@ static const struct bpf_func_proto bpf_bind_proto = {
37433744
.arg3_type = ARG_CONST_SIZE,
37443745
};
37453746

3747+
#ifdef CONFIG_XFRM
3748+
BPF_CALL_5(bpf_skb_get_xfrm_state, struct sk_buff *, skb, u32, index,
3749+
struct bpf_xfrm_state *, to, u32, size, u64, flags)
3750+
{
3751+
const struct sec_path *sp = skb_sec_path(skb);
3752+
const struct xfrm_state *x;
3753+
3754+
if (!sp || unlikely(index >= sp->len || flags))
3755+
goto err_clear;
3756+
3757+
x = sp->xvec[index];
3758+
3759+
if (unlikely(size != sizeof(struct bpf_xfrm_state)))
3760+
goto err_clear;
3761+
3762+
to->reqid = x->props.reqid;
3763+
to->spi = x->id.spi;
3764+
to->family = x->props.family;
3765+
if (to->family == AF_INET6) {
3766+
memcpy(to->remote_ipv6, x->props.saddr.a6,
3767+
sizeof(to->remote_ipv6));
3768+
} else {
3769+
to->remote_ipv4 = x->props.saddr.a4;
3770+
}
3771+
3772+
return 0;
3773+
err_clear:
3774+
memset(to, 0, size);
3775+
return -EINVAL;
3776+
}
3777+
3778+
static const struct bpf_func_proto bpf_skb_get_xfrm_state_proto = {
3779+
.func = bpf_skb_get_xfrm_state,
3780+
.gpl_only = false,
3781+
.ret_type = RET_INTEGER,
3782+
.arg1_type = ARG_PTR_TO_CTX,
3783+
.arg2_type = ARG_ANYTHING,
3784+
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
3785+
.arg4_type = ARG_CONST_SIZE,
3786+
.arg5_type = ARG_ANYTHING,
3787+
};
3788+
#endif
3789+
37463790
static const struct bpf_func_proto *
37473791
bpf_base_func_proto(enum bpf_func_id func_id)
37483792
{
@@ -3884,6 +3928,10 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
38843928
return &bpf_get_socket_cookie_proto;
38853929
case BPF_FUNC_get_socket_uid:
38863930
return &bpf_get_socket_uid_proto;
3931+
#ifdef CONFIG_XFRM
3932+
case BPF_FUNC_skb_get_xfrm_state:
3933+
return &bpf_skb_get_xfrm_state_proto;
3934+
#endif
38873935
default:
38883936
return bpf_base_func_proto(func_id);
38893937
}

0 commit comments

Comments
 (0)