Skip to content

Commit aef2e84

Browse files
committed
daemon: cgen: route matcher codegen through flavor-specific dispatch
Replace gen_inline_get_mark and gen_inline_get_skb in bf_flavor_ops with a single gen_inline_matcher callback that gives each flavor full control over matcher codegen. Packet-based flavors intercept matcher types they handle specially (e.g., meta.mark on __sk_buff-based flavors) and delegate the rest to bf_matcher_generate_packet(). Extract bf_matcher_generate_packet() from program.c into cgen/ matcher/packet.{h,c} where it belongs alongside the matcher codegen it dispatches to. Export bf_matcher_generate_meta_mark() and bf_matcher_generate_meta_flow_hash() as comparison-only helpers. Callers load the value into BPF_REG_1 before calling. This is a prerequisite for CGROUP_SOCK_ADDR support, where the flavor needs to intercept matchers like ip4.daddr and generate bytecode that reads from bpf_sock_addr fields instead of packet headers.
1 parent a65aca1 commit aef2e84

File tree

11 files changed

+266
-153
lines changed

11 files changed

+266
-153
lines changed

src/bpfilter/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ add_executable(bpfilter
2727
${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/tcp.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/tcp.c
2828
${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/udp.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/udp.c
2929
${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/meta.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/meta.c
30+
${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/packet.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/packet.c
3031
${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/set.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/set.c
3132
${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/icmp.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/icmp.c
3233
${CMAKE_CURRENT_SOURCE_DIR}/cgen/nf.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/nf.c

src/bpfilter/cgen/cgroup_skb.c

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
#include <bpfilter/btf.h>
1616
#include <bpfilter/flavor.h>
1717
#include <bpfilter/helper.h>
18+
#include <bpfilter/matcher.h>
1819
#include <bpfilter/verdict.h>
1920

2021
#include "cgen/cgen.h"
22+
#include "cgen/matcher/meta.h"
23+
#include "cgen/matcher/packet.h"
2124
#include "cgen/program.h"
2225
#include "cgen/stub.h"
2326
#include "cgen/swich.h"
@@ -114,30 +117,33 @@ static int _bf_cgroup_skb_gen_inline_set_mark(struct bf_program *program,
114117
return 0;
115118
}
116119

117-
static int _bf_cgroup_skb_gen_inline_get_mark(struct bf_program *program,
118-
int reg)
120+
static int _bf_cgroup_skb_gen_inline_matcher(struct bf_program *program,
121+
const struct bf_matcher *matcher)
119122
{
120-
EMIT(program,
121-
BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, BF_PROG_CTX_OFF(arg)));
122-
EMIT(program,
123-
BPF_LDX_MEM(BPF_W, reg, BPF_REG_1, offsetof(struct __sk_buff, mark)));
124-
125-
return 0;
126-
}
127-
128-
static int _bf_cgroup_skb_gen_inline_get_skb(struct bf_program *program,
129-
int reg)
130-
{
131-
EMIT(program, BPF_LDX_MEM(BPF_DW, reg, BPF_REG_10, BF_PROG_CTX_OFF(arg)));
132-
133-
return 0;
123+
assert(program);
124+
assert(matcher);
125+
126+
switch (bf_matcher_get_type(matcher)) {
127+
case BF_MATCHER_META_MARK:
128+
EMIT(program,
129+
BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, BF_PROG_CTX_OFF(arg)));
130+
EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_1,
131+
offsetof(struct __sk_buff, mark)));
132+
return bf_matcher_generate_meta_mark(program, matcher);
133+
case BF_MATCHER_META_FLOW_HASH:
134+
EMIT(program,
135+
BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, BF_PROG_CTX_OFF(arg)));
136+
return bf_matcher_generate_meta_flow_hash(program, matcher);
137+
default:
138+
return bf_matcher_generate_packet(program, matcher);
139+
}
134140
}
135141

136142
/**
137143
* Convert a standard verdict into a return value.
138144
*
139145
* @param verdict Verdict to convert. Must be valid.
140-
* @return TC return code corresponding to the verdict, as an integer.
146+
* @return Cgroup return code corresponding to the verdict, as an integer.
141147
*/
142148
static int _bf_cgroup_skb_get_verdict(enum bf_verdict verdict)
143149
{
@@ -155,7 +161,6 @@ const struct bf_flavor_ops bf_flavor_ops_cgroup_skb = {
155161
.gen_inline_prologue = _bf_cgroup_skb_gen_inline_prologue,
156162
.gen_inline_epilogue = _bf_cgroup_skb_gen_inline_epilogue,
157163
.gen_inline_set_mark = _bf_cgroup_skb_gen_inline_set_mark,
158-
.gen_inline_get_mark = _bf_cgroup_skb_gen_inline_get_mark,
159-
.gen_inline_get_skb = _bf_cgroup_skb_gen_inline_get_skb,
160164
.get_verdict = _bf_cgroup_skb_get_verdict,
165+
.gen_inline_matcher = _bf_cgroup_skb_gen_inline_matcher,
161166
};

src/bpfilter/cgen/matcher/meta.c

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -141,15 +141,15 @@ static int _bf_matcher_generate_meta_port(struct bf_program *program,
141141
return 0;
142142
}
143143

144-
static int _bf_matcher_generate_meta_mark(struct bf_program *program,
145-
const struct bf_matcher *matcher)
144+
int bf_matcher_generate_meta_mark(struct bf_program *program,
145+
const struct bf_matcher *matcher)
146146
{
147-
uint32_t mark = *(uint32_t *)bf_matcher_payload(matcher);
148-
int r;
147+
uint32_t mark;
149148

150-
r = program->runtime.ops->gen_inline_get_mark(program, BPF_REG_1);
151-
if (r)
152-
return bf_err_r(r, "failed to get inline mark");
149+
assert(program);
150+
assert(matcher);
151+
152+
mark = *(uint32_t *)bf_matcher_payload(matcher);
153153

154154
switch (bf_matcher_get_op(matcher)) {
155155
case BF_MATCHER_EQ:
@@ -169,15 +169,15 @@ static int _bf_matcher_generate_meta_mark(struct bf_program *program,
169169
return 0;
170170
}
171171

172-
static int _bf_matcher_generate_meta_flow_hash(struct bf_program *program,
173-
const struct bf_matcher *matcher)
172+
int bf_matcher_generate_meta_flow_hash(struct bf_program *program,
173+
const struct bf_matcher *matcher)
174174
{
175-
uint32_t *hash = (uint32_t *)bf_matcher_payload(matcher);
176-
int r;
175+
uint32_t *hash;
177176

178-
r = program->runtime.ops->gen_inline_get_skb(program, BPF_REG_1);
179-
if (r)
180-
return bf_err_r(r, "failed to get inline skb");
177+
assert(program);
178+
assert(matcher);
179+
180+
hash = (uint32_t *)bf_matcher_payload(matcher);
181181

182182
EMIT(program, BPF_EMIT_CALL(BPF_FUNC_get_hash_recalc));
183183

@@ -276,12 +276,6 @@ int bf_matcher_generate_meta(struct bf_program *program,
276276
case BF_MATCHER_META_DPORT:
277277
r = _bf_matcher_generate_meta_port(program, matcher);
278278
break;
279-
case BF_MATCHER_META_MARK:
280-
r = _bf_matcher_generate_meta_mark(program, matcher);
281-
break;
282-
case BF_MATCHER_META_FLOW_HASH:
283-
r = _bf_matcher_generate_meta_flow_hash(program, matcher);
284-
break;
285279
case BF_MATCHER_META_FLOW_PROBABILITY:
286280
r = _bf_matcher_generate_meta_flow_probability(program, matcher);
287281
break;

src/bpfilter/cgen/matcher/meta.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,31 @@ struct bf_program;
1010

1111
int bf_matcher_generate_meta(struct bf_program *program,
1212
const struct bf_matcher *matcher);
13+
14+
/**
15+
* @brief Generate bytecode to compare a mark value already loaded in
16+
* @c BPF_REG_1 against the matcher's payload.
17+
*
18+
* The caller is responsible for loading the mark value into @c BPF_REG_1
19+
* before calling this function.
20+
*
21+
* @param program Program being generated. Can't be NULL.
22+
* @param matcher Matcher to generate comparison for. Can't be NULL.
23+
* @return 0 on success, negative errno on error.
24+
*/
25+
int bf_matcher_generate_meta_mark(struct bf_program *program,
26+
const struct bf_matcher *matcher);
27+
28+
/**
29+
* @brief Generate bytecode to compute and compare a flow hash. The skb pointer
30+
* must already be loaded in @c BPF_REG_1 before calling this function.
31+
*
32+
* Calls @c bpf_get_hash_recalc on the skb, then compares the result against
33+
* the matcher's payload.
34+
*
35+
* @param program Program being generated. Can't be NULL.
36+
* @param matcher Matcher to generate comparison for. Can't be NULL.
37+
* @return 0 on success, negative errno on error.
38+
*/
39+
int bf_matcher_generate_meta_flow_hash(struct bf_program *program,
40+
const struct bf_matcher *matcher);

src/bpfilter/cgen/matcher/packet.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4+
*/
5+
6+
#include "cgen/matcher/packet.h"
7+
8+
#include <errno.h>
9+
10+
#include <bpfilter/helper.h>
11+
#include <bpfilter/logger.h>
12+
#include <bpfilter/matcher.h>
13+
14+
#include "cgen/matcher/icmp.h"
15+
#include "cgen/matcher/ip4.h"
16+
#include "cgen/matcher/ip6.h"
17+
#include "cgen/matcher/meta.h"
18+
#include "cgen/matcher/set.h"
19+
#include "cgen/matcher/tcp.h"
20+
#include "cgen/matcher/udp.h"
21+
#include "cgen/program.h"
22+
23+
int bf_matcher_generate_packet(struct bf_program *program,
24+
const struct bf_matcher *matcher)
25+
{
26+
int r;
27+
28+
assert(program);
29+
assert(matcher);
30+
31+
switch (bf_matcher_get_type(matcher)) {
32+
case BF_MATCHER_META_IFACE:
33+
case BF_MATCHER_META_L3_PROTO:
34+
case BF_MATCHER_META_L4_PROTO:
35+
case BF_MATCHER_META_PROBABILITY:
36+
case BF_MATCHER_META_SPORT:
37+
case BF_MATCHER_META_DPORT:
38+
case BF_MATCHER_META_FLOW_PROBABILITY:
39+
r = bf_matcher_generate_meta(program, matcher);
40+
if (r)
41+
return r;
42+
break;
43+
case BF_MATCHER_META_MARK:
44+
case BF_MATCHER_META_FLOW_HASH:
45+
return bf_err_r(-ENOTSUP,
46+
"matcher '%s' is not supported by this flavor",
47+
bf_matcher_type_to_str(bf_matcher_get_type(matcher)));
48+
case BF_MATCHER_IP4_SADDR:
49+
case BF_MATCHER_IP4_SNET:
50+
case BF_MATCHER_IP4_DADDR:
51+
case BF_MATCHER_IP4_DNET:
52+
case BF_MATCHER_IP4_PROTO:
53+
case BF_MATCHER_IP4_DSCP:
54+
r = bf_matcher_generate_ip4(program, matcher);
55+
if (r)
56+
return r;
57+
break;
58+
case BF_MATCHER_IP6_SADDR:
59+
case BF_MATCHER_IP6_SNET:
60+
case BF_MATCHER_IP6_DADDR:
61+
case BF_MATCHER_IP6_DNET:
62+
case BF_MATCHER_IP6_NEXTHDR:
63+
case BF_MATCHER_IP6_DSCP:
64+
r = bf_matcher_generate_ip6(program, matcher);
65+
if (r)
66+
return r;
67+
break;
68+
case BF_MATCHER_TCP_SPORT:
69+
case BF_MATCHER_TCP_DPORT:
70+
case BF_MATCHER_TCP_FLAGS:
71+
r = bf_matcher_generate_tcp(program, matcher);
72+
if (r)
73+
return r;
74+
break;
75+
case BF_MATCHER_UDP_SPORT:
76+
case BF_MATCHER_UDP_DPORT:
77+
r = bf_matcher_generate_udp(program, matcher);
78+
if (r)
79+
return r;
80+
break;
81+
case BF_MATCHER_ICMP_TYPE:
82+
case BF_MATCHER_ICMP_CODE:
83+
case BF_MATCHER_ICMPV6_TYPE:
84+
case BF_MATCHER_ICMPV6_CODE:
85+
r = bf_matcher_generate_icmp(program, matcher);
86+
if (r)
87+
return r;
88+
break;
89+
case BF_MATCHER_SET:
90+
r = bf_matcher_generate_set(program, matcher);
91+
if (r)
92+
return r;
93+
break;
94+
default:
95+
return bf_err_r(-EINVAL, "unknown matcher type %d",
96+
bf_matcher_get_type(matcher));
97+
};
98+
99+
return 0;
100+
}

src/bpfilter/cgen/matcher/packet.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4+
*/
5+
6+
#pragma once
7+
8+
struct bf_matcher;
9+
struct bf_program;
10+
11+
/**
12+
* @brief Generate bytecode for a packet-based matcher.
13+
*
14+
* Dispatches to the appropriate matcher codegen function based on the matcher
15+
* type. Handles all matchers that operate on packet headers or metadata common
16+
* to all packet-based flavors.
17+
*
18+
* `BF_MATCHER_META_MARK` and `BF_MATCHER_META_FLOW_HASH` are not supported
19+
* by this function and return `-ENOTSUP`, as they require flavor-specific
20+
* context access.
21+
*
22+
* @param program Program being generated. Can't be NULL.
23+
* @param matcher Matcher to generate code for. Can't be NULL.
24+
* @return 0 on success, negative errno on error.
25+
*/
26+
int bf_matcher_generate_packet(struct bf_program *program,
27+
const struct bf_matcher *matcher);

src/bpfilter/cgen/nf.c

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@
1919
#include <bpfilter/flavor.h>
2020
#include <bpfilter/helper.h>
2121
#include <bpfilter/hook.h>
22+
#include <bpfilter/matcher.h>
2223
#include <bpfilter/verdict.h>
2324

2425
#include "cgen/jmp.h"
26+
#include "cgen/matcher/meta.h"
27+
#include "cgen/matcher/packet.h"
2528
#include "cgen/program.h"
2629
#include "cgen/stub.h"
2730
#include "cgen/swich.h"
@@ -124,39 +127,42 @@ static int _bf_nf_gen_inline_epilogue(struct bf_program *program)
124127
return 0;
125128
}
126129

127-
static int _bf_nf_gen_inline_get_mark(struct bf_program *program, int reg)
130+
static int _bf_nf_gen_inline_matcher(struct bf_program *program,
131+
const struct bf_matcher *matcher)
128132
{
129133
int offset;
130134

131-
EMIT(program,
132-
BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, BF_PROG_CTX_OFF(arg)));
133-
if ((offset = bf_btf_get_field_off("bpf_nf_ctx", "skb")) < 0)
134-
return offset;
135-
EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, offset));
136-
if ((offset = bf_btf_get_field_off("sk_buff", "mark")) < 0)
137-
return offset;
138-
EMIT(program, BPF_LDX_MEM(BPF_W, reg, BPF_REG_2, offset));
139-
140-
return 0;
141-
}
142-
143-
static int _bf_nf_gen_inline_get_skb(struct bf_program *program, int reg)
144-
{
145-
int offset;
146-
147-
EMIT(program, BPF_LDX_MEM(BPF_DW, reg, BPF_REG_10, BF_PROG_CTX_OFF(arg)));
148-
if ((offset = bf_btf_get_field_off("bpf_nf_ctx", "skb")) < 0)
149-
return offset;
150-
EMIT(program, BPF_LDX_MEM(BPF_DW, reg, reg, offset));
135+
assert(program);
136+
assert(matcher);
151137

152-
return 0;
138+
switch (bf_matcher_get_type(matcher)) {
139+
case BF_MATCHER_META_MARK:
140+
EMIT(program,
141+
BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, BF_PROG_CTX_OFF(arg)));
142+
if ((offset = bf_btf_get_field_off("bpf_nf_ctx", "skb")) < 0)
143+
return offset;
144+
EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, offset));
145+
if ((offset = bf_btf_get_field_off("sk_buff", "mark")) < 0)
146+
return offset;
147+
EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_2, offset));
148+
return bf_matcher_generate_meta_mark(program, matcher);
149+
case BF_MATCHER_META_FLOW_HASH:
150+
EMIT(program,
151+
BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, BF_PROG_CTX_OFF(arg)));
152+
if ((offset = bf_btf_get_field_off("bpf_nf_ctx", "skb")) < 0)
153+
return offset;
154+
EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, offset));
155+
return bf_matcher_generate_meta_flow_hash(program, matcher);
156+
default:
157+
return bf_matcher_generate_packet(program, matcher);
158+
}
153159
}
154160

155161
/**
156162
* Convert a standard verdict into a return value.
157163
*
158164
* @param verdict Verdict to convert. Must be valid.
159-
* @return TC return code corresponding to the verdict, as an integer.
165+
* @return Netfilter return code corresponding to the verdict, as an integer.
160166
*/
161167
static int _bf_nf_get_verdict(enum bf_verdict verdict)
162168
{
@@ -173,7 +179,6 @@ static int _bf_nf_get_verdict(enum bf_verdict verdict)
173179
const struct bf_flavor_ops bf_flavor_ops_nf = {
174180
.gen_inline_prologue = _bf_nf_gen_inline_prologue,
175181
.gen_inline_epilogue = _bf_nf_gen_inline_epilogue,
176-
.gen_inline_get_mark = _bf_nf_gen_inline_get_mark,
177-
.gen_inline_get_skb = _bf_nf_gen_inline_get_skb,
178182
.get_verdict = _bf_nf_get_verdict,
183+
.gen_inline_matcher = _bf_nf_gen_inline_matcher,
179184
};

0 commit comments

Comments
 (0)