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_2, BPF_REG_3));
42 : }
43 :
44 0 : EMIT_FIXUP_JMP_NEXT_RULE(
45 : program, BPF_JMP_REG(matcher->op == BF_MATCHER_EQ ? BPF_JNE : BPF_JEQ,
46 : BPF_REG_1, BPF_REG_2, 0));
47 :
48 0 : return 0;
49 : }
50 :
51 0 : static int _bf_matcher_generate_ip4_addr_set(struct bf_program *program,
52 : const struct bf_matcher *matcher)
53 : {
54 : uint32_t set_id;
55 : struct bf_set *set;
56 : int16_t offset;
57 :
58 0 : bf_assert(program);
59 0 : bf_assert(matcher);
60 :
61 0 : set_id = *(uint32_t *)matcher->payload;
62 0 : set = bf_list_get_at(&program->runtime.chain->sets, set_id);
63 :
64 0 : switch (set->type) {
65 0 : case BF_SET_IP4:
66 0 : offset = matcher->type == BF_MATCHER_IP4_SRC_ADDR ?
67 : offsetof(struct iphdr, saddr) :
68 : offsetof(struct iphdr, daddr);
69 0 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_6, offset));
70 0 : EMIT(program,
71 : BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, BF_PROG_SCR_OFF(0)));
72 : break;
73 0 : default:
74 0 : return bf_err_r(-EINVAL, "unsupported set type: %s",
75 : bf_set_type_to_str(set->type));
76 : }
77 :
78 0 : EMIT_LOAD_SET_FD_FIXUP(program, BPF_REG_1, set_id);
79 0 : EMIT(program, BPF_MOV64_REG(BPF_REG_2, BPF_REG_10));
80 0 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, BF_PROG_SCR_OFF(0)));
81 :
82 0 : EMIT(program, BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem));
83 :
84 : // Jump to the next rule if map_lookup_elem returned 0
85 0 : EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
86 :
87 0 : return 0;
88 : }
89 :
90 0 : static int _bf_matcher_generate_ip4_addr(struct bf_program *program,
91 : const struct bf_matcher *matcher)
92 : {
93 0 : switch (matcher->op) {
94 0 : case BF_MATCHER_EQ:
95 : case BF_MATCHER_NE:
96 0 : return _bf_matcher_generate_ip4_addr_unique(program, matcher);
97 0 : case BF_MATCHER_IN:
98 0 : return _bf_matcher_generate_ip4_addr_set(program, matcher);
99 : default:
100 : return -EINVAL;
101 : }
102 :
103 : return 0;
104 : }
105 :
106 0 : static int _bf_matcher_generate_ip4_proto(struct bf_program *program,
107 : const struct bf_matcher *matcher)
108 : {
109 0 : uint8_t proto = *(uint8_t *)&matcher->payload;
110 :
111 0 : EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_6,
112 : offsetof(struct iphdr, protocol)));
113 0 : EMIT_FIXUP_JMP_NEXT_RULE(
114 : program, BPF_JMP_IMM(matcher->op == BF_MATCHER_EQ ? BPF_JNE : BPF_JEQ,
115 : BPF_REG_1, proto, 0));
116 :
117 0 : return 0;
118 : }
119 :
120 0 : int bf_matcher_generate_ip4(struct bf_program *program,
121 : const struct bf_matcher *matcher)
122 : {
123 : int r;
124 :
125 0 : EMIT_FIXUP_JMP_NEXT_RULE(
126 : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IP), 0));
127 :
128 0 : EMIT(program,
129 : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l3_hdr)));
130 :
131 0 : switch (matcher->type) {
132 0 : case BF_MATCHER_IP4_SRC_ADDR:
133 : case BF_MATCHER_IP4_DST_ADDR:
134 0 : r = _bf_matcher_generate_ip4_addr(program, matcher);
135 0 : break;
136 0 : case BF_MATCHER_IP4_PROTO:
137 0 : r = _bf_matcher_generate_ip4_proto(program, matcher);
138 0 : break;
139 0 : default:
140 0 : return bf_err_r(-EINVAL, "unknown matcher type %d", matcher->type);
141 : };
142 :
143 : if (r)
144 : return r;
145 :
146 : return 0;
147 : }
|