Branch data 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/flavor.h>
13 : : #include <bpfilter/helper.h>
14 : : #include <bpfilter/logger.h>
15 : : #include <bpfilter/verdict.h>
16 : :
17 : : #include "cgen/program.h"
18 : : #include "cgen/stub.h"
19 : : #include "filter.h"
20 : :
21 : : /**
22 : : * Generate XDP program prologue.
23 : : *
24 : : * @warning @ref bf_stub_parse_l2_ethhdr will check for L3 protocol. If L3 is
25 : : * not IPv4, the program will be terminated.
26 : : *
27 : : * @param program Program to generate the prologue for. Must not be NULL.
28 : : * @return 0 on success, or negative errno value on error.
29 : : */
30 : 57 : static int _bf_xdp_gen_inline_prologue(struct bf_program *program)
31 : : {
32 : : int r;
33 : :
34 : : assert(program);
35 : :
36 : : // Calculate the packet size and store it into the runtime context
37 [ - + ]: 57 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
38 : : offsetof(struct xdp_md, data)));
39 [ - + ]: 57 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
40 : : offsetof(struct xdp_md, data_end)));
41 [ - + ]: 57 : EMIT(program, BPF_ALU64_REG(BPF_SUB, BPF_REG_3, BPF_REG_2));
42 [ - + ]: 57 : EMIT(program,
43 : : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_3, BF_PROG_CTX_OFF(pkt_size)));
44 : :
45 : : // Store the ingress ifindex into the runtime context
46 [ - + ]: 57 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
47 : : offsetof(struct xdp_md, ingress_ifindex)));
48 [ - + ]: 57 : EMIT(program,
49 : : BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, BF_PROG_CTX_OFF(ifindex)));
50 : :
51 : 57 : r = bf_stub_make_ctx_xdp_dynptr(program, BPF_REG_1);
52 [ + - ]: 57 : if (r)
53 : : return r;
54 : :
55 : 57 : r = bf_stub_parse_l2_ethhdr(program);
56 [ + - ]: 57 : if (r)
57 : : return r;
58 : :
59 : 57 : r = bf_stub_parse_l3_hdr(program);
60 [ + - ]: 57 : if (r)
61 : : return r;
62 : :
63 : 57 : r = bf_stub_parse_l4_hdr(program);
64 : : if (r)
65 : : return r;
66 : :
67 : : return 0;
68 : : }
69 : :
70 : 56 : static int _bf_xdp_gen_inline_epilogue(struct bf_program *program)
71 : : {
72 : : (void)program;
73 : :
74 : 56 : return 0;
75 : : }
76 : :
77 : : /**
78 : : * @brief Generate bytecode to redirect a packet using XDP.
79 : : *
80 : : * XDP redirect only supports egress direction - the packet is always
81 : : * transmitted out of the target interface. The BPF_F_INGRESS flag is
82 : : * ignored by XDP's bpf_redirect().
83 : : *
84 : : * @param program Program to generate bytecode for. Can't be NULL.
85 : : * @param ifindex Target interface index.
86 : : * @param dir Direction (must be BF_REDIRECT_EGRESS for XDP).
87 : : * @return 0 on success, or a negative errno value on failure.
88 : : */
89 : 4 : static int _bf_xdp_gen_inline_redirect(struct bf_program *program,
90 : : uint32_t ifindex,
91 : : enum bf_redirect_dir dir)
92 : : {
93 : : assert(program);
94 : :
95 [ + + ]: 4 : if (dir != BF_REDIRECT_EGRESS)
96 [ + - ]: 1 : return bf_err_r(-ENOTSUP, "XDP redirect only supports 'out' direction");
97 : :
98 : : // bpf_redirect(ifindex, flags) - flags are ignored for XDP
99 [ - + ]: 3 : EMIT(program, BPF_MOV64_IMM(BPF_REG_1, ifindex));
100 [ - + ]: 3 : EMIT(program, BPF_MOV64_IMM(BPF_REG_2, 0));
101 [ - + ]: 3 : EMIT(program, BPF_EMIT_CALL(BPF_FUNC_redirect));
102 : :
103 : : // Return value from bpf_redirect() is the action (XDP_REDIRECT on success)
104 [ - + ]: 3 : EMIT(program, BPF_EXIT_INSN());
105 : :
106 : 3 : return 0;
107 : : }
108 : :
109 : 341 : static int _bf_xdp_get_verdict(enum bf_verdict verdict)
110 : : {
111 [ + - + ]: 341 : switch (verdict) {
112 : : case BF_VERDICT_ACCEPT:
113 : : return XDP_PASS;
114 : 36 : case BF_VERDICT_DROP:
115 : 36 : return XDP_DROP;
116 : 0 : default:
117 : 0 : return -ENOTSUP;
118 : : }
119 : : }
120 : :
121 : : const struct bf_flavor_ops bf_flavor_ops_xdp = {
122 : : .gen_inline_prologue = _bf_xdp_gen_inline_prologue,
123 : : .gen_inline_epilogue = _bf_xdp_gen_inline_epilogue,
124 : : .gen_inline_redirect = _bf_xdp_gen_inline_redirect,
125 : : .get_verdict = _bf_xdp_get_verdict,
126 : : };
|