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/set.h"
7 :
8 : #include <linux/bpf.h>
9 : #include <linux/bpf_common.h>
10 : #include <linux/if_ether.h>
11 : #include <linux/in.h> // NOLINT
12 : #include <linux/ipv6.h>
13 : #include <linux/tcp.h>
14 : #include <linux/udp.h>
15 :
16 : #include <endian.h>
17 : #include <errno.h>
18 : #include <stddef.h>
19 : #include <stdint.h>
20 :
21 : #include "bpfilter/cgen/program.h"
22 : #include "bpfilter/cgen/swich.h"
23 : #include "core/helper.h"
24 : #include "core/logger.h"
25 : #include "core/matcher.h"
26 :
27 : #include "external/filter.h"
28 :
29 0 : int _bf_matcher_generate_set_ip6port(struct bf_program *program,
30 : const struct bf_matcher *matcher)
31 : {
32 0 : _cleanup_bf_swich_ struct bf_swich swich;
33 : uint32_t set_id;
34 : int r;
35 :
36 0 : bf_assert(program);
37 0 : bf_assert(matcher);
38 :
39 0 : set_id = *(uint32_t *)matcher->payload;
40 :
41 : // Ensure IPv6, then load the header address into r6
42 0 : EMIT_FIXUP_JMP_NEXT_RULE(
43 : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IPV6), 0));
44 :
45 : // Get the source port into r2. If l4_proto is not UDP or TCP, jump to the next rule
46 0 : EMIT(program,
47 : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l4_hdr)));
48 0 : swich = bf_swich_get(program, BPF_REG_8);
49 0 : EMIT_SWICH_OPTION(&swich, IPPROTO_TCP,
50 : BPF_LDX_MEM(BPF_H, BPF_REG_3, BPF_REG_6,
51 : offsetof(struct tcphdr, source)));
52 0 : EMIT_SWICH_OPTION(&swich, IPPROTO_TCP,
53 : BPF_LDX_MEM(BPF_H, BPF_REG_3, BPF_REG_6,
54 : offsetof(struct udphdr, source)));
55 0 : EMIT_SWICH_DEFAULT(&swich, BPF_MOV64_IMM(BPF_REG_3, 0));
56 0 : r = bf_swich_generate(&swich);
57 0 : if (r)
58 0 : return bf_err_r(r, "failed to generate swich for meta.(s|d)port");
59 0 : EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_3, 0, 0));
60 :
61 : // Copy the source IPv6 address into r1 and r2
62 0 : EMIT(program,
63 : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l3_hdr)));
64 0 : EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6,
65 : offsetof(struct ipv6hdr, saddr)));
66 0 : EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_6,
67 : offsetof(struct ipv6hdr, saddr) + 8));
68 :
69 : // Prepare the key
70 0 : EMIT(program,
71 : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, BF_PROG_SCR_OFF(0)));
72 0 : EMIT(program,
73 : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, BF_PROG_SCR_OFF(8)));
74 0 : EMIT(program,
75 : BPF_STX_MEM(BPF_H, BPF_REG_10, BPF_REG_3, BF_PROG_SCR_OFF(16)));
76 :
77 : // Call bpf_map_lookup_elem(r1=map_fd, r2=key_addr)
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 0 : EMIT(program, BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem));
82 :
83 : // Key not found? Jump to the next rule
84 0 : EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
85 :
86 0 : return 0;
87 : }
88 :
89 0 : int _bf_matcher_generate_set_ip6(struct bf_program *program,
90 : const struct bf_matcher *matcher)
91 : {
92 : uint32_t set_id;
93 :
94 0 : bf_assert(program && matcher);
95 :
96 0 : set_id = *(uint32_t *)matcher->payload;
97 :
98 : // Ensure IPv6, then loader the header address into r6
99 0 : EMIT_FIXUP_JMP_NEXT_RULE(
100 : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IPV6), 0));
101 0 : EMIT(program,
102 : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l3_hdr)));
103 :
104 : // Copy the source IPv6 address into r1 and r2
105 0 : EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6,
106 : offsetof(struct ipv6hdr, saddr)));
107 0 : EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_6,
108 : offsetof(struct ipv6hdr, saddr) + 8));
109 :
110 : // Prepare the key
111 0 : EMIT(program,
112 : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, BF_PROG_SCR_OFF(0)));
113 0 : EMIT(program,
114 : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, BF_PROG_SCR_OFF(8)));
115 :
116 : // Call bpf_map_lookup_elem(r1=map_fd, r2=key_addr)
117 0 : EMIT_LOAD_SET_FD_FIXUP(program, BPF_REG_1, set_id);
118 0 : EMIT(program, BPF_MOV64_REG(BPF_REG_2, BPF_REG_10));
119 0 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, BF_PROG_SCR_OFF(0)));
120 0 : EMIT(program, BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem));
121 :
122 : // Key not found? Jump to the next rule
123 0 : EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
124 :
125 0 : return 0;
126 : }
127 :
128 0 : int bf_matcher_generate_set(struct bf_program *program,
129 : const struct bf_matcher *matcher)
130 : {
131 : int r;
132 :
133 0 : switch (matcher->type) {
134 0 : case BF_MATCHER_SET_SRCIP6PORT:
135 0 : r = _bf_matcher_generate_set_ip6port(program, matcher);
136 0 : break;
137 0 : case BF_MATCHER_SET_SRCIP6:
138 0 : r = _bf_matcher_generate_set_ip6(program, matcher);
139 0 : break;
140 0 : default:
141 0 : return bf_err_r(-EINVAL, "unknown matcher type %d", matcher->type);
142 : };
143 :
144 : if (r)
145 : return r;
146 :
147 : return 0;
148 : }
|