Commit 12bed760 authored by Eyal Birger's avatar Eyal Birger Committed by Daniel Borkmann

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: default avatarEyal Birger <eyal.birger@gmail.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parent fbcf93eb
...@@ -774,6 +774,15 @@ union bpf_attr { ...@@ -774,6 +774,15 @@ union bpf_attr {
* @xdp_md: pointer to xdp_md * @xdp_md: pointer to xdp_md
* @delta: A negative integer to be added to xdp_md.data_end * @delta: A negative integer to be added to xdp_md.data_end
* Return: 0 on success or negative on error * Return: 0 on success or negative on error
*
* int bpf_skb_get_xfrm_state(skb, index, xfrm_state, size, flags)
* retrieve XFRM state
* @skb: pointer to skb
* @index: index of the xfrm state in the secpath
* @key: pointer to 'struct bpf_xfrm_state'
* @size: size of 'struct bpf_xfrm_state'
* @flags: room for future extensions
* Return: 0 on success or negative error
*/ */
#define __BPF_FUNC_MAPPER(FN) \ #define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \ FN(unspec), \
...@@ -841,7 +850,8 @@ union bpf_attr { ...@@ -841,7 +850,8 @@ union bpf_attr {
FN(msg_cork_bytes), \ FN(msg_cork_bytes), \
FN(msg_pull_data), \ FN(msg_pull_data), \
FN(bind), \ FN(bind), \
FN(xdp_adjust_tail), FN(xdp_adjust_tail), \
FN(skb_get_xfrm_state),
/* integer value in 'imm' field of BPF_CALL instruction selects which helper /* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call * function eBPF program intends to call
...@@ -947,6 +957,19 @@ struct bpf_tunnel_key { ...@@ -947,6 +957,19 @@ struct bpf_tunnel_key {
__u32 tunnel_label; __u32 tunnel_label;
}; };
/* user accessible mirror of in-kernel xfrm_state.
* new fields can only be added to the end of this structure
*/
struct bpf_xfrm_state {
__u32 reqid;
__u32 spi; /* Stored in network byte order */
__u16 family;
union {
__u32 remote_ipv4; /* Stored in network byte order */
__u32 remote_ipv6[4]; /* Stored in network byte order */
};
};
/* Generic BPF return codes which all BPF program types may support. /* Generic BPF return codes which all BPF program types may support.
* The values are binary compatible with their TC_ACT_* counter-part to * The values are binary compatible with their TC_ACT_* counter-part to
* provide backwards compatibility with existing SCHED_CLS and SCHED_ACT * provide backwards compatibility with existing SCHED_CLS and SCHED_ACT
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#include <net/sock_reuseport.h> #include <net/sock_reuseport.h>
#include <net/busy_poll.h> #include <net/busy_poll.h>
#include <net/tcp.h> #include <net/tcp.h>
#include <net/xfrm.h>
#include <linux/bpf_trace.h> #include <linux/bpf_trace.h>
/** /**
...@@ -3743,6 +3744,49 @@ static const struct bpf_func_proto bpf_bind_proto = { ...@@ -3743,6 +3744,49 @@ static const struct bpf_func_proto bpf_bind_proto = {
.arg3_type = ARG_CONST_SIZE, .arg3_type = ARG_CONST_SIZE,
}; };
#ifdef CONFIG_XFRM
BPF_CALL_5(bpf_skb_get_xfrm_state, struct sk_buff *, skb, u32, index,
struct bpf_xfrm_state *, to, u32, size, u64, flags)
{
const struct sec_path *sp = skb_sec_path(skb);
const struct xfrm_state *x;
if (!sp || unlikely(index >= sp->len || flags))
goto err_clear;
x = sp->xvec[index];
if (unlikely(size != sizeof(struct bpf_xfrm_state)))
goto err_clear;
to->reqid = x->props.reqid;
to->spi = x->id.spi;
to->family = x->props.family;
if (to->family == AF_INET6) {
memcpy(to->remote_ipv6, x->props.saddr.a6,
sizeof(to->remote_ipv6));
} else {
to->remote_ipv4 = x->props.saddr.a4;
}
return 0;
err_clear:
memset(to, 0, size);
return -EINVAL;
}
static const struct bpf_func_proto bpf_skb_get_xfrm_state_proto = {
.func = bpf_skb_get_xfrm_state,
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_ANYTHING,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_CONST_SIZE,
.arg5_type = ARG_ANYTHING,
};
#endif
static const struct bpf_func_proto * static const struct bpf_func_proto *
bpf_base_func_proto(enum bpf_func_id func_id) bpf_base_func_proto(enum bpf_func_id func_id)
{ {
...@@ -3884,6 +3928,10 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) ...@@ -3884,6 +3928,10 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
return &bpf_get_socket_cookie_proto; return &bpf_get_socket_cookie_proto;
case BPF_FUNC_get_socket_uid: case BPF_FUNC_get_socket_uid:
return &bpf_get_socket_uid_proto; return &bpf_get_socket_uid_proto;
#ifdef CONFIG_XFRM
case BPF_FUNC_skb_get_xfrm_state:
return &bpf_skb_get_xfrm_state_proto;
#endif
default: default:
return bpf_base_func_proto(func_id); return bpf_base_func_proto(func_id);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment