Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-only */
2 : /*
3 : * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
4 : */
5 :
6 : #include "bpfilter/cgen/matcher/set.h"
7 :
8 : #include "bpfilter/cgen/program.h"
9 : #include "bpfilter/cgen/stub.h"
10 : #include "core/chain.h"
11 : #include "core/matcher.h"
12 : #include "core/set.h"
13 :
14 0 : static int _bf_matcher_generate_set_trie(struct bf_program *program,
15 : const struct bf_matcher *matcher)
16 : {
17 0 : bf_assert(program && matcher);
18 :
19 : const struct bf_set *set =
20 0 : bf_chain_get_set_for_matcher(program->runtime.chain, matcher);
21 0 : enum bf_matcher_type type = set->key[0];
22 0 : const struct bf_matcher_meta *meta = bf_matcher_get_meta(type);
23 : int r;
24 :
25 : if (!set) {
26 : return bf_err_r(-ENOENT, "set #%u not found in %s",
27 : *(uint32_t *)matcher->payload,
28 : program->runtime.chain->name);
29 : }
30 :
31 0 : r = bf_stub_rule_check_protocol(program, meta);
32 0 : if (r)
33 0 : return bf_err_r(r, "failed to check for protocol");
34 :
35 0 : r = bf_stub_load_header(program, meta, BPF_REG_6);
36 0 : if (r)
37 0 : return bf_err_r(r, "failed to load protocol header into BPF_REG_6");
38 :
39 0 : if (BF_FLAG(type) & (BF_FLAGS(BF_MATCHER_IP4_SNET, BF_MATCHER_IP4_DNET))) {
40 0 : EMIT(program, BPF_MOV64_IMM(BPF_REG_1, 32));
41 0 : EMIT(program,
42 : BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_1, BF_PROG_SCR_OFF(4)));
43 0 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_6,
44 : meta->hdr_payload_offset));
45 0 : EMIT(program,
46 : BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_1, BF_PROG_SCR_OFF(8)));
47 0 : } else if (BF_FLAG(type) &
48 : (BF_FLAGS(BF_MATCHER_IP6_SNET, BF_MATCHER_IP6_DNET))) {
49 0 : EMIT(program, BPF_MOV64_IMM(BPF_REG_1, 128));
50 0 : EMIT(program,
51 : BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_1, BF_PROG_SCR_OFF(4)));
52 :
53 0 : EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6,
54 : meta->hdr_payload_offset));
55 0 : EMIT(program,
56 : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, BF_PROG_SCR_OFF(8)));
57 :
58 0 : EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6,
59 : meta->hdr_payload_offset + 8));
60 0 : EMIT(program,
61 : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, BF_PROG_SCR_OFF(16)));
62 : } else {
63 0 : return bf_err_r(-EINVAL,
64 : "set key '%s' (%d) should not use a LPM trie map",
65 : bf_matcher_type_to_str(type), type);
66 : }
67 :
68 0 : EMIT_LOAD_SET_FD_FIXUP(program, BPF_REG_1, *(uint32_t *)matcher->payload);
69 0 : EMIT(program, BPF_MOV64_REG(BPF_REG_2, BPF_REG_10));
70 0 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, BF_PROG_SCR_OFF(4)));
71 0 : EMIT(program, BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem));
72 :
73 : // Jump to the next rule if map_lookup_elem returned 0
74 0 : EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
75 0 : return 0;
76 : }
77 :
78 0 : int bf_matcher_generate_set(struct bf_program *program,
79 : const struct bf_matcher *matcher)
80 : {
81 0 : bf_assert(program && matcher);
82 :
83 : const struct bf_set *set =
84 0 : bf_chain_get_set_for_matcher(program->runtime.chain, matcher);
85 : size_t offset = 0;
86 : int r;
87 :
88 0 : if (!set) {
89 0 : return bf_err_r(-ENOENT, "set #%u not found in %s",
90 : *(uint32_t *)matcher->payload,
91 : program->runtime.chain->name);
92 : }
93 :
94 0 : if (set->use_trie)
95 0 : return _bf_matcher_generate_set_trie(program, matcher);
96 :
97 : // Ensure the packet uses the required protocols
98 0 : for (size_t i = 0; i < set->n_comps; ++i) {
99 0 : enum bf_matcher_type type = set->key[i];
100 0 : const struct bf_matcher_meta *meta = bf_matcher_get_meta(type);
101 :
102 0 : if (!meta) {
103 0 : return bf_err_r(-ENOENT, "meta for '%s' not found",
104 : bf_matcher_type_to_str(type));
105 : }
106 :
107 0 : r = bf_stub_rule_check_protocol(program, meta);
108 0 : if (r)
109 0 : return bf_err_r(r, "failed to check for protocol");
110 : }
111 :
112 : // Generate the bytecode to build the set key
113 0 : for (size_t i = 0; i < set->n_comps; ++i) {
114 0 : enum bf_matcher_type type = set->key[i];
115 0 : const struct bf_matcher_meta *meta = bf_matcher_get_meta(type);
116 :
117 0 : if (!meta) {
118 0 : return bf_err_r(-ENOENT, "meta for '%s' not found",
119 : bf_matcher_type_to_str(type));
120 : }
121 :
122 0 : r = bf_stub_load_header(program, meta, BPF_REG_6);
123 0 : if (r)
124 0 : return bf_err_r(r, "failed to load protocol header into BPF_REG_6");
125 :
126 0 : r = bf_stub_stx_payload(program, meta, offset);
127 0 : if (r) {
128 0 : return bf_err_r(r,
129 : "failed to generate bytecode to load packet data");
130 : }
131 :
132 0 : offset += meta->hdr_payload_size;
133 : }
134 :
135 0 : EMIT_LOAD_SET_FD_FIXUP(program, BPF_REG_1, *(uint32_t *)matcher->payload);
136 0 : EMIT(program, BPF_MOV64_REG(BPF_REG_2, BPF_REG_10));
137 0 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, BF_PROG_SCR_OFF(0)));
138 0 : EMIT(program, BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem));
139 :
140 : // Jump to the next rule if map_lookup_elem returned 0
141 0 : EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
142 :
143 0 : return 0;
144 : }
|