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 : struct bf_matcher_ip4_addr *addr = (void *)&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->addr));
38 :
39 0 : if (addr->mask != ~0U) {
40 0 : EMIT(program, BPF_MOV32_IMM(BPF_REG_3, addr->mask));
41 0 : EMIT(program, BPF_ALU32_REG(BPF_AND, BPF_REG_1, BPF_REG_3));
42 0 : EMIT(program, BPF_ALU32_REG(BPF_AND, BPF_REG_2, BPF_REG_3));
43 : }
44 :
45 0 : EMIT_FIXUP_JMP_NEXT_RULE(
46 : program, BPF_JMP_REG(matcher->op == BF_MATCHER_EQ ? BPF_JNE : BPF_JEQ,
47 : BPF_REG_1, BPF_REG_2, 0));
48 :
49 0 : return 0;
50 : }
51 :
52 0 : static int _bf_matcher_generate_ip4_addr_set(struct bf_program *program,
53 : const struct bf_matcher *matcher)
54 : {
55 : uint32_t set_id;
56 : struct bf_set *set;
57 : int16_t offset;
58 :
59 0 : bf_assert(program);
60 0 : bf_assert(matcher);
61 :
62 0 : set_id = *(uint32_t *)matcher->payload;
63 0 : set = bf_list_get_at(&program->runtime.chain->sets, set_id);
64 :
65 0 : switch (set->type) {
66 0 : case BF_SET_IP4:
67 0 : offset = matcher->type == BF_MATCHER_IP4_SADDR ?
68 : offsetof(struct iphdr, saddr) :
69 : offsetof(struct iphdr, daddr);
70 0 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_6, offset));
71 0 : EMIT(program,
72 : BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, BF_PROG_SCR_OFF(0)));
73 : break;
74 0 : default:
75 0 : return bf_err_r(-EINVAL, "unsupported set type: %s",
76 : bf_set_type_to_str(set->type));
77 : }
78 :
79 0 : EMIT_LOAD_SET_FD_FIXUP(program, BPF_REG_1, set_id);
80 0 : EMIT(program, BPF_MOV64_REG(BPF_REG_2, BPF_REG_10));
81 0 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, BF_PROG_SCR_OFF(0)));
82 :
83 0 : EMIT(program, BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem));
84 :
85 : // Jump to the next rule if map_lookup_elem returned 0
86 0 : EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
87 :
88 0 : return 0;
89 : }
90 :
91 0 : static int _bf_matcher_generate_ip4_addr(struct bf_program *program,
92 : const struct bf_matcher *matcher)
93 : {
94 0 : switch (matcher->op) {
95 0 : case BF_MATCHER_EQ:
96 : case BF_MATCHER_NE:
97 0 : return _bf_matcher_generate_ip4_addr_unique(program, matcher);
98 0 : case BF_MATCHER_IN:
99 0 : return _bf_matcher_generate_ip4_addr_set(program, matcher);
100 : default:
101 : return -EINVAL;
102 : }
103 :
104 : return 0;
105 : }
106 :
107 0 : static int _bf_matcher_generate_ip4_proto(struct bf_program *program,
108 : const struct bf_matcher *matcher)
109 : {
110 0 : uint8_t proto = *(uint8_t *)&matcher->payload;
111 :
112 0 : EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_6,
113 : offsetof(struct iphdr, protocol)));
114 0 : EMIT_FIXUP_JMP_NEXT_RULE(
115 : program, BPF_JMP_IMM(matcher->op == BF_MATCHER_EQ ? BPF_JNE : BPF_JEQ,
116 : BPF_REG_1, proto, 0));
117 :
118 0 : return 0;
119 : }
120 :
121 0 : static int _bf_matcher_generate_ip4_net(struct bf_program *program,
122 : const struct bf_matcher *matcher)
123 : {
124 : uint32_t set_id;
125 : struct bf_set *set;
126 : int16_t offset;
127 :
128 0 : bf_assert(program && matcher);
129 :
130 0 : set_id = *(uint32_t *)matcher->payload;
131 0 : set = bf_list_get_at(&program->runtime.chain->sets, set_id);
132 0 : if (!set)
133 0 : return bf_err_r(-ENOENT, "set #%d not found", set_id);
134 :
135 0 : switch (set->type) {
136 0 : case BF_SET_IP4_SUBNET:
137 0 : offset = matcher->type == BF_MATCHER_IP4_SNET ?
138 : offsetof(struct iphdr, saddr) :
139 : offsetof(struct iphdr, daddr);
140 0 : EMIT(program, BPF_MOV64_IMM(BPF_REG_3, 32));
141 0 : EMIT(program,
142 : BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_3, BF_PROG_SCR_OFF(0)));
143 0 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_6, offset));
144 0 : EMIT(program,
145 : BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, BF_PROG_SCR_OFF(4)));
146 : break;
147 0 : default:
148 0 : return bf_err_r(-EINVAL, "unsupported set type: %s",
149 : bf_set_type_to_str(set->type));
150 : }
151 :
152 0 : EMIT_LOAD_SET_FD_FIXUP(program, BPF_REG_1, set_id);
153 0 : EMIT(program, BPF_MOV64_REG(BPF_REG_2, BPF_REG_10));
154 0 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, BF_PROG_SCR_OFF(0)));
155 :
156 0 : EMIT(program, BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem));
157 :
158 : // Jump to the next rule if map_lookup_elem returned 0
159 0 : EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
160 :
161 0 : return 0;
162 : }
163 :
164 0 : int bf_matcher_generate_ip4(struct bf_program *program,
165 : const struct bf_matcher *matcher)
166 : {
167 : int r;
168 :
169 0 : EMIT_FIXUP_JMP_NEXT_RULE(
170 : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IP), 0));
171 :
172 0 : EMIT(program,
173 : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l3_hdr)));
174 :
175 0 : switch (matcher->type) {
176 0 : case BF_MATCHER_IP4_SADDR:
177 : case BF_MATCHER_IP4_DADDR:
178 0 : r = _bf_matcher_generate_ip4_addr(program, matcher);
179 0 : break;
180 0 : case BF_MATCHER_IP4_PROTO:
181 0 : r = _bf_matcher_generate_ip4_proto(program, matcher);
182 0 : break;
183 0 : case BF_MATCHER_IP4_SNET:
184 : case BF_MATCHER_IP4_DNET:
185 0 : r = _bf_matcher_generate_ip4_net(program, matcher);
186 0 : break;
187 0 : default:
188 0 : return bf_err_r(-EINVAL, "unknown matcher type %d", matcher->type);
189 : };
190 :
191 : if (r)
192 : return r;
193 :
194 : return 0;
195 : }
|