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 : : bf_assert(program && matcher);
19 : :
20 : : const struct bf_set *set =
21 : 20 : bf_chain_get_set_for_matcher(program->runtime.chain, matcher);
22 : 20 : enum bf_matcher_type type = set->key[0];
23 : 20 : 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 : 20 : r = bf_stub_rule_check_protocol(program, meta);
33 [ - + ]: 20 : if (r)
34 [ # # ]: 0 : return bf_err_r(r, "failed to check for protocol");
35 : :
36 : 20 : r = bf_stub_load_header(program, meta, BPF_REG_6);
37 [ - + ]: 20 : if (r)
38 [ # # ]: 0 : return bf_err_r(r, "failed to load protocol header into BPF_REG_6");
39 : :
40 [ - + ]: 20 : 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 [ + - ]: 20 : } else if (BF_FLAG(type) &
49 : : (BF_FLAGS(BF_MATCHER_IP6_SNET, BF_MATCHER_IP6_DNET))) {
50 [ - + ]: 20 : EMIT(program, BPF_MOV64_IMM(BPF_REG_1, 128));
51 [ - + ]: 20 : EMIT(program,
52 : : BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_1, BF_PROG_SCR_OFF(4)));
53 : :
54 [ - + ]: 20 : EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6,
55 : : meta->hdr_payload_offset));
56 [ - + ]: 20 : EMIT(program,
57 : : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, BF_PROG_SCR_OFF(8)));
58 : :
59 [ - + ]: 20 : EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6,
60 : : meta->hdr_payload_offset + 8));
61 [ - + ]: 20 : 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 [ + - + - ]: 20 : EMIT_LOAD_SET_FD_FIXUP(program, BPF_REG_1,
70 : : *(uint32_t *)bf_matcher_payload(matcher));
71 [ - + ]: 20 : EMIT(program, BPF_MOV64_REG(BPF_REG_2, BPF_REG_10));
72 [ - + ]: 20 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, BF_PROG_SCR_OFF(4)));
73 [ - + ]: 20 : EMIT(program, BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem));
74 : :
75 : : // Jump to the next rule if map_lookup_elem returned 0
76 [ - + ]: 20 : EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
77 : 20 : return 0;
78 : : }
79 : :
80 : 80 : int bf_matcher_generate_set(struct bf_program *program,
81 : : const struct bf_matcher *matcher)
82 : : {
83 : : bf_assert(program && matcher);
84 : :
85 : : const struct bf_set *set =
86 : 80 : bf_chain_get_set_for_matcher(program->runtime.chain, matcher);
87 : : size_t offset = 0;
88 : : int r;
89 : :
90 [ - + ]: 80 : 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 [ + + ]: 80 : if (set->use_trie)
97 : 20 : return _bf_matcher_generate_set_trie(program, matcher);
98 : :
99 : : // Ensure the packet uses the required protocols
100 [ + + ]: 140 : for (size_t i = 0; i < set->n_comps; ++i) {
101 : 80 : enum bf_matcher_type type = set->key[i];
102 : 80 : const struct bf_matcher_meta *meta = bf_matcher_get_meta(type);
103 : :
104 [ - + ]: 80 : if (!meta) {
105 [ # # ]: 0 : return bf_err_r(-ENOENT, "meta for '%s' not found",
106 : : bf_matcher_type_to_str(type));
107 : : }
108 : :
109 : 80 : r = bf_stub_rule_check_protocol(program, meta);
110 [ - + ]: 80 : 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 [ + + ]: 140 : for (size_t i = 0; i < set->n_comps; ++i) {
116 : 80 : enum bf_matcher_type type = set->key[i];
117 : 80 : const struct bf_matcher_meta *meta = bf_matcher_get_meta(type);
118 : :
119 [ - + ]: 80 : if (!meta) {
120 [ # # ]: 0 : return bf_err_r(-ENOENT, "meta for '%s' not found",
121 : : bf_matcher_type_to_str(type));
122 : : }
123 : :
124 : 80 : r = bf_stub_load_header(program, meta, BPF_REG_6);
125 [ - + ]: 80 : if (r)
126 [ # # ]: 0 : return bf_err_r(r, "failed to load protocol header into BPF_REG_6");
127 : :
128 : 80 : r = bf_stub_stx_payload(program, meta, offset);
129 [ - + ]: 80 : if (r) {
130 [ # # ]: 0 : return bf_err_r(r,
131 : : "failed to generate bytecode to load packet data");
132 : : }
133 : :
134 : 80 : offset += meta->hdr_payload_size;
135 : : }
136 : :
137 [ + - + - ]: 60 : EMIT_LOAD_SET_FD_FIXUP(program, BPF_REG_1,
138 : : *(uint32_t *)bf_matcher_payload(matcher));
139 [ - + ]: 60 : EMIT(program, BPF_MOV64_REG(BPF_REG_2, BPF_REG_10));
140 [ - + ]: 60 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, BF_PROG_SCR_OFF(0)));
141 [ - + ]: 60 : EMIT(program, BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem));
142 : :
143 : : // Jump to the next rule if map_lookup_elem returned 0
144 [ - + ]: 60 : EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
145 : :
146 : 60 : return 0;
147 : : }
|