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