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 "bpfilter/cgen/tc.h"
7 :
8 : #include <linux/bpf.h>
9 : #include <linux/bpf_common.h>
10 : #include <linux/pkt_cls.h>
11 :
12 : #include <stddef.h>
13 : #include <stdint.h>
14 :
15 : #include "bpfilter/cgen/cgen.h"
16 : #include "bpfilter/cgen/program.h"
17 : #include "bpfilter/cgen/stub.h"
18 : #include "core/btf.h"
19 : #include "core/flavor.h"
20 : #include "core/helper.h"
21 : #include "core/verdict.h"
22 :
23 : #include "external/filter.h"
24 :
25 0 : static int _bf_tc_gen_inline_prologue(struct bf_program *program)
26 : {
27 : int r;
28 :
29 0 : bf_assert(program);
30 :
31 : // Calculate the packet size and store it into the runtime context
32 0 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
33 : offsetof(struct __sk_buff, data)));
34 0 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
35 : offsetof(struct __sk_buff, data_end)));
36 0 : EMIT(program, BPF_ALU64_REG(BPF_SUB, BPF_REG_3, BPF_REG_2));
37 0 : EMIT(program,
38 : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_3, BF_PROG_CTX_OFF(pkt_size)));
39 :
40 : /** The @c __sk_buff structure contains two fields related to the interface
41 : * index: @c ingress_ifindex and @c ifindex . @c ingress_ifindex is the
42 : * interface index the packet has been received on. However, we use
43 : * @c ifindex which is the interface index the packet is processed by: if
44 : * a packet is redirected locally from interface #1 to interface #2, then
45 : * @c ingress_ifindex will contain @c 1 but @c ifindex will contains @c 2 .
46 : * For egress, only @c ifindex is used.
47 : */
48 0 : if ((r = bf_btf_get_field_off("__sk_buff", "ifindex")) < 0)
49 : return r;
50 0 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, r));
51 0 : EMIT(program,
52 : BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, BF_PROG_CTX_OFF(ifindex)));
53 :
54 0 : r = bf_stub_make_ctx_skb_dynptr(program, BPF_REG_1);
55 0 : if (r)
56 : return r;
57 :
58 0 : r = bf_stub_parse_l2_ethhdr(program);
59 0 : if (r)
60 : return r;
61 :
62 0 : r = bf_stub_parse_l3_hdr(program);
63 0 : if (r)
64 : return r;
65 :
66 0 : r = bf_stub_parse_l4_hdr(program);
67 : if (r)
68 : return r;
69 :
70 : return 0;
71 : }
72 :
73 0 : static int _bf_tc_gen_inline_epilogue(struct bf_program *program)
74 : {
75 : UNUSED(program);
76 :
77 0 : return 0;
78 : }
79 :
80 : /**
81 : * Convert a standard verdict into a return value.
82 : *
83 : * @param verdict Verdict to convert. Must be valid.
84 : * @return TC return code corresponding to the verdict, as an integer.
85 : */
86 0 : static int _bf_tc_get_verdict(enum bf_verdict verdict)
87 : {
88 0 : bf_assert(0 <= verdict && verdict < _BF_TERMINAL_VERDICT_MAX);
89 :
90 : static const int verdicts[] = {
91 : [BF_VERDICT_ACCEPT] = TC_ACT_OK,
92 : [BF_VERDICT_DROP] = TC_ACT_SHOT,
93 : };
94 :
95 : static_assert(ARRAY_SIZE(verdicts) == _BF_TERMINAL_VERDICT_MAX);
96 :
97 0 : return verdicts[verdict];
98 : }
99 :
100 : const struct bf_flavor_ops bf_flavor_ops_tc = {
101 : .gen_inline_prologue = _bf_tc_gen_inline_prologue,
102 : .gen_inline_epilogue = _bf_tc_gen_inline_epilogue,
103 : .get_verdict = _bf_tc_get_verdict,
104 : };
|