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