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