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