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