Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0-only */
2 : : /*
3 : : * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4 : : */
5 : :
6 : : #include "cgen/cgroup_skb.h"
7 : :
8 : : #include <linux/bpf_common.h>
9 : : #include <linux/if_ether.h>
10 : :
11 : : #include <stddef.h>
12 : : #include <stdint.h>
13 : : #include <sys/socket.h>
14 : :
15 : : #include <bpfilter/btf.h>
16 : : #include <bpfilter/flavor.h>
17 : : #include <bpfilter/helper.h>
18 : : #include <bpfilter/matcher.h>
19 : : #include <bpfilter/verdict.h>
20 : :
21 : : #include "cgen/matcher/cmp.h"
22 : : #include "cgen/packet.h"
23 : : #include "cgen/program.h"
24 : : #include "cgen/stub.h"
25 : : #include "cgen/swich.h"
26 : : #include "filter.h"
27 : : #include "linux/bpf.h"
28 : :
29 : : // Forward definition to avoid headers clusterfuck.
30 : : uint16_t htons(uint16_t hostshort);
31 : :
32 : 213 : static int _bf_cgroup_skb_gen_inline_prologue(struct bf_program *program)
33 : : {
34 : : int offset;
35 : : int r;
36 : :
37 : : assert(program);
38 : :
39 : : // Copy the packet size (+ETH_HLEN) into the runtime context
40 [ + - ]: 213 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
41 : : offsetof(struct __sk_buff, len)));
42 [ + - ]: 213 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, ETH_HLEN));
43 [ + - ]: 213 : EMIT(program,
44 : : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_3, BF_PROG_CTX_OFF(pkt_size)));
45 : :
46 : : /** The @c __sk_buff structure contains two fields related to the interface
47 : : * index: @c ingress_ifindex and @c ifindex . @c ingress_ifindex is the
48 : : * interface index the packet has been received on. However, we use
49 : : * @c ifindex which is the interface index the packet is processed by: if
50 : : * a packet is redirected locally from interface #1 to interface #2, then
51 : : * @c ingress_ifindex will contain @c 1 but @c ifindex will contains @c 2 .
52 : : * For egress, only @c ifindex is used.
53 : : */
54 [ + - ]: 213 : if ((r = bf_btf_get_field_off("__sk_buff", "ifindex")) < 0)
55 : : return r;
56 [ + - ]: 213 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, r));
57 [ + - ]: 213 : EMIT(program,
58 : : BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, BF_PROG_CTX_OFF(ifindex)));
59 : :
60 : : /* BPF_PROG_TYPE_CGROUP_SKB doesn't provide access the the Ethernet header,
61 : : * so we can't parse it and discover the L3 protocol ID.
62 : : * Instead, we use the __sk_buff.family value and convert it to the
63 : : * corresponding ethertype. */
64 [ + - ]: 213 : if ((offset = bf_btf_get_field_off("__sk_buff", "family")) < 0)
65 : : return offset;
66 [ + - ]: 213 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offset));
67 : :
68 : : {
69 : 213 : _clean_bf_swich_ struct bf_swich swich =
70 [ - + ]: 213 : bf_swich_get(program, BPF_REG_2);
71 : :
72 [ - + ]: 213 : EMIT_SWICH_OPTION(&swich, AF_INET,
73 : : BPF_MOV64_IMM(BPF_REG_7, htons(ETH_P_IP)));
74 [ - + ]: 213 : EMIT_SWICH_OPTION(&swich, AF_INET6,
75 : : BPF_MOV64_IMM(BPF_REG_7, htons(ETH_P_IPV6)));
76 [ - + ]: 213 : EMIT_SWICH_DEFAULT(&swich, BPF_MOV64_IMM(BPF_REG_7, 0));
77 : :
78 : 213 : r = bf_swich_generate(&swich);
79 [ + - ]: 213 : if (r)
80 : : return r;
81 : : }
82 : :
83 [ + - ]: 213 : EMIT(program, BPF_ST_MEM(BPF_W, BPF_REG_10, BF_PROG_CTX_OFF(l3_offset), 0));
84 : :
85 : 213 : r = bf_stub_make_ctx_skb_dynptr(program, BPF_REG_1);
86 [ + - ]: 213 : if (r)
87 : : return r;
88 : :
89 : 213 : r = bf_stub_parse_l3_hdr(program);
90 [ + - ]: 213 : if (r)
91 : : return r;
92 : :
93 : 213 : r = bf_stub_parse_l4_hdr(program);
94 : : if (r)
95 : : return r;
96 : :
97 : : return 0;
98 : : }
99 : :
100 : 212 : static int _bf_cgroup_skb_gen_inline_epilogue(struct bf_program *program)
101 : : {
102 : : (void)program;
103 : :
104 : 212 : return 0;
105 : : }
106 : :
107 : 4 : static int _bf_cgroup_skb_gen_inline_set_mark(struct bf_program *program,
108 : : uint32_t mark)
109 : : {
110 [ + - ]: 4 : EMIT(program,
111 : : BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, BF_PROG_CTX_OFF(arg)));
112 [ + - ]: 4 : EMIT(program, BPF_MOV64_IMM(BPF_REG_2, mark));
113 : 4 : EMIT(program, BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_2,
114 : : offsetof(struct __sk_buff, mark)));
115 : :
116 : : return 0;
117 : : }
118 : :
119 : 492 : static int _bf_cgroup_skb_gen_inline_matcher(struct bf_program *program,
120 : : const struct bf_matcher *matcher)
121 : : {
122 : : assert(program);
123 : : assert(matcher);
124 : :
125 [ + + ]: 492 : switch (bf_matcher_get_type(matcher)) {
126 : 12 : case BF_MATCHER_META_MARK:
127 [ + - ]: 12 : EMIT(program,
128 : : BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, BF_PROG_CTX_OFF(arg)));
129 [ + - ]: 12 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_1,
130 : : offsetof(struct __sk_buff, mark)));
131 : :
132 : 12 : return bf_cmp_value(program, bf_matcher_get_op(matcher),
133 : : bf_matcher_payload(matcher), 4, BPF_REG_1);
134 : 480 : default:
135 : 480 : return bf_packet_gen_inline_matcher(program, matcher);
136 : : }
137 : : }
138 : :
139 : : /**
140 : : * Convert a standard verdict into a return value.
141 : : *
142 : : * @param verdict Verdict to convert. Must be valid.
143 : : * @param ret_code Cgroup return code. Can't be NULL.
144 : : * @return 0 on success, or a negative errno value on failure.
145 : : */
146 : 1108 : static int _bf_cgroup_skb_get_verdict(enum bf_verdict verdict, int *ret_code)
147 : : {
148 : : assert(ret_code);
149 : :
150 [ + + - ]: 1108 : switch (verdict) {
151 : 899 : case BF_VERDICT_ACCEPT:
152 : : case BF_VERDICT_NEXT:
153 : 899 : *ret_code = 1;
154 : 899 : return 0;
155 : 209 : case BF_VERDICT_DROP:
156 : 209 : *ret_code = 0;
157 : 209 : return 0;
158 : : default:
159 : : return -ENOTSUP;
160 : : }
161 : : }
162 : :
163 : : const struct bf_flavor_ops bf_flavor_ops_cgroup_skb = {
164 : : .gen_inline_prologue = _bf_cgroup_skb_gen_inline_prologue,
165 : : .gen_inline_epilogue = _bf_cgroup_skb_gen_inline_epilogue,
166 : : .gen_inline_set_mark = _bf_cgroup_skb_gen_inline_set_mark,
167 : : .get_verdict = _bf_cgroup_skb_get_verdict,
168 : : .gen_inline_matcher = _bf_cgroup_skb_gen_inline_matcher,
169 : : .gen_inline_log = bf_packet_gen_inline_log,
170 : : };
|