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