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 0 : static int _bf_matcher_generate_ip4_addr(struct bf_program *program,
27 : const struct bf_matcher *matcher)
28 : {
29 0 : bf_assert(program && matcher);
30 :
31 0 : uint32_t *addr = (uint32_t *)bf_matcher_payload(matcher);
32 0 : size_t offset = bf_matcher_get_type(matcher) == 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));
38 :
39 0 : 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 0 : return 0;
46 : }
47 :
48 0 : static int _bf_matcher_generate_ip4_proto(struct bf_program *program,
49 : const struct bf_matcher *matcher)
50 : {
51 0 : bf_assert(program && matcher);
52 :
53 0 : uint8_t proto = *(uint8_t *)bf_matcher_payload(matcher);
54 :
55 0 : EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_6,
56 : offsetof(struct iphdr, protocol)));
57 0 : 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 0 : return 0;
64 : }
65 :
66 0 : static void _bf_ip4_prefix_to_mask(uint32_t prefixlen, uint8_t *mask)
67 : {
68 0 : bf_assert(mask);
69 :
70 0 : memset(mask, 0x00, 4);
71 :
72 0 : memset(mask, 0xff, prefixlen / 8);
73 0 : if (prefixlen % 8)
74 0 : mask[prefixlen / 8] = 0xff << (8 - prefixlen % 8) & 0xff;
75 0 : }
76 :
77 0 : static int _bf_matcher_generate_ip4_net(struct bf_program *program,
78 : const struct bf_matcher *matcher)
79 : {
80 0 : bf_assert(program && matcher);
81 :
82 : uint32_t mask;
83 : struct bf_ip4_lpm_key *addr =
84 0 : (struct bf_ip4_lpm_key *)bf_matcher_payload(matcher);
85 0 : size_t offset = bf_matcher_get_type(matcher) == BF_MATCHER_IP4_SNET ?
86 0 : offsetof(struct iphdr, saddr) :
87 : offsetof(struct iphdr, daddr);
88 :
89 0 : _bf_ip4_prefix_to_mask(addr->prefixlen, (void *)&mask);
90 :
91 0 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_6, offset));
92 0 : EMIT(program, BPF_MOV32_IMM(BPF_REG_2, addr->data));
93 :
94 0 : if (mask != ~0U) {
95 0 : EMIT(program, BPF_MOV32_IMM(BPF_REG_3, mask));
96 0 : EMIT(program, BPF_ALU32_REG(BPF_AND, BPF_REG_1, BPF_REG_3));
97 0 : EMIT(program, BPF_ALU32_REG(BPF_AND, BPF_REG_2, BPF_REG_3));
98 : }
99 :
100 0 : 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 0 : return 0;
107 : }
108 :
109 0 : int bf_matcher_generate_ip4(struct bf_program *program,
110 : const struct bf_matcher *matcher)
111 : {
112 0 : bf_assert(program && matcher);
113 :
114 : int r;
115 :
116 0 : EMIT_FIXUP_JMP_NEXT_RULE(
117 : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IP), 0));
118 :
119 0 : EMIT(program,
120 : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l3_hdr)));
121 :
122 0 : switch (bf_matcher_get_type(matcher)) {
123 0 : case BF_MATCHER_IP4_SADDR:
124 : case BF_MATCHER_IP4_DADDR:
125 0 : r = _bf_matcher_generate_ip4_addr(program, matcher);
126 0 : break;
127 0 : case BF_MATCHER_IP4_PROTO:
128 0 : r = _bf_matcher_generate_ip4_proto(program, matcher);
129 0 : break;
130 0 : case BF_MATCHER_IP4_SNET:
131 : case BF_MATCHER_IP4_DNET:
132 0 : r = _bf_matcher_generate_ip4_net(program, matcher);
133 0 : 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 : }
|