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/stub.h"
7 : :
8 : : #include <linux/bpf.h>
9 : : #include <linux/bpf_common.h>
10 : : #include <linux/icmp.h>
11 : : #include <linux/icmpv6.h>
12 : : #include <linux/if_ether.h>
13 : : #include <linux/in.h> // NOLINT
14 : : #include <linux/in6.h>
15 : : #include <linux/ip.h>
16 : : #include <linux/ipv6.h>
17 : : #include <linux/tcp.h>
18 : : #include <linux/udp.h>
19 : :
20 : : #include <endian.h>
21 : : #include <stddef.h>
22 : :
23 : : #include <bpfilter/flavor.h>
24 : : #include <bpfilter/helper.h>
25 : : #include <bpfilter/matcher.h>
26 : : #include <bpfilter/verdict.h>
27 : :
28 : : #include "cgen/elfstub.h"
29 : : #include "cgen/jmp.h"
30 : : #include "cgen/printer.h"
31 : : #include "cgen/program.h"
32 : : #include "cgen/swich.h"
33 : : #include "filter.h"
34 : : #include "opts.h"
35 : :
36 : : #define _BF_LOW_EH_BITMASK 0x1801800000000801ULL
37 : :
38 : : /**
39 : : * Generate stub to create a dynptr.
40 : : *
41 : : * @param program Program to generate the stub for. Must not be NULL.
42 : : * @param arg_reg Register where the first argument to the dynptr creation
43 : : * function is located (SKB or xdp_md structure).
44 : : * @param kfunc Name of the kfunc to use to create the dynamic pointer.
45 : : * @return 0 on success, or negative errno value on error.
46 : : */
47 : 64 : static int _bf_stub_make_ctx_dynptr(struct bf_program *program, int arg_reg,
48 : : const char *kfunc)
49 : : {
50 : : int r;
51 : :
52 : : assert(program);
53 : : assert(kfunc);
54 : :
55 : : // Call bpf_dynptr_from_xxx()
56 [ - + ]: 64 : if (arg_reg != BPF_REG_1)
57 [ # # ]: 0 : EMIT(program, BPF_MOV64_IMM(BPF_REG_1, arg_reg));
58 [ - + ]: 64 : EMIT(program, BPF_MOV64_IMM(BPF_REG_2, 0));
59 [ - + ]: 64 : EMIT(program, BPF_MOV64_REG(BPF_REG_3, BPF_REG_10));
60 [ - + ]: 64 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, BF_PROG_CTX_OFF(dynptr)));
61 [ + - ]: 64 : EMIT_KFUNC_CALL(program, kfunc);
62 : :
63 : : // If the function call failed, quit the program
64 : : {
65 : 64 : _clean_bf_jmpctx_ struct bf_jmpctx _ =
66 [ - + ]: 64 : bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
67 : :
68 : : // Update the error counter
69 [ - + ]: 64 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
70 [ - + ]: 64 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
71 [ + - + - ]: 64 : EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
72 [ - + ]: 64 : EMIT(program,
73 : : BPF_MOV32_IMM(BPF_REG_3, bf_program_error_counter_idx(program)));
74 [ + - ]: 64 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
75 : :
76 [ - + ]: 64 : if (bf_opts_is_verbose(BF_VERBOSE_BPF))
77 [ # # # # : 0 : EMIT_PRINT(program, "failed to create a new dynamic pointer");
# # # # ]
78 : :
79 : 64 : r = program->runtime.ops->get_verdict(BF_VERDICT_ACCEPT);
80 [ + - ]: 64 : if (r < 0)
81 : : return r;
82 [ - + ]: 64 : EMIT(program, BPF_MOV64_IMM(BPF_REG_0, r));
83 [ - + ]: 64 : EMIT(program, BPF_EXIT_INSN());
84 : : }
85 : :
86 : 64 : return 0;
87 : : }
88 : :
89 : 34 : int bf_stub_make_ctx_xdp_dynptr(struct bf_program *program, int md_reg)
90 : : {
91 : : assert(program);
92 : :
93 : 34 : return _bf_stub_make_ctx_dynptr(program, md_reg, "bpf_dynptr_from_xdp");
94 : : }
95 : :
96 : 30 : int bf_stub_make_ctx_skb_dynptr(struct bf_program *program, int skb_reg)
97 : : {
98 : : assert(program);
99 : :
100 : 30 : return _bf_stub_make_ctx_dynptr(program, skb_reg, "bpf_dynptr_from_skb");
101 : : }
102 : :
103 : 45 : int bf_stub_parse_l2_ethhdr(struct bf_program *program)
104 : : {
105 : : int r;
106 : :
107 : : assert(program);
108 : :
109 : : // Call bpf_dynptr_slice()
110 [ - + ]: 45 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
111 [ - + ]: 45 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(dynptr)));
112 [ - + ]: 45 : EMIT(program, BPF_MOV64_IMM(BPF_REG_2, 0));
113 [ - + ]: 45 : EMIT(program, BPF_MOV64_REG(BPF_REG_3, BPF_REG_10));
114 [ - + ]: 45 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, BF_PROG_CTX_OFF(l2)));
115 [ - + ]: 45 : EMIT(program, BPF_MOV64_IMM(BPF_REG_4, sizeof(struct ethhdr)));
116 : :
117 [ - + ]: 45 : EMIT(program,
118 : : BPF_STX_MEM(BPF_B, BPF_REG_10, BPF_REG_4, BF_PROG_CTX_OFF(l2_size)));
119 : :
120 [ + - ]: 45 : EMIT_KFUNC_CALL(program, "bpf_dynptr_slice");
121 : :
122 : : // If the function call failed, quit the program
123 : : {
124 : 45 : _clean_bf_jmpctx_ struct bf_jmpctx _ =
125 [ - + ]: 45 : bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 0));
126 : :
127 : : // Update the error counter
128 [ - + ]: 45 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
129 [ - + ]: 45 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
130 [ + - + - ]: 45 : EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
131 [ - + ]: 45 : EMIT(program,
132 : : BPF_MOV32_IMM(BPF_REG_3, bf_program_error_counter_idx(program)));
133 [ + - ]: 45 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
134 : :
135 [ - + ]: 45 : if (bf_opts_is_verbose(BF_VERBOSE_BPF))
136 [ # # # # : 0 : EMIT_PRINT(program, "failed to create L2 dynamic pointer slice");
# # # # ]
137 : :
138 : 45 : r = program->runtime.ops->get_verdict(BF_VERDICT_ACCEPT);
139 [ + - ]: 45 : if (r < 0)
140 : : return r;
141 [ - + ]: 45 : EMIT(program, BPF_MOV64_IMM(BPF_REG_0, r));
142 [ - + ]: 45 : EMIT(program, BPF_EXIT_INSN());
143 : : }
144 : :
145 : : // Store the L2 header address into the runtime context
146 [ - + ]: 45 : EMIT(program,
147 : : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, BF_PROG_CTX_OFF(l2_hdr)));
148 : :
149 : : // Store the L3 protocol ID in r7
150 [ - + ]: 45 : EMIT(program, BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_0,
151 : : offsetof(struct ethhdr, h_proto)));
152 : :
153 : : // Set bf_runtime.l3_offset
154 [ - + ]: 45 : EMIT(program, BPF_ST_MEM(BPF_W, BPF_REG_10, BF_PROG_CTX_OFF(l3_offset),
155 : : sizeof(struct ethhdr)));
156 : :
157 : 45 : return 0;
158 : : }
159 : :
160 : 64 : int bf_stub_parse_l3_hdr(struct bf_program *program)
161 : : {
162 : 64 : _clean_bf_jmpctx_ struct bf_jmpctx _ = bf_jmpctx_default();
163 : : int r;
164 : :
165 : : assert(program);
166 : :
167 : : /* Store the size of the L3 protocol header in r4, depending on the protocol
168 : : * ID stored in r7. If the protocol is not supported, we store 0 into r7
169 : : * and we skip the instructions below. */
170 : : {
171 : 64 : _clean_bf_swich_ struct bf_swich swich =
172 [ - + ]: 64 : bf_swich_get(program, BPF_REG_7);
173 : :
174 [ - + ]: 64 : EMIT_SWICH_OPTION(&swich, htobe16(ETH_P_IP),
175 : : BPF_MOV64_IMM(BPF_REG_4, sizeof(struct iphdr)));
176 [ - + ]: 64 : EMIT_SWICH_OPTION(&swich, htobe16(ETH_P_IPV6),
177 : : BPF_MOV64_IMM(BPF_REG_4, sizeof(struct ipv6hdr)));
178 [ - + ]: 64 : EMIT_SWICH_DEFAULT(&swich, BPF_MOV64_IMM(BPF_REG_7, 0));
179 : :
180 : 64 : r = bf_swich_generate(&swich);
181 [ + - ]: 64 : if (r)
182 : : return r;
183 : : }
184 [ - + ]: 64 : _ = bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_7, 0, 0));
185 : :
186 [ - + ]: 64 : EMIT(program,
187 : : BPF_STX_MEM(BPF_B, BPF_REG_10, BPF_REG_4, BF_PROG_CTX_OFF(l3_size)));
188 : :
189 : : // Call bpf_dynptr_slice()
190 [ - + ]: 64 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
191 [ - + ]: 64 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(dynptr)));
192 [ - + ]: 64 : EMIT(program,
193 : : BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_10, BF_PROG_CTX_OFF(l3_offset)));
194 [ - + ]: 64 : EMIT(program, BPF_MOV64_REG(BPF_REG_3, BPF_REG_10));
195 [ - + ]: 64 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, BF_PROG_CTX_OFF(l2)));
196 [ + - ]: 64 : EMIT_KFUNC_CALL(program, "bpf_dynptr_slice");
197 : :
198 : : // If the function call failed, quit the program
199 : : {
200 : 64 : _clean_bf_jmpctx_ struct bf_jmpctx _ =
201 [ - + ]: 64 : bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 0));
202 : :
203 [ - + ]: 64 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
204 [ - + ]: 64 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
205 [ + - + - ]: 64 : EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
206 [ - + ]: 64 : EMIT(program,
207 : : BPF_MOV32_IMM(BPF_REG_3, bf_program_error_counter_idx(program)));
208 [ + - ]: 64 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
209 : :
210 [ - + ]: 64 : if (bf_opts_is_verbose(BF_VERBOSE_BPF))
211 [ # # # # : 0 : EMIT_PRINT(program, "failed to create L3 dynamic pointer slice");
# # # # ]
212 : :
213 : 64 : r = program->runtime.ops->get_verdict(BF_VERDICT_ACCEPT);
214 [ + - ]: 64 : if (r < 0)
215 : : return r;
216 [ - + ]: 64 : EMIT(program, BPF_MOV64_IMM(BPF_REG_0, r));
217 [ - + ]: 64 : EMIT(program, BPF_EXIT_INSN());
218 : : }
219 : :
220 : : // Store the L3 header address into the runtime context
221 [ - + ]: 64 : EMIT(program,
222 : : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, BF_PROG_CTX_OFF(l3_hdr)));
223 : :
224 : : /* Unsupported L3 protocols have been filtered out at the beginning of this
225 : : * function and would jump over the block below, so there is no need to
226 : : * worry about them here. */
227 : : {
228 : : // IPv4
229 [ - + ]: 128 : _clean_bf_jmpctx_ struct bf_jmpctx _ = bf_jmpctx_get(
230 : : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IP), 0));
231 : :
232 [ - + ]: 64 : EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0));
233 [ - + ]: 64 : EMIT(program, BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x0f));
234 [ - + ]: 64 : EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 2));
235 [ - + ]: 64 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_10,
236 : : BF_PROG_CTX_OFF(l3_offset)));
237 [ - + ]: 64 : EMIT(program, BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2));
238 [ - + ]: 64 : EMIT(program, BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_1,
239 : : BF_PROG_CTX_OFF(l4_offset)));
240 [ - + ]: 64 : EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_0,
241 : : offsetof(struct iphdr, protocol)));
242 : : }
243 : :
244 : : {
245 : : // IPv6
246 : : struct bf_jmpctx tcpjmp, udpjmp, noehjmp, ehjmp;
247 : 64 : struct bpf_insn ld64[2] = {BPF_LD_IMM64(BPF_REG_2, _BF_LOW_EH_BITMASK)};
248 [ - + ]: 128 : _clean_bf_jmpctx_ struct bf_jmpctx _ = bf_jmpctx_get(
249 : : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IPV6), 0));
250 : :
251 [ - + ]: 64 : EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_0,
252 : : offsetof(struct ipv6hdr, nexthdr)));
253 : :
254 : : /* Fast path for TCP and UDP: quickly recognize the most used protocol
255 : : * to process them as fast as possible. */
256 [ - + ]: 64 : tcpjmp = bf_jmpctx_get(program,
257 : : BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, IPPROTO_TCP, 0));
258 [ - + ]: 64 : udpjmp = bf_jmpctx_get(program,
259 : : BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, IPPROTO_UDP, 0));
260 : :
261 : : /* For all the EH protocol numbers <64, use a bitmask:
262 : : * mask = (1<<0) | (1<<43) | (1<<44) | (1<<50) | (1<<51) | (1<<60)
263 : : *
264 : : * Pseudo-code:
265 : : * - r3 = 1 << r8 (nexthdr)
266 : : * - r3 = r3 & mask
267 : : * - if r3 != 0: go to slow path (EH present) */
268 [ + - ]: 64 : EMIT(program, ld64[0]);
269 [ + - ]: 64 : EMIT(program, ld64[1]);
270 [ - + ]: 64 : EMIT(program, BPF_JMP_IMM(BPF_JGE, BPF_REG_8, 64, 4));
271 [ - + ]: 64 : EMIT(program, BPF_MOV64_IMM(BPF_REG_3, 1));
272 [ - + ]: 64 : EMIT(program, BPF_ALU64_REG(BPF_LSH, BPF_REG_3, BPF_REG_8));
273 [ - + ]: 64 : EMIT(program, BPF_ALU64_REG(BPF_AND, BPF_REG_3, BPF_REG_2));
274 [ - + ]: 64 : EMIT(program, BPF_JMP_IMM(BPF_JNE, BPF_REG_3, 0, 4));
275 : :
276 : : // EH with protocol numbers >64 are processed individually
277 [ - + ]: 64 : EMIT(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, 135, 3));
278 [ - + ]: 64 : EMIT(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, 139, 2));
279 [ - + ]: 64 : EMIT(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, 140, 1));
280 : :
281 : : // If no EH matched, nexthdr is L4, skip EH processing
282 [ - + ]: 64 : noehjmp = bf_jmpctx_get(program, BPF_JMP_A(0));
283 : :
284 : : // Process EH
285 [ - + ]: 64 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
286 [ - + ]: 64 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
287 : : // If any rule filters on ipv6.nexthdr, store the EH in the runtime context
288 : : // during process, so we won't have to process the EH again.
289 [ + + ]: 64 : if (program->runtime.chain->flags & BF_FLAG(BF_CHAIN_STORE_NEXTHDR))
290 [ + - ]: 10 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_PARSE_IPV6_NH);
291 : : else
292 [ + - ]: 54 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_PARSE_IPV6_EH);
293 [ - + ]: 64 : EMIT(program, BPF_MOV64_REG(BPF_REG_8, BPF_REG_0));
294 : :
295 [ - + ]: 64 : ehjmp = bf_jmpctx_get(program, BPF_JMP_A(0));
296 : :
297 : : // If no EH found, all the jmp will end up here
298 : 64 : bf_jmpctx_cleanup(&tcpjmp);
299 : 64 : bf_jmpctx_cleanup(&udpjmp);
300 : 64 : bf_jmpctx_cleanup(&noehjmp);
301 : :
302 : : // Process IPv6 header, no EH (BPF_REG_8 already contains nexthdr)
303 [ - + ]: 64 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_10,
304 : : BF_PROG_CTX_OFF(l3_offset)));
305 [ - + ]: 64 : EMIT(program,
306 : : BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, sizeof(struct ipv6hdr)));
307 [ - + ]: 64 : EMIT(program, BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2,
308 : : BF_PROG_CTX_OFF(l4_offset)));
309 : :
310 : 64 : bf_jmpctx_cleanup(&ehjmp);
311 : : }
312 : :
313 : 64 : return 0;
314 : : }
315 : :
316 : 64 : int bf_stub_parse_l4_hdr(struct bf_program *program)
317 : : {
318 : 64 : _clean_bf_jmpctx_ struct bf_jmpctx _ = bf_jmpctx_default();
319 : : int r;
320 : :
321 : : assert(program);
322 : :
323 : : /* Parse the L4 protocol and handle unuspported protocol, similarly to
324 : : * bf_stub_parse_l3_hdr() above. */
325 : : {
326 : 64 : _clean_bf_swich_ struct bf_swich swich =
327 [ - + ]: 64 : bf_swich_get(program, BPF_REG_8);
328 : :
329 [ - + ]: 64 : EMIT_SWICH_OPTION(&swich, IPPROTO_TCP,
330 : : BPF_MOV64_IMM(BPF_REG_4, sizeof(struct tcphdr)));
331 [ - + ]: 64 : EMIT_SWICH_OPTION(&swich, IPPROTO_UDP,
332 : : BPF_MOV64_IMM(BPF_REG_4, sizeof(struct udphdr)));
333 [ - + ]: 64 : EMIT_SWICH_OPTION(&swich, IPPROTO_ICMP,
334 : : BPF_MOV64_IMM(BPF_REG_4, sizeof(struct icmphdr)));
335 [ - + ]: 64 : EMIT_SWICH_OPTION(&swich, IPPROTO_ICMPV6,
336 : : BPF_MOV64_IMM(BPF_REG_4, sizeof(struct icmp6hdr)));
337 [ - + ]: 64 : EMIT_SWICH_DEFAULT(&swich, BPF_MOV64_IMM(BPF_REG_8, 0));
338 : :
339 : 64 : r = bf_swich_generate(&swich);
340 [ + - ]: 64 : if (r)
341 : : return r;
342 : : }
343 [ - + ]: 64 : _ = bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, 0, 0));
344 : :
345 [ - + ]: 64 : EMIT(program,
346 : : BPF_STX_MEM(BPF_B, BPF_REG_10, BPF_REG_4, BF_PROG_CTX_OFF(l4_size)));
347 : :
348 : : // Call bpf_dynptr_slice()
349 [ - + ]: 64 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
350 [ - + ]: 64 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(dynptr)));
351 [ - + ]: 64 : EMIT(program,
352 : : BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_10, BF_PROG_CTX_OFF(l4_offset)));
353 [ - + ]: 64 : EMIT(program, BPF_MOV64_REG(BPF_REG_3, BPF_REG_10));
354 [ - + ]: 64 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, BF_PROG_CTX_OFF(l4)));
355 [ + - ]: 64 : EMIT_KFUNC_CALL(program, "bpf_dynptr_slice");
356 : :
357 : : // If the function call failed, quit the program
358 : : {
359 : 64 : _clean_bf_jmpctx_ struct bf_jmpctx _ =
360 [ - + ]: 64 : bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 0));
361 : :
362 [ - + ]: 64 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
363 [ - + ]: 64 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
364 [ + - + - ]: 64 : EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
365 [ - + ]: 64 : EMIT(program,
366 : : BPF_MOV32_IMM(BPF_REG_3, bf_program_error_counter_idx(program)));
367 [ + - ]: 64 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
368 : :
369 [ - + ]: 64 : if (bf_opts_is_verbose(BF_VERBOSE_BPF))
370 [ # # # # : 0 : EMIT_PRINT(program, "failed to create L4 dynamic pointer slice");
# # # # ]
371 : :
372 : 64 : r = program->runtime.ops->get_verdict(BF_VERDICT_ACCEPT);
373 [ + - ]: 64 : if (r < 0)
374 : : return r;
375 [ - + ]: 64 : EMIT(program, BPF_MOV64_IMM(BPF_REG_0, r));
376 [ - + ]: 64 : EMIT(program, BPF_EXIT_INSN());
377 : : }
378 : :
379 : : // Store the L4 header address into the runtime context
380 [ - + ]: 64 : EMIT(program,
381 : : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, BF_PROG_CTX_OFF(l4_hdr)));
382 : :
383 : 64 : return 0;
384 : : }
385 : :
386 : 100 : int bf_stub_rule_check_protocol(struct bf_program *program,
387 : : const struct bf_matcher_meta *meta)
388 : : {
389 : : assert(program);
390 : : assert(meta);
391 : :
392 [ + + - ]: 100 : switch (meta->layer) {
393 : 60 : case BF_MATCHER_LAYER_3:
394 [ - + ]: 60 : EMIT_FIXUP_JMP_NEXT_RULE(
395 : : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
396 : : htobe16((uint16_t)meta->hdr_id), 0));
397 : 60 : break;
398 : 40 : case BF_MATCHER_LAYER_4:
399 [ - + ]: 40 : EMIT_FIXUP_JMP_NEXT_RULE(
400 : : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_8, (uint8_t)meta->hdr_id, 0));
401 : 40 : break;
402 : 0 : default:
403 [ # # ]: 0 : return bf_err_r(-EINVAL, "rule can't check for layer ID %d",
404 : : meta->layer);
405 : : }
406 : :
407 : : return 0;
408 : : }
409 : :
410 : 100 : int bf_stub_load_header(struct bf_program *program,
411 : : const struct bf_matcher_meta *meta, int reg)
412 : : {
413 : : assert(program);
414 : : assert(meta);
415 : :
416 [ + + - ]: 100 : switch (meta->layer) {
417 : 60 : case BF_MATCHER_LAYER_3:
418 [ - + ]: 60 : EMIT(program,
419 : : BPF_LDX_MEM(BPF_DW, reg, BPF_REG_10, BF_PROG_CTX_OFF(l3_hdr)));
420 : 60 : break;
421 : 40 : case BF_MATCHER_LAYER_4:
422 [ - + ]: 40 : EMIT(program,
423 : : BPF_LDX_MEM(BPF_DW, reg, BPF_REG_10, BF_PROG_CTX_OFF(l4_hdr)));
424 : 40 : break;
425 : 0 : default:
426 [ # # ]: 0 : return bf_err_r(-EINVAL,
427 : : "layer ID %d is not a valid layer to load header for",
428 : : meta->layer);
429 : : }
430 : :
431 : : return 0;
432 : : }
433 : :
434 : 80 : int bf_stub_stx_payload(struct bf_program *program,
435 : : const struct bf_matcher_meta *meta, size_t offset)
436 : : {
437 : : assert(program);
438 : : assert(meta);
439 : :
440 : 80 : size_t remaining_size = meta->hdr_payload_size;
441 : : size_t src_offset = 0;
442 : : size_t dst_offset = offset;
443 : :
444 [ + + ]: 160 : while (remaining_size) {
445 : : int bpf_size = BPF_B;
446 : : size_t copy_bytes = 1;
447 : :
448 [ + + + - ]: 80 : if (BF_ALIGNED_64(offset) && remaining_size >= 8) {
449 : : bpf_size = BPF_DW;
450 : : copy_bytes = 8;
451 [ + - + + ]: 80 : } else if (BF_ALIGNED_32(offset) && remaining_size >= 4) {
452 : : bpf_size = BPF_W;
453 : : copy_bytes = 4;
454 [ - + + + ]: 60 : } else if (BF_ALIGNED_16(offset) && remaining_size >= 2) {
455 : : bpf_size = BPF_H;
456 : : copy_bytes = 2;
457 : : }
458 : :
459 [ - + ]: 80 : EMIT(program, BPF_LDX_MEM(bpf_size, BPF_REG_1, BPF_REG_6,
460 : : meta->hdr_payload_offset + src_offset));
461 [ - + ]: 80 : EMIT(program, BPF_STX_MEM(bpf_size, BPF_REG_10, BPF_REG_1,
462 : : BF_PROG_SCR_OFF(dst_offset)));
463 : :
464 : 80 : remaining_size -= copy_bytes;
465 : 80 : src_offset += copy_bytes;
466 : 80 : dst_offset += copy_bytes;
467 : : }
468 : :
469 : : return 0;
470 : : }
|