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_SRC_ADDR ?
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_SRC_ADDR ?
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 : int bf_matcher_generate_ip4(struct bf_program *program,
122 : const struct bf_matcher *matcher)
123 : {
124 : int r;
125 :
126 0 : EMIT_FIXUP_JMP_NEXT_RULE(
127 : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IP), 0));
128 :
129 0 : EMIT(program,
130 : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l3_hdr)));
131 :
132 0 : switch (matcher->type) {
133 0 : case BF_MATCHER_IP4_SRC_ADDR:
134 : case BF_MATCHER_IP4_DST_ADDR:
135 0 : r = _bf_matcher_generate_ip4_addr(program, matcher);
136 0 : break;
137 0 : case BF_MATCHER_IP4_PROTO:
138 0 : r = _bf_matcher_generate_ip4_proto(program, matcher);
139 0 : break;
140 0 : default:
141 0 : return bf_err_r(-EINVAL, "unknown matcher type %d", matcher->type);
142 : };
143 :
144 : if (r)
145 : return r;
146 :
147 : return 0;
148 : }
|