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