Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-only */
2 : /*
3 : * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4 : */
5 :
6 : #include <linux/bpf.h>
7 : #include <linux/bpf_common.h>
8 :
9 : #include <stddef.h>
10 : #include <stdint.h>
11 :
12 : #include "bpfilter/cgen/program.h"
13 : #include "bpfilter/cgen/stub.h"
14 : #include "core/flavor.h"
15 : #include "core/helper.h"
16 : #include "core/verdict.h"
17 :
18 : #include "external/filter.h"
19 :
20 : /**
21 : * Generate XDP program prologue.
22 : *
23 : * @warning @ref bf_stub_parse_l2_ethhdr will check for L3 protocol. If L3 is
24 : * not IPv4, the program will be terminated.
25 : *
26 : * @param program Program to generate the prologue for. Must not be NULL.
27 : * @return 0 on success, or negative errno value on error.
28 : */
29 0 : static int _bf_xdp_gen_inline_prologue(struct bf_program *program)
30 : {
31 : int r;
32 :
33 0 : bf_assert(program);
34 :
35 : // Calculate the packet size and store it into the runtime context
36 0 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
37 : offsetof(struct xdp_md, data)));
38 0 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
39 : offsetof(struct xdp_md, data_end)));
40 0 : EMIT(program, BPF_ALU64_REG(BPF_SUB, BPF_REG_3, BPF_REG_2));
41 0 : EMIT(program,
42 : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_3, BF_PROG_CTX_OFF(pkt_size)));
43 :
44 : // Store the ingress ifindex into the runtime context
45 0 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
46 : offsetof(struct xdp_md, ingress_ifindex)));
47 0 : EMIT(program,
48 : BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, BF_PROG_CTX_OFF(ifindex)));
49 :
50 0 : r = bf_stub_make_ctx_xdp_dynptr(program, BPF_REG_1);
51 0 : if (r)
52 : return r;
53 :
54 0 : r = bf_stub_parse_l2_ethhdr(program);
55 0 : if (r)
56 : return r;
57 :
58 0 : r = bf_stub_parse_l3_hdr(program);
59 0 : if (r)
60 : return r;
61 :
62 0 : r = bf_stub_parse_l4_hdr(program);
63 : if (r)
64 : return r;
65 :
66 : return 0;
67 : }
68 :
69 0 : static int _bf_xdp_gen_inline_epilogue(struct bf_program *program)
70 : {
71 : UNUSED(program);
72 :
73 0 : return 0;
74 : }
75 :
76 0 : static int _bf_xdp_get_verdict(enum bf_verdict verdict)
77 : {
78 0 : bf_assert(0 <= verdict && verdict < _BF_TERMINAL_VERDICT_MAX);
79 :
80 : static const int verdicts[] = {
81 : [BF_VERDICT_ACCEPT] = XDP_PASS,
82 : [BF_VERDICT_DROP] = XDP_DROP,
83 : };
84 :
85 : static_assert(ARRAY_SIZE(verdicts) == _BF_TERMINAL_VERDICT_MAX);
86 :
87 0 : return verdicts[verdict];
88 : }
89 :
90 : const struct bf_flavor_ops bf_flavor_ops_xdp = {
91 : .gen_inline_prologue = _bf_xdp_gen_inline_prologue,
92 : .gen_inline_epilogue = _bf_xdp_gen_inline_epilogue,
93 : .get_verdict = _bf_xdp_get_verdict,
94 : };
|