1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
/* SPDX-License-Identifier: GPL-2.0 */
divert(-1)
#forloop definition taken from example in the M4 manual
define(`forloop', `pushdef(`$1', `$2')_forloop($@)popdef(`$1')')
define(`_forloop',`$4`'ifelse($1, decr(`$3'), `', `define(`$1', incr($1))$0($@)')')
define(`NUM_PROGS',ifdef(`MAX_DISPATCHER_ACTIONS', MAX_DISPATCHER_ACTIONS, `10'))
divert(0)dnl
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
#include <xdp/prog_dispatcher.h>
/* While 'const volatile' sounds a little like an oxymoron, there's reason
* behind the madness:
*
* - const places the data in rodata, where libbpf will mark it as read-only and
* frozen on program load, letting the kernel do dead code elimination based
* on the values.
*
* - volatile prevents the compiler from optimising away the checks based on the
* compile-time value of the variables, which is important since we will be
* changing the values before loading the program into the kernel.
*/
static volatile const struct xdp_dispatcher_config conf = {};
/* The volatile return value prevents the compiler from assuming it knows the
* return value and optimising based on that.
*/
forloop(`i', `0', NUM_PROGS,
`__attribute__ ((noinline))
int format(`prog%d', i)(struct xdp_md *ctx) {
volatile int ret = XDP_DISPATCHER_RETVAL;
if (!ctx)
return XDP_ABORTED;
return ret;
}
')
__attribute__ ((noinline))
int compat_test(struct xdp_md *ctx) {
volatile int ret = XDP_DISPATCHER_RETVAL;
if (!ctx)
return XDP_ABORTED;
return ret;
}
SEC("xdp")
int xdp_dispatcher(struct xdp_md *ctx)
{
__u8 num_progs_enabled = conf.num_progs_enabled;
int ret;
forloop(`i', `0', NUM_PROGS,
`
if (num_progs_enabled < incr(i))
goto out;
ret = format(`prog%d', i)(ctx);
if (!((1U << ret) & conf.chain_call_actions[i]))
return ret;
')
/* keep a reference to the compat_test() function so we can use it
* as an freplace target in xdp_multiprog__check_compat() in libxdp
*/
if (num_progs_enabled < incr(NUM_PROGS))
goto out;
ret = compat_test(ctx);
out:
return XDP_PASS;
}
SEC("xdp")
int xdp_pass(struct xdp_md *ctx)
{
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
__uint(dispatcher_version, XDP_DISPATCHER_VERSION) SEC(XDP_METADATA_SECTION);
|