[1/3] Separate comparison logic from data loading in matchers#464
[1/3] Separate comparison logic from data loading in matchers#464yaakov-stein wants to merge 2 commits intofacebook:mainfrom
Conversation
|
Claude: review of facebook/bpfilter #464 (b0f6a25) Must fix
Suggestions
Nits
|
c428864 to
bc6a3bd
Compare
bc6a3bd to
4cff28a
Compare
4cff28a to
1cd9a5e
Compare
1cd9a5e to
4f73db5
Compare
4f73db5 to
426262b
Compare
qdeslandes
left a comment
There was a problem hiding this comment.
I didn't review the full diff deeply, as https://github.com/facebook/bpfilter/pull/464/changes#r2915802296 will involve big-ish changes (i.e. let's not worry about the nits when there are core comments to resolve).
For the few nits already there, most of them are linked to a specific line but apply to the all change.
That being said, it's a great PR and a big step in the right direction!
ab9e6dd to
c979327
Compare
dad2d27 to
4b67dd8
Compare
4b67dd8 to
d99f953
Compare
qdeslandes
left a comment
There was a problem hiding this comment.
Few more comments, but the core of the change LGTM :)
d99f953 to
06f8e4f
Compare
06f8e4f to
4dfe6a6
Compare
Separate comparison logic from data loading in matcher codegen. bf_cmp_value, bf_cmp_masked_value, bf_cmp_range, and bf_cmp_bitfield encapsulate the BPF bytecode patterns previously duplicated across ip4.c, ip6.c, tcp.c, udp.c, icmp.c, and meta.c. No behavioral change; emitted bytecode is identical.
Remove ip4.c/h, ip6.c/h, tcp.c/h, udp.c/h, and icmp.c/h by absorbing their loading logic into packet.c. Protocol guards and header loads now go through bf_stub_rule_check_protocol and bf_stub_load_header driven by _bf_matcher_metas, while comparisons use the shared cmp.c functions. This centralises all packet matcher codegen in a single dispatch point, making it straightforward to add new flavor-specific dispatch without touching per-protocol files.
4dfe6a6 to
b0f6a25
Compare
| if (meta->layer == BF_MATCHER_LAYER_3 || | ||
| meta->layer == BF_MATCHER_LAYER_4) { | ||
| r = bf_stub_rule_check_protocol(program, meta); | ||
| if (r) | ||
| return r; | ||
| checked_layers |= BF_FLAG(meta->layer); | ||
| } |
There was a problem hiding this comment.
We don't have any matcher on L2 yet, but the enum value is defined, so it should be supported here.
| static int _bf_matcher_pkt_load_field(struct bf_program *program, | ||
| const struct bf_matcher_meta *meta, | ||
| int reg) | ||
| { | ||
| int bpf_size; | ||
|
|
||
| switch (meta->hdr_payload_size) { | ||
| case 1: | ||
| bpf_size = BPF_B; | ||
| break; | ||
| case 2: | ||
| bpf_size = BPF_H; | ||
| break; | ||
| case 4: | ||
| bpf_size = BPF_W; | ||
| break; | ||
| case 8: | ||
| case 16: | ||
| bpf_size = BPF_DW; | ||
| break; | ||
| default: | ||
| return -EINVAL; | ||
| } | ||
|
|
||
| EMIT(program, | ||
| BPF_LDX_MEM(bpf_size, reg, BPF_REG_6, meta->hdr_payload_offset)); | ||
|
|
||
| if (meta->hdr_payload_size == 16) { | ||
| EMIT(program, BPF_LDX_MEM(BPF_DW, reg + 1, BPF_REG_6, | ||
| meta->hdr_payload_offset + 8)); | ||
| } | ||
|
|
||
| return 0; | ||
| } |
There was a problem hiding this comment.
I would insert the EMIT instruction in each case here, it would clarify the behaviour instead of handling 64-bits compare as a special case. This leads to very low code duplicate (in the source code, no duplication in the BPF bytecode).
|
|
||
| r = _bf_cmp_build_imm64(program, BPF_REG_3, BPF_REG_4, masked_hi); | ||
| if (r) | ||
| return r; |
There was a problem hiding this comment.
Not sure which question you're refering to :/
Stacked PRs:
CGROUP_SOCK_ADDRinitial chain support #459CGROUP_SOCK_ADDRmatcher support #465This is helpful for #355 (but makes sense as a standalone refactor as well). Changes are non-functional - all bytecode should remain exactly the same, no new features, etc.
Summary
Decomposes matcher codegen into independent concerns to enable flavor-specific data loading while sharing comparison logic across flavors.
Every matcher generator performs three operations:
A) Protocol guard : Is this the right L3/L4 protocol? (R7/R8 check)
B) Data loading (flavor-specific): Get the field value into R1 (R1+R2 for 128-bit)
C) Comparison: Does the value match the rule payload? (EQ/NE/RANGE/mask)
Previously, concerns B and C were tangled in per-protocol files (
ip4.c,ip6.c,tcp.c,udp.c,icmp.c). Each file hardcoded both packet header loading and comparison, making it impossible to reuse comparison logic for non-packet flavors and hard to reuse the logic in general.Before
Problems: B+C tangled, tcp/udp port comparison duplicated, adding a new flavor means either duplicating C or refactoring B+C apart.
After
Per-protocol files eliminated (
ip4.c/h,ip6.c/h,tcp.c/h,udp.c/h,icmp.c/h). Loading logic absorbed intopacket.cstatic helpers; comparison logic extracted into cmp.c.Test plan