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/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 <assert.h>
14 : : #include <endian.h>
15 : : #include <errno.h>
16 : : #include <stddef.h>
17 : : #include <stdint.h>
18 : :
19 : : #include <bpfilter/helper.h>
20 : : #include <bpfilter/logger.h>
21 : : #include <bpfilter/matcher.h>
22 : : #include <bpfilter/runtime.h>
23 : :
24 : : #include "cgen/program.h"
25 : : #include "filter.h"
26 : :
27 : 40 : static int _bf_matcher_generate_ip4_addr(struct bf_program *program,
28 : : const struct bf_matcher *matcher)
29 : : {
30 : : assert(program);
31 : : assert(matcher);
32 : :
33 : 40 : uint32_t *addr = (uint32_t *)bf_matcher_payload(matcher);
34 : 40 : size_t offset = bf_matcher_get_type(matcher) == BF_MATCHER_IP4_SADDR ?
35 [ + + ]: 40 : offsetof(struct iphdr, saddr) :
36 : : offsetof(struct iphdr, daddr);
37 : :
38 [ - + ]: 40 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_6, offset));
39 [ - + ]: 40 : EMIT(program, BPF_MOV32_IMM(BPF_REG_2, *addr));
40 : :
41 [ + + - + ]: 60 : EMIT_FIXUP_JMP_NEXT_RULE(
42 : : program,
43 : : BPF_JMP_REG(bf_matcher_get_op(matcher) == BF_MATCHER_EQ ? BPF_JNE :
44 : : BPF_JEQ,
45 : : BPF_REG_1, BPF_REG_2, 0));
46 : :
47 : 40 : return 0;
48 : : }
49 : :
50 : 64 : static int _bf_matcher_generate_ip4_proto(struct bf_program *program,
51 : : const struct bf_matcher *matcher)
52 : : {
53 : : assert(program);
54 : : assert(matcher);
55 : :
56 : 64 : uint8_t proto = *(uint8_t *)bf_matcher_payload(matcher);
57 : :
58 [ - + ]: 64 : EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_6,
59 : : offsetof(struct iphdr, protocol)));
60 [ - + - + ]: 64 : EMIT_FIXUP_JMP_NEXT_RULE(
61 : : program,
62 : : BPF_JMP_IMM(bf_matcher_get_op(matcher) == BF_MATCHER_EQ ? BPF_JNE :
63 : : BPF_JEQ,
64 : : BPF_REG_1, proto, 0));
65 : :
66 : 64 : return 0;
67 : : }
68 : :
69 : 0 : static int _bf_matcher_generate_ip4_dscp(struct bf_program *program,
70 : : const struct bf_matcher *matcher)
71 : : {
72 : : uint8_t dscp;
73 : :
74 : : assert(program);
75 : : assert(matcher);
76 : :
77 : 0 : dscp = *(uint8_t *)bf_matcher_payload(matcher);
78 : :
79 [ # # ]: 0 : EMIT(program,
80 : : BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_6, offsetof(struct iphdr, tos)));
81 [ # # # # ]: 0 : EMIT_FIXUP_JMP_NEXT_RULE(
82 : : program,
83 : : BPF_JMP_IMM(bf_matcher_get_op(matcher) == BF_MATCHER_EQ ? BPF_JNE :
84 : : BPF_JEQ,
85 : : BPF_REG_1, dscp, 0));
86 : :
87 : 0 : return 0;
88 : : }
89 : :
90 : 40 : static void _bf_ip4_prefix_to_mask(uint32_t prefixlen, uint8_t *mask)
91 : : {
92 : : assert(mask);
93 : :
94 : 40 : memset(mask, 0x00, 4);
95 : :
96 : 40 : memset(mask, 0xff, prefixlen / 8);
97 [ + + ]: 40 : if (prefixlen % 8)
98 : 30 : mask[prefixlen / 8] = 0xff << (8 - prefixlen % 8) & 0xff;
99 : 40 : }
100 : :
101 : 40 : static int _bf_matcher_generate_ip4_net(struct bf_program *program,
102 : : const struct bf_matcher *matcher)
103 : : {
104 : : assert(program);
105 : : assert(matcher);
106 : :
107 : : uint32_t mask;
108 : : struct bf_ip4_lpm_key *addr =
109 : 40 : (struct bf_ip4_lpm_key *)bf_matcher_payload(matcher);
110 : 40 : size_t offset = bf_matcher_get_type(matcher) == BF_MATCHER_IP4_SNET ?
111 [ + + ]: 40 : offsetof(struct iphdr, saddr) :
112 : : offsetof(struct iphdr, daddr);
113 : :
114 : 40 : _bf_ip4_prefix_to_mask(addr->prefixlen, (void *)&mask);
115 : :
116 [ - + ]: 40 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_6, offset));
117 [ - + ]: 40 : EMIT(program, BPF_MOV32_IMM(BPF_REG_2, addr->data));
118 : :
119 [ + - ]: 40 : if (mask != ~0U) {
120 [ - + ]: 40 : EMIT(program, BPF_MOV32_IMM(BPF_REG_3, mask));
121 [ - + ]: 40 : EMIT(program, BPF_ALU32_REG(BPF_AND, BPF_REG_1, BPF_REG_3));
122 [ - + ]: 40 : EMIT(program, BPF_ALU32_REG(BPF_AND, BPF_REG_2, BPF_REG_3));
123 : : }
124 : :
125 [ + + - + ]: 60 : EMIT_FIXUP_JMP_NEXT_RULE(
126 : : program,
127 : : BPF_JMP_REG(bf_matcher_get_op(matcher) == BF_MATCHER_EQ ? BPF_JNE :
128 : : BPF_JEQ,
129 : : BPF_REG_1, BPF_REG_2, 0));
130 : :
131 : 40 : return 0;
132 : : }
133 : :
134 : 144 : int bf_matcher_generate_ip4(struct bf_program *program,
135 : : const struct bf_matcher *matcher)
136 : : {
137 : : assert(program);
138 : : assert(matcher);
139 : :
140 : : int r;
141 : :
142 [ - + ]: 144 : EMIT_FIXUP_JMP_NEXT_RULE(
143 : : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IP), 0));
144 : :
145 [ - + ]: 144 : EMIT(program,
146 : : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l3_hdr)));
147 : :
148 [ + + - + : 144 : switch (bf_matcher_get_type(matcher)) {
- ]
149 : 40 : case BF_MATCHER_IP4_SADDR:
150 : : case BF_MATCHER_IP4_DADDR:
151 : 40 : r = _bf_matcher_generate_ip4_addr(program, matcher);
152 : 40 : break;
153 : 64 : case BF_MATCHER_IP4_PROTO:
154 : 64 : r = _bf_matcher_generate_ip4_proto(program, matcher);
155 : 64 : break;
156 : 0 : case BF_MATCHER_IP4_DSCP:
157 : 0 : r = _bf_matcher_generate_ip4_dscp(program, matcher);
158 : 0 : break;
159 : 40 : case BF_MATCHER_IP4_SNET:
160 : : case BF_MATCHER_IP4_DNET:
161 : 40 : r = _bf_matcher_generate_ip4_net(program, matcher);
162 : 40 : break;
163 : 0 : default:
164 [ # # ]: 0 : return bf_err_r(-EINVAL, "unknown matcher type %d",
165 : : bf_matcher_get_type(matcher));
166 : : };
167 : :
168 : : if (r)
169 : : return r;
170 : :
171 : : return 0;
172 : : }
|