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/ip4.h"
7 :
8 : #include <linux/bpf.h>
9 : #include <linux/bpf_common.h>
10 : #include <linux/if_ether.h>
11 : #include <linux/ip.h>
12 :
13 : #include <endian.h>
14 : #include <errno.h>
15 : #include <stddef.h>
16 : #include <stdint.h>
17 :
18 : #include "bpfilter/cgen/program.h"
19 : #include "core/helper.h"
20 : #include "core/list.h"
21 : #include "core/logger.h"
22 : #include "core/matcher.h"
23 : #include "core/set.h"
24 :
25 : #include "external/filter.h"
26 :
27 : static int
28 0 : _bf_matcher_generate_ip4_addr_unique(struct bf_program *program,
29 : const struct bf_matcher *matcher)
30 : {
31 : uint32_t *addr = (uint32_t *)&matcher->payload;
32 0 : size_t offset = matcher->type == BF_MATCHER_IP4_SADDR ?
33 0 : offsetof(struct iphdr, saddr) :
34 : offsetof(struct iphdr, daddr);
35 :
36 0 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_6, offset));
37 0 : EMIT(program, BPF_MOV32_IMM(BPF_REG_2, *addr));
38 :
39 0 : EMIT_FIXUP_JMP_NEXT_RULE(
40 : program, BPF_JMP_REG(matcher->op == BF_MATCHER_EQ ? BPF_JNE : BPF_JEQ,
41 : BPF_REG_1, BPF_REG_2, 0));
42 :
43 0 : return 0;
44 : }
45 :
46 0 : static int _bf_matcher_generate_ip4_addr_set(struct bf_program *program,
47 : const struct bf_matcher *matcher)
48 : {
49 : uint32_t set_id;
50 : struct bf_set *set;
51 : int16_t offset;
52 :
53 0 : bf_assert(program);
54 0 : bf_assert(matcher);
55 :
56 0 : set_id = *(uint32_t *)matcher->payload;
57 0 : set = bf_list_get_at(&program->runtime.chain->sets, set_id);
58 :
59 0 : switch (set->type) {
60 0 : case BF_SET_IP4:
61 0 : offset = matcher->type == BF_MATCHER_IP4_SADDR ?
62 : offsetof(struct iphdr, saddr) :
63 : offsetof(struct iphdr, daddr);
64 0 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_6, offset));
65 0 : EMIT(program,
66 : BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, BF_PROG_SCR_OFF(0)));
67 : break;
68 0 : default:
69 0 : return bf_err_r(-EINVAL, "unsupported set type: %s",
70 : bf_set_type_to_str(set->type));
71 : }
72 :
73 0 : EMIT_LOAD_SET_FD_FIXUP(program, BPF_REG_1, set_id);
74 0 : EMIT(program, BPF_MOV64_REG(BPF_REG_2, BPF_REG_10));
75 0 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, BF_PROG_SCR_OFF(0)));
76 :
77 0 : EMIT(program, BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem));
78 :
79 : // Jump to the next rule if map_lookup_elem returned 0
80 0 : EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
81 :
82 0 : return 0;
83 : }
84 :
85 0 : static int _bf_matcher_generate_ip4_addr(struct bf_program *program,
86 : const struct bf_matcher *matcher)
87 : {
88 0 : switch (matcher->op) {
89 0 : case BF_MATCHER_EQ:
90 : case BF_MATCHER_NE:
91 0 : return _bf_matcher_generate_ip4_addr_unique(program, matcher);
92 0 : case BF_MATCHER_IN:
93 0 : return _bf_matcher_generate_ip4_addr_set(program, matcher);
94 : default:
95 : return -EINVAL;
96 : }
97 :
98 : return 0;
99 : }
100 :
101 0 : static int _bf_matcher_generate_ip4_proto(struct bf_program *program,
102 : const struct bf_matcher *matcher)
103 : {
104 0 : uint8_t proto = *(uint8_t *)&matcher->payload;
105 :
106 0 : EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_6,
107 : offsetof(struct iphdr, protocol)));
108 0 : EMIT_FIXUP_JMP_NEXT_RULE(
109 : program, BPF_JMP_IMM(matcher->op == BF_MATCHER_EQ ? BPF_JNE : BPF_JEQ,
110 : BPF_REG_1, proto, 0));
111 :
112 0 : return 0;
113 : }
114 :
115 0 : static int _bf_matcher_generate_ip4_net_single(struct bf_program *program,
116 : const struct bf_matcher *matcher)
117 : {
118 : struct bf_matcher_ip4_addr *addr =
119 : (struct bf_matcher_ip4_addr *)&matcher->payload;
120 0 : size_t offset = matcher->type == BF_MATCHER_IP4_SNET ?
121 0 : offsetof(struct iphdr, saddr) :
122 : offsetof(struct iphdr, daddr);
123 :
124 0 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_6, offset));
125 0 : EMIT(program, BPF_MOV32_IMM(BPF_REG_2, addr->addr));
126 :
127 0 : if (addr->mask != ~0U) {
128 0 : EMIT(program, BPF_MOV32_IMM(BPF_REG_3, addr->mask));
129 0 : EMIT(program, BPF_ALU32_REG(BPF_AND, BPF_REG_1, BPF_REG_3));
130 0 : EMIT(program, BPF_ALU32_REG(BPF_AND, BPF_REG_2, BPF_REG_3));
131 : }
132 :
133 0 : EMIT_FIXUP_JMP_NEXT_RULE(
134 : program, BPF_JMP_REG(matcher->op == BF_MATCHER_EQ ? BPF_JNE : BPF_JEQ,
135 : BPF_REG_1, BPF_REG_2, 0));
136 :
137 0 : return 0;
138 : }
139 :
140 0 : static int _bf_matcher_generate_ip4_net_in(struct bf_program *program,
141 : const struct bf_matcher *matcher)
142 : {
143 : uint32_t set_id;
144 : struct bf_set *set;
145 : int16_t offset;
146 :
147 0 : bf_assert(program && matcher);
148 :
149 0 : set_id = *(uint32_t *)matcher->payload;
150 0 : set = bf_list_get_at(&program->runtime.chain->sets, set_id);
151 0 : if (!set)
152 0 : return bf_err_r(-ENOENT, "set #%d not found", set_id);
153 :
154 0 : switch (set->type) {
155 0 : case BF_SET_IP4_SUBNET:
156 0 : offset = matcher->type == BF_MATCHER_IP4_SNET ?
157 : offsetof(struct iphdr, saddr) :
158 : offsetof(struct iphdr, daddr);
159 0 : EMIT(program, BPF_MOV64_IMM(BPF_REG_3, 32));
160 0 : EMIT(program,
161 : BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_3, BF_PROG_SCR_OFF(0)));
162 0 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_6, offset));
163 0 : EMIT(program,
164 : BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, BF_PROG_SCR_OFF(4)));
165 : break;
166 0 : default:
167 0 : return bf_err_r(-EINVAL, "unsupported set type: %s",
168 : bf_set_type_to_str(set->type));
169 : }
170 :
171 0 : EMIT_LOAD_SET_FD_FIXUP(program, BPF_REG_1, set_id);
172 0 : EMIT(program, BPF_MOV64_REG(BPF_REG_2, BPF_REG_10));
173 0 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, BF_PROG_SCR_OFF(0)));
174 :
175 0 : EMIT(program, BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem));
176 :
177 : // Jump to the next rule if map_lookup_elem returned 0
178 0 : EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
179 :
180 0 : return 0;
181 : }
182 :
183 0 : static int _bf_matcher_generate_ip4_net(struct bf_program *program,
184 : const struct bf_matcher *matcher)
185 : {
186 0 : bf_assert(program && matcher);
187 :
188 : int r;
189 :
190 0 : switch (matcher->op) {
191 0 : case BF_MATCHER_EQ:
192 : case BF_MATCHER_NE:
193 0 : r = _bf_matcher_generate_ip4_net_single(program, matcher);
194 0 : break;
195 0 : case BF_MATCHER_IN:
196 0 : r = _bf_matcher_generate_ip4_net_in(program, matcher);
197 0 : break;
198 0 : default:
199 0 : return bf_err_r(-ENOTSUP, "unsupported operator %s for matcher %s",
200 : bf_matcher_type_to_str(matcher->type),
201 : bf_matcher_op_to_str(matcher->op));
202 : }
203 :
204 : return r;
205 : }
206 :
207 0 : int bf_matcher_generate_ip4(struct bf_program *program,
208 : const struct bf_matcher *matcher)
209 : {
210 : int r;
211 :
212 0 : EMIT_FIXUP_JMP_NEXT_RULE(
213 : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IP), 0));
214 :
215 0 : EMIT(program,
216 : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l3_hdr)));
217 :
218 0 : switch (matcher->type) {
219 0 : case BF_MATCHER_IP4_SADDR:
220 : case BF_MATCHER_IP4_DADDR:
221 0 : r = _bf_matcher_generate_ip4_addr(program, matcher);
222 0 : break;
223 0 : case BF_MATCHER_IP4_PROTO:
224 0 : r = _bf_matcher_generate_ip4_proto(program, matcher);
225 0 : break;
226 0 : case BF_MATCHER_IP4_SNET:
227 : case BF_MATCHER_IP4_DNET:
228 0 : r = _bf_matcher_generate_ip4_net(program, matcher);
229 0 : break;
230 0 : default:
231 0 : return bf_err_r(-EINVAL, "unknown matcher type %d", matcher->type);
232 : };
233 :
234 : if (r)
235 : return r;
236 :
237 : return 0;
238 : }
|