Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0-only */
2 : : /*
3 : : * Copyright (c) Meta Platforms, Inc. and affiliates.
4 : : */
5 : :
6 : : #include "cgen/cgroup_sock_addr.h"
7 : :
8 : : #include <linux/bpf.h>
9 : : #include <linux/bpf_common.h>
10 : : #include <linux/if_ether.h>
11 : :
12 : : #include <assert.h>
13 : : #include <stddef.h>
14 : : #include <stdint.h>
15 : : #include <sys/socket.h>
16 : :
17 : : #include <bpfilter/chain.h>
18 : : #include <bpfilter/elfstub.h>
19 : : #include <bpfilter/flavor.h>
20 : : #include <bpfilter/hook.h>
21 : : #include <bpfilter/logger.h>
22 : : #include <bpfilter/matcher.h>
23 : : #include <bpfilter/rule.h>
24 : : #include <bpfilter/runtime.h>
25 : : #include <bpfilter/set.h>
26 : : #include <bpfilter/verdict.h>
27 : :
28 : : #include "cgen/matcher/cmp.h"
29 : : #include "cgen/matcher/meta.h"
30 : : #include "cgen/matcher/set.h"
31 : : #include "cgen/program.h"
32 : : #include "cgen/runtime.h"
33 : : #include "cgen/stub.h"
34 : : #include "cgen/swich.h"
35 : : #include "filter.h"
36 : :
37 : : // Forward definition to avoid header conflicts.
38 : : uint16_t htons(uint16_t hostshort);
39 : :
40 : 63 : static int _bf_cgroup_sock_addr_gen_inline_prologue(struct bf_program *program)
41 : : {
42 : : int r;
43 : :
44 : : assert(program);
45 : :
46 : : /* `R6` = `bpf_sock_addr` context pointer. Unlike packet-based flavors where
47 : : * `R6` changes per header, the socket context is fixed so we set it once. */
48 [ + - ]: 63 : EMIT(program, BPF_MOV64_REG(BPF_REG_6, BPF_REG_1));
49 : :
50 : : // The counters stub reads `pkt_size` unconditionally; zero it out.
51 [ + - ]: 63 : EMIT(program, BPF_ST_MEM(BPF_DW, BPF_REG_10, BF_PROG_CTX_OFF(pkt_size), 0));
52 : :
53 : : /* Convert `bpf_sock_addr.family` to L3 protocol ID in `R7`, using the same
54 : : * `bf_swich` pattern as cgroup_skb. */
55 [ + - ]: 63 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_6,
56 : : offsetof(struct bpf_sock_addr, family)));
57 : :
58 : : {
59 : 63 : _clean_bf_swich_ struct bf_swich swich =
60 [ - + ]: 63 : bf_swich_get(program, BPF_REG_2);
61 : :
62 [ - + ]: 63 : EMIT_SWICH_OPTION(&swich, AF_INET,
63 : : BPF_MOV64_IMM(BPF_REG_7, htons(ETH_P_IP)));
64 [ - + ]: 63 : EMIT_SWICH_OPTION(&swich, AF_INET6,
65 : : BPF_MOV64_IMM(BPF_REG_7, htons(ETH_P_IPV6)));
66 [ - + ]: 63 : EMIT_SWICH_DEFAULT(&swich, BPF_MOV64_IMM(BPF_REG_7, 0));
67 : :
68 : 63 : r = bf_swich_generate(&swich);
69 [ + - ]: 63 : if (r)
70 : : return r;
71 : : }
72 : :
73 : 63 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_8, BPF_REG_6,
74 : : offsetof(struct bpf_sock_addr, protocol)));
75 : :
76 : : return 0;
77 : : }
78 : :
79 : 63 : static int _bf_cgroup_sock_addr_gen_inline_epilogue(struct bf_program *program)
80 : : {
81 : : (void)program;
82 : :
83 : 63 : return 0;
84 : : }
85 : :
86 : : /**
87 : : * @brief Load a field from the `bpf_sock_addr` context into a register.
88 : : *
89 : : * `R6` must already point to the context. For 16-byte fields, the low
90 : : * 8 bytes go into `reg` and the high 8 bytes into `reg + 1`.
91 : : *
92 : : * When the field offset is not 8-byte aligned, 8- and 16-byte loads fall
93 : : * back to 4-byte reads packed via shift/or. This clobbers `reg + 1` for
94 : : * 8-byte loads and `reg + 2` for 16-byte loads.
95 : : *
96 : : * @param program Program to emit into. Can't be NULL.
97 : : * @param offset Byte offset into `struct bpf_sock_addr`.
98 : : * @param size Field size in bytes: 1, 2, 4, 8, or 16.
99 : : * @param reg BPF register to load the value into.
100 : : * @return 0 on success, negative errno on error.
101 : : */
102 : 92 : static int _bf_cgroup_sock_addr_load_field(struct bf_program *program,
103 : : size_t offset, size_t size, int reg)
104 : : {
105 : : assert(program);
106 : :
107 [ - - + - : 92 : switch (size) {
+ - ]
108 : 0 : case 1:
109 [ # # ]: 0 : EMIT(program, BPF_LDX_MEM(BPF_B, reg, BPF_REG_6, offset));
110 : : break;
111 : 0 : case 2:
112 [ # # ]: 0 : EMIT(program, BPF_LDX_MEM(BPF_H, reg, BPF_REG_6, offset));
113 : : break;
114 : 75 : case 4:
115 [ + - ]: 75 : EMIT(program, BPF_LDX_MEM(BPF_W, reg, BPF_REG_6, offset));
116 : : break;
117 : 0 : case 8:
118 [ # # ]: 0 : if (offset % 8 == 0) {
119 [ # # ]: 0 : EMIT(program, BPF_LDX_MEM(BPF_DW, reg, BPF_REG_6, offset));
120 : : } else {
121 [ # # ]: 0 : EMIT(program, BPF_LDX_MEM(BPF_W, reg, BPF_REG_6, offset));
122 [ # # ]: 0 : EMIT(program, BPF_LDX_MEM(BPF_W, reg + 1, BPF_REG_6, offset + 4));
123 [ # # ]: 0 : EMIT(program, BPF_ALU64_IMM(BPF_LSH, reg + 1, 32));
124 [ # # ]: 0 : EMIT(program, BPF_ALU64_REG(BPF_OR, reg, reg + 1));
125 : : }
126 : : break;
127 : 17 : case 16:
128 [ + + ]: 17 : if (offset % 8 == 0) {
129 [ + - ]: 14 : EMIT(program, BPF_LDX_MEM(BPF_DW, reg, BPF_REG_6, offset));
130 [ + - ]: 14 : EMIT(program, BPF_LDX_MEM(BPF_DW, reg + 1, BPF_REG_6, offset + 8));
131 : : } else {
132 [ + - ]: 3 : EMIT(program, BPF_LDX_MEM(BPF_W, reg, BPF_REG_6, offset));
133 [ + - ]: 3 : EMIT(program, BPF_LDX_MEM(BPF_W, reg + 2, BPF_REG_6, offset + 4));
134 [ + - ]: 3 : EMIT(program, BPF_ALU64_IMM(BPF_LSH, reg + 2, 32));
135 [ + - ]: 3 : EMIT(program, BPF_ALU64_REG(BPF_OR, reg, reg + 2));
136 [ + - ]: 3 : EMIT(program, BPF_LDX_MEM(BPF_W, reg + 1, BPF_REG_6, offset + 8));
137 [ + - ]: 3 : EMIT(program, BPF_LDX_MEM(BPF_W, reg + 2, BPF_REG_6, offset + 12));
138 [ + - ]: 3 : EMIT(program, BPF_ALU64_IMM(BPF_LSH, reg + 2, 32));
139 [ + - ]: 3 : EMIT(program, BPF_ALU64_REG(BPF_OR, reg + 1, reg + 2));
140 : : }
141 : : break;
142 : : default:
143 : : return -EINVAL;
144 : : }
145 : :
146 : : return 0;
147 : : }
148 : :
149 : : /**
150 : : * @brief Store a register value at an offset from `BPF_REG_10`.
151 : : *
152 : : * Counterpart to `_bf_cgroup_sock_addr_load_field`. For 16-byte stores,
153 : : * `reg` holds the low 8 bytes and `reg + 1` the high 8 bytes, matching
154 : : * the layout produced by `_bf_cgroup_sock_addr_load_field`.
155 : : *
156 : : * @param program Program to emit into. Can't be NULL.
157 : : * @param offset Byte offset from `BPF_REG_10`.
158 : : * @param size Field size in bytes: 1, 2, 4, 8, or 16.
159 : : * @param reg BPF register holding the value to store.
160 : : * @return 0 on success, negative errno on error.
161 : : */
162 : 10 : static int _bf_cgroup_sock_addr_store_field(struct bf_program *program,
163 : : int offset, size_t size, int reg)
164 : : {
165 : : assert(program);
166 : :
167 [ - + + - : 10 : switch (size) {
+ - ]
168 : 0 : case 1:
169 [ # # ]: 0 : EMIT(program, BPF_STX_MEM(BPF_B, BPF_REG_10, reg, offset));
170 : : break;
171 : 4 : case 2:
172 [ + - ]: 4 : EMIT(program, BPF_STX_MEM(BPF_H, BPF_REG_10, reg, offset));
173 : : break;
174 : 3 : case 4:
175 [ + - ]: 3 : EMIT(program, BPF_STX_MEM(BPF_W, BPF_REG_10, reg, offset));
176 : : break;
177 : 0 : case 8:
178 [ # # ]: 0 : EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, reg, offset));
179 : : break;
180 : 3 : case 16:
181 [ + - ]: 3 : EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, reg, offset));
182 [ + - ]: 3 : EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, reg + 1, offset + 8));
183 : : break;
184 : : default:
185 : : return -EINVAL;
186 : : }
187 : :
188 : : return 0;
189 : : }
190 : :
191 : 13 : static int _bf_cgroup_sock_addr_load_and_cmp(struct bf_program *program,
192 : : const struct bf_matcher *matcher,
193 : : size_t offset, size_t size)
194 : : {
195 : : int r;
196 : :
197 : : assert(program);
198 : : assert(matcher);
199 : :
200 : 13 : r = _bf_cgroup_sock_addr_load_field(program, offset, size, BPF_REG_1);
201 [ + - ]: 13 : if (r)
202 : : return r;
203 : :
204 : 13 : return bf_cmp_value(program, matcher, bf_matcher_payload(matcher), size,
205 : : BPF_REG_1);
206 : : }
207 : :
208 : 13 : static int _bf_cgroup_sock_addr_generate_net(struct bf_program *program,
209 : : const struct bf_matcher *matcher,
210 : : size_t offset, size_t size)
211 : : {
212 : : uint32_t prefixlen;
213 : : const void *data;
214 : : int r;
215 : :
216 : : assert(program);
217 : : assert(matcher);
218 : :
219 : 13 : prefixlen = *(const uint32_t *)bf_matcher_payload(matcher);
220 : 13 : data = (const uint8_t *)bf_matcher_payload(matcher) + sizeof(uint32_t);
221 : :
222 : 13 : r = _bf_cgroup_sock_addr_load_field(program, offset, size, BPF_REG_1);
223 [ + - ]: 13 : if (r)
224 : : return r;
225 : :
226 : 13 : return bf_cmp_masked_value(program, matcher, data, prefixlen, size,
227 : : BPF_REG_1);
228 : : }
229 : :
230 : : /* `user_port` is a __u32 in network byte order with the upper 16 bits
231 : : * guaranteed zero by the kernel ABI. Loaded as `BPF_W` so EQ/NE compare
232 : : * the full 32-bit register (safe because upper bits are zero). For range
233 : : * comparisons, `BSWAP` converts to host order (and zeroes the upper bits). */
234 : 56 : static int _bf_cgroup_sock_addr_generate_port(struct bf_program *program,
235 : : const struct bf_matcher *matcher)
236 : : {
237 : : int r;
238 : :
239 : : assert(program);
240 : : assert(matcher);
241 : :
242 : 56 : r = _bf_cgroup_sock_addr_load_field(
243 : : program, offsetof(struct bpf_sock_addr, user_port), 4, BPF_REG_1);
244 [ + - ]: 56 : if (r)
245 : : return r;
246 : :
247 [ + + ]: 56 : if (bf_matcher_get_op(matcher) == BF_MATCHER_RANGE) {
248 : 16 : uint16_t *ports = (uint16_t *)bf_matcher_payload(matcher);
249 [ + - ]: 16 : EMIT(program, BPF_BSWAP(BPF_REG_1, 16));
250 : 16 : return bf_cmp_range(program, matcher, ports[0], ports[1], BPF_REG_1);
251 : : }
252 : :
253 : 40 : return bf_cmp_value(program, matcher, bf_matcher_payload(matcher), 2,
254 : : BPF_REG_1);
255 : : }
256 : :
257 : : static ssize_t _bf_cgroup_sock_addr_ctx_offset(enum bf_matcher_type type)
258 : : {
259 : : switch (type) {
260 : : case BF_MATCHER_IP4_SADDR:
261 : : case BF_MATCHER_IP4_SNET:
262 : : return offsetof(struct bpf_sock_addr, msg_src_ip4);
263 : : case BF_MATCHER_IP4_DADDR:
264 : : case BF_MATCHER_IP4_DNET:
265 : : return offsetof(struct bpf_sock_addr, user_ip4);
266 : : case BF_MATCHER_IP6_SADDR:
267 : : case BF_MATCHER_IP6_SNET:
268 : : return offsetof(struct bpf_sock_addr, msg_src_ip6);
269 : : case BF_MATCHER_IP6_DADDR:
270 : : case BF_MATCHER_IP6_DNET:
271 : : return offsetof(struct bpf_sock_addr, user_ip6);
272 : : case BF_MATCHER_IP4_PROTO:
273 : : return offsetof(struct bpf_sock_addr, protocol);
274 : : case BF_MATCHER_TCP_DPORT:
275 : : case BF_MATCHER_UDP_DPORT:
276 : : return offsetof(struct bpf_sock_addr, user_port);
277 : : default:
278 : : return -ENOTSUP;
279 : : }
280 : : }
281 : :
282 : 13 : static int _bf_cgroup_sock_addr_generate_set(struct bf_program *program,
283 : : const struct bf_matcher *matcher)
284 : : {
285 : : const struct bf_set *set;
286 : : size_t offset = 0;
287 : : int r;
288 : :
289 : : assert(program);
290 : : assert(matcher);
291 : :
292 : 13 : set = bf_chain_get_set_for_matcher(program->runtime.chain, matcher);
293 [ - + ]: 13 : if (!set) {
294 [ # # ]: 0 : return bf_err_r(-ENOENT, "set #%u not found in %s",
295 : : *(uint32_t *)bf_matcher_payload(matcher),
296 : : program->runtime.chain->name);
297 : : }
298 : :
299 [ + + ]: 13 : if (set->use_trie) {
300 : 4 : const struct bf_matcher_meta *meta = bf_matcher_get_meta(set->key[0]);
301 [ + - ]: 4 : ssize_t ctx_off = _bf_cgroup_sock_addr_ctx_offset(set->key[0]);
302 : :
303 [ - + ]: 4 : if (!meta) {
304 [ # # ]: 0 : return bf_err_r(-EINVAL, "missing meta for set component '%s'",
305 : : bf_matcher_type_to_str(set->key[0]));
306 : : }
307 : :
308 [ - + ]: 4 : if (ctx_off < 0) {
309 [ # # ]: 0 : return bf_err_r(
310 : : (int)ctx_off,
311 : : "set component '%s' not supported for cgroup_sock_addr",
312 : : bf_matcher_type_to_str(set->key[0]));
313 : : }
314 : :
315 : 4 : return bf_set_generate_trie_lookup(program, matcher, (size_t)ctx_off,
316 : 4 : meta->hdr_payload_size);
317 : : }
318 : :
319 [ + + ]: 22 : for (size_t i = 0; i < set->n_comps; ++i) {
320 : 13 : enum bf_matcher_type type = set->key[i];
321 : 13 : const struct bf_matcher_meta *meta = bf_matcher_get_meta(type);
322 : : ssize_t ctx_off = _bf_cgroup_sock_addr_ctx_offset(type);
323 : :
324 [ - + ]: 13 : if (!meta) {
325 [ # # ]: 0 : return bf_err_r(-EINVAL, "missing meta for set component '%s'",
326 : : bf_matcher_type_to_str(type));
327 : : }
328 : :
329 [ - + ]: 13 : if (ctx_off < 0) {
330 [ # # ]: 0 : return bf_err_r(
331 : : (int)ctx_off,
332 : : "set component '%s' not supported for cgroup_sock_addr",
333 : : bf_matcher_type_to_str(type));
334 : : }
335 : :
336 : : /* The BPF verifier enforces specific ctx access widths on
337 : : * `bpf_sock_addr` fields. `bf_stub_load()` reads
338 : : * `meta->hdr_payload_size` bytes from ctx:
339 : : * - Ports (`hdr_payload_size == 2`): `user_port` is a 4-byte
340 : : * `__u32`, but the 2-byte narrow read is accepted and rewritten
341 : : * to the NBO port value.
342 : : * - Protocol (`hdr_payload_size == 1`): only 4-byte reads are
343 : : * allowed, so a 1-byte `bf_stub_load()` would be rejected. Reuse
344 : : * `BPF_REG_8`, which the prologue loaded with a 4-byte read. */
345 [ + + ]: 13 : if (type == BF_MATCHER_IP4_PROTO) {
346 [ + - ]: 1 : EMIT(program, BPF_STX_MEM(BPF_B, BPF_REG_10, BPF_REG_8,
347 : : BF_PROG_SCR_OFF(offset)));
348 : : } else {
349 : 12 : r = bf_stub_load(program, (size_t)ctx_off, meta->hdr_payload_size,
350 : 12 : BF_PROG_SCR_OFF(offset));
351 [ + - ]: 12 : if (r)
352 : : return r;
353 : : }
354 : :
355 : 13 : offset += meta->hdr_payload_size;
356 : : }
357 : :
358 : 9 : return bf_set_generate_map_lookup(program, matcher, BF_PROG_SCR_OFF(0));
359 : : }
360 : :
361 : : static int
362 : 124 : _bf_cgroup_sock_addr_gen_inline_matcher(struct bf_program *program,
363 : : const struct bf_matcher *matcher)
364 : : {
365 : : assert(program);
366 : : assert(matcher);
367 : :
368 [ + + + + : 124 : switch (bf_matcher_get_type(matcher)) {
+ + + + +
+ + + - ]
369 : 24 : case BF_MATCHER_META_L3_PROTO:
370 : : case BF_MATCHER_META_L4_PROTO:
371 : : case BF_MATCHER_META_PROBABILITY:
372 : 24 : return bf_matcher_generate_meta(program, matcher);
373 : 1 : case BF_MATCHER_IP4_SADDR:
374 : 1 : return _bf_cgroup_sock_addr_load_and_cmp(
375 : : program, matcher, offsetof(struct bpf_sock_addr, msg_src_ip4), 4);
376 : 1 : case BF_MATCHER_IP4_SNET:
377 : 1 : return _bf_cgroup_sock_addr_generate_net(
378 : : program, matcher, offsetof(struct bpf_sock_addr, msg_src_ip4), 4);
379 : 5 : case BF_MATCHER_IP4_DADDR:
380 : 5 : return _bf_cgroup_sock_addr_load_and_cmp(
381 : : program, matcher, offsetof(struct bpf_sock_addr, user_ip4), 4);
382 : 5 : case BF_MATCHER_IP4_DNET:
383 : 5 : return _bf_cgroup_sock_addr_generate_net(
384 : : program, matcher, offsetof(struct bpf_sock_addr, user_ip4), 4);
385 : 5 : case BF_MATCHER_IP4_PROTO:
386 [ + - ]: 5 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_8));
387 : 5 : return bf_cmp_value(program, matcher, bf_matcher_payload(matcher), 1,
388 : : BPF_REG_1);
389 : 1 : case BF_MATCHER_IP6_SADDR:
390 : 1 : return _bf_cgroup_sock_addr_load_and_cmp(
391 : : program, matcher, offsetof(struct bpf_sock_addr, msg_src_ip6), 16);
392 : 1 : case BF_MATCHER_IP6_SNET:
393 : 1 : return _bf_cgroup_sock_addr_generate_net(
394 : : program, matcher, offsetof(struct bpf_sock_addr, msg_src_ip6), 16);
395 : 6 : case BF_MATCHER_IP6_DADDR:
396 : 6 : return _bf_cgroup_sock_addr_load_and_cmp(
397 : : program, matcher, offsetof(struct bpf_sock_addr, user_ip6), 16);
398 : 6 : case BF_MATCHER_IP6_DNET:
399 : 6 : return _bf_cgroup_sock_addr_generate_net(
400 : : program, matcher, offsetof(struct bpf_sock_addr, user_ip6), 16);
401 : 56 : case BF_MATCHER_META_DPORT:
402 : : case BF_MATCHER_TCP_DPORT:
403 : : case BF_MATCHER_UDP_DPORT:
404 : 56 : return _bf_cgroup_sock_addr_generate_port(program, matcher);
405 : 13 : case BF_MATCHER_SET:
406 : 13 : return _bf_cgroup_sock_addr_generate_set(program, matcher);
407 : 0 : default:
408 [ # # ]: 0 : return bf_err_r(-ENOTSUP,
409 : : "matcher '%s' not supported for cgroup_sock_addr",
410 : : bf_matcher_type_to_str(bf_matcher_get_type(matcher)));
411 : : }
412 : : }
413 : :
414 : : /**
415 : : * @brief Convert a standard verdict into a return value.
416 : : *
417 : : * @param verdict Verdict to convert. Must be valid.
418 : : * @param ret_code Cgroup return code. Can't be NULL.
419 : : * @return 0 on success, or a negative errno value on failure.
420 : : */
421 : 139 : static int _bf_cgroup_sock_addr_get_verdict(enum bf_verdict verdict,
422 : : int *ret_code)
423 : : {
424 : : assert(ret_code);
425 : :
426 [ + + - ]: 139 : switch (verdict) {
427 : 80 : case BF_VERDICT_ACCEPT:
428 : : case BF_VERDICT_NEXT:
429 : 80 : *ret_code = 1;
430 : 80 : return 0;
431 : 59 : case BF_VERDICT_DROP:
432 : 59 : *ret_code = 0;
433 : 59 : return 0;
434 : : default:
435 : : return -ENOTSUP;
436 : : }
437 : : }
438 : :
439 : 4 : static int _bf_cgroup_sock_addr_gen_inline_log(struct bf_program *program,
440 : : const struct bf_rule *rule)
441 : : {
442 : : uint8_t captured_fields = 0;
443 : : bool has_saddr = false;
444 : : size_t addr_size = 0;
445 : : size_t saddr_off = 0;
446 : : size_t daddr_off = 0;
447 : : int r;
448 : :
449 : : assert(program);
450 : : assert(rule);
451 : :
452 : : // Zero the staging area: connect hooks have no source address,
453 : : // and IPv4 hooks only write 4 of the 16 address bytes.
454 [ + + ]: 24 : for (int i = 0; i < (int)sizeof(struct bf_runtime_sock_addr); i += 8)
455 [ + - ]: 20 : EMIT(program, BPF_ST_MEM(BPF_DW, BPF_REG_10, BF_PROG_SCR_OFF(i), 0));
456 : :
457 [ + + - + : 4 : switch (program->runtime.chain->hook) {
+ ]
458 : : case BF_HOOK_CGROUP_SOCK_ADDR_SENDMSG4:
459 : : has_saddr = true;
460 : : saddr_off = offsetof(struct bpf_sock_addr, msg_src_ip4);
461 : : __attribute__((fallthrough));
462 : : case BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4:
463 : : addr_size = 4;
464 : : daddr_off = offsetof(struct bpf_sock_addr, user_ip4);
465 : : break;
466 : : case BF_HOOK_CGROUP_SOCK_ADDR_SENDMSG6:
467 : : has_saddr = true;
468 : : saddr_off = offsetof(struct bpf_sock_addr, msg_src_ip6);
469 : : __attribute__((fallthrough));
470 : : case BF_HOOK_CGROUP_SOCK_ADDR_CONNECT6:
471 : : addr_size = 16;
472 : : daddr_off = offsetof(struct bpf_sock_addr, user_ip6);
473 : : break;
474 : 0 : default:
475 [ # # ]: 0 : return bf_err_r(-ENOTSUP, "unexpected hook: %s",
476 : : bf_hook_to_str(program->runtime.chain->hook));
477 : : }
478 : :
479 : : if (has_saddr) {
480 : : captured_fields |= BF_LOG_SOCK_ADDR_SADDR;
481 : 2 : r = _bf_cgroup_sock_addr_load_field(program, saddr_off, addr_size,
482 : : BPF_REG_1);
483 [ + - ]: 2 : if (r)
484 : : return r;
485 : 2 : r = _bf_cgroup_sock_addr_store_field(
486 : : program,
487 : : BF_PROG_SCR_OFF(offsetof(struct bf_runtime_sock_addr, saddr)),
488 : : addr_size, BPF_REG_1);
489 [ + - ]: 2 : if (r)
490 : : return r;
491 : : }
492 : :
493 : 4 : r = _bf_cgroup_sock_addr_load_field(program, daddr_off, addr_size,
494 : : BPF_REG_1);
495 [ + - ]: 4 : if (r)
496 : : return r;
497 : 4 : r = _bf_cgroup_sock_addr_store_field(
498 : : program, BF_PROG_SCR_OFF(offsetof(struct bf_runtime_sock_addr, daddr)),
499 : : addr_size, BPF_REG_1);
500 [ + - ]: 4 : if (r)
501 : : return r;
502 : :
503 : : /* Destination port: valid for all cgroup_sock_addr hooks.
504 : : * user_port is __be32; BSWAP 16 converts to host order. */
505 : 4 : r = _bf_cgroup_sock_addr_load_field(
506 : : program, offsetof(struct bpf_sock_addr, user_port), 4, BPF_REG_1);
507 [ + - ]: 4 : if (r)
508 : : return r;
509 [ + - ]: 4 : EMIT(program, BPF_BSWAP(BPF_REG_1, 16));
510 : 4 : r = _bf_cgroup_sock_addr_store_field(
511 : : program, BF_PROG_SCR_OFF(offsetof(struct bf_runtime_sock_addr, dport)),
512 : : 2, BPF_REG_1);
513 [ + - ]: 4 : if (r)
514 : : return r;
515 : :
516 [ + - ]: 4 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
517 [ + - ]: 4 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
518 [ + - ]: 4 : EMIT(program, BPF_MOV64_IMM(BPF_REG_2, rule->index));
519 [ + - ]: 4 : EMIT(program, BPF_MOV64_IMM(BPF_REG_3, rule->verdict));
520 [ + - ]: 4 : EMIT(program, BPF_MOV64_REG(BPF_REG_4, BPF_REG_7));
521 [ + - ]: 4 : EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_4, 16));
522 [ + - ]: 4 : EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_4, BPF_REG_8));
523 [ + - ]: 4 : EMIT(program, BPF_MOV64_IMM(BPF_REG_5, captured_fields));
524 : 4 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_SOCK_ADDR_LOG);
525 : :
526 : : return 0;
527 : : }
528 : :
529 : : const struct bf_flavor_ops bf_flavor_ops_cgroup_sock_addr = {
530 : : .gen_inline_prologue = _bf_cgroup_sock_addr_gen_inline_prologue,
531 : : .gen_inline_epilogue = _bf_cgroup_sock_addr_gen_inline_epilogue,
532 : : .get_verdict = _bf_cgroup_sock_addr_get_verdict,
533 : : .gen_inline_matcher = _bf_cgroup_sock_addr_gen_inline_matcher,
534 : : .gen_inline_log = _bf_cgroup_sock_addr_gen_inline_log,
535 : : };
|