Restore counter values on chain update#416
Restore counter values on chain update#416yaakov-stein wants to merge 1 commit intofacebook:mainfrom
Conversation
518e88f to
63375bf
Compare
|
I know it's a bit late to ask, but what if instead of identifying objects by value (rule contents, set elements, etc.), we gave every element a stable ID (e.g. random 32, 64, or 128 bits)? Then the caller could preserve IDs as its edits the chain, and the counters from old objects would be attributed to new objects if IDs are the same. With your PR as it is, if you do That would be a much bigger change though. So another, simpler, idea I had was: what if we compared unnamed sets by-value, but named sets by their name? @qdeslandes do you have any opinion on this? |
One of my goals for this was to be transparent to the user and for this to happen automatically behind the scenes - i.e. they shouldn't need to be aware of element id's and need to match them up (however we'd implement it, it seems like it'd add some overhead for the user).
I think that behavior would be lead to confusing results. A counter would report a number that doesn't accurately reflect what has actually been matched by that rule (given that the rules behavior has changed over time).
I think the current approach is cleaner/more correct, but I'm happy to change things up if we'd rather go in that direction. |
qdeslandes
left a comment
There was a problem hiding this comment.
Summarizing the discussion I had with Yaakov: with the daemonless changes, we will eventually simplify the commands we expose to users. E.g. chain set and chain update don't need to be separate command, we should also update atomically if possible.
Eventually, we will provide two types of commands:
- Ruleset-level commands, which manipulates chains (e.g. set a chain)
- Chain-level commands, which manipulates entities within the chains (e.g. update a set, insert a rule)
Thus, as a user, I wouldn't expect ruleset-level commands to maintain the counter values, as I'm expecting a new chain. For chain-level commands, however, we expect the chain to remain the same, so the counters should be preserved.
Hence, for now, I would only expect update-set operation to preserve the counters values.
63375bf to
9a1d97e
Compare
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. |
qdeslandes
left a comment
There was a problem hiding this comment.
Some test changes, otherwise LGTM!
8912407 to
0c23cfc
Compare
| DROP | ||
| " | ||
| ping -c 1 -W 0.1 ${NS_IP_ADDR} || true | ||
| counter=$(${FROM_NS} bpftool map dump pinned ${WORKDIR}/bpf/bpfilter/test_xdp/bf_cmap | jq '.[0].value.packets') |
There was a problem hiding this comment.
Note: this does now rely on BTF
|
Claude: Review of PR #416 — Restore counter values on chain update The approach is sound: using a flags enum to control counter preservation in Issues found:
Documentation, naming conventions, tests, and commit message all follow the project conventions. |
|
Claude: Review summary The approach is sound: transferring counters between load and link swap minimizes the packet counting gap, and the flags-based API is extensible for future update behaviors. Two inline comments posted:
|
0c23cfc to
15d30fc
Compare
|
Claude: Review of PR #416 — Restore counter values on chain update Design is clean: the flags-based API extends One inline comment posted:
Tests cover both the reset (chain update) and preservation (update-set) cases well. Note on previous automated reviews: the comments flagging the sentinel name |
15d30fc to
e5e982e
Compare
|
Claude: Review of PR #416 — Restore counter values on chain update The design is sound: using a flags enum to control counter preservation in One new inline comment posted:
All three call sites ( CLAUDE.md note: The Doxygen rule "first and last lines empty (unlike regular comments)" is not followed anywhere in the codebase (0 instances found across |
Add a flags parameter to `bf_cgen_update()` to control whether counter values are transferred from the old program to the new one. Chain-level operations like `update-set` manipulate entities within a chain, so counters should survive the update. Ruleset-level operations like chain update replace the entire chain and start with fresh counters. Counter transfer reads values from the old handle's counter map and writes them into the new handle's map after program load but before the link swap. While this is not atomic, it does minimize the window where packets could be miscounted.
e5e982e to
0969c52
Compare
|
Claude: Review of PR #416 — Restore counter values on chain update The implementation is sound. Transferring counters between program load and link swap is the correct placement, and the flags-based API for Prior review feedback (sentinel naming, E2E tests cover both the counter-reset ( |
As mentioned in #389, when
bf_cgen_update()replaces a chain, the new BPF program starts with a zeroed counter map. The behavior should be that when updating a specific entity within a chain (set, rule, etc.), the counters should be preserved (see @qdeslandes comment below for more details and rationale).This PR adds that behavior specifically for
chain update-set, while leaving the existing behavior forchain update.Notes/Thoughts:
add-ruleorremove-rule.bf_cgen_update_flagsenum is added for flexibility in case we need future arguments as opposed to a boolean (which is simpler but harder to work with if we need to use or update this in the future). However, the goal either way should be for this to be temporary (in line with the consolidated behavior mentioned here).## DesignThe implementation assumes:Chains may have large numbers of rules, sets, and set elements, but rules won't have exceedingly large numbers of matchersUpdate overhead should remain negligible relative to program generation and loadingSimplicity is preferred over hyper-optimizations where possibleSet mapping. Because set matchers reference sets by position and positions can change between chains, a set index mapping is built first. To efficiently compare large sets, old sets are hashed (FNV-1a with commutative element sum for order-independence), sorted by hash, and binary-searched for each new set. Hash matches are verified deterministically withbf_set_equal(), which copies each set's elements into a flat array, sorts them, and compares with memcmp.Rule matching. Rules are hashed the same way - FNV-1a of scalar fields plus a commutative sum of per-matcher hashes. A new rules set matchers hash their mapped old index so equivalent rules produce identical hashes regardless of set position (this abstracts away the whole idea of the set so we don't need to worry about it). Old rules are sorted by hash and binary-searched for each new rule, with full order-independent matcher comparison to verify matches. Once again, hash matches are verified deterministically using_bf_rule_equal.Counter transfer. For each matched pair, the old counter is read and written to the new program's counter map. Policy and error counters are always preserved. This happens afterbf_program_loadbut beforebf_link_update, so there is no race.## PerformanceTested with up to 10k rules and 100 sets of 50k elements each. The mapping and transfer overhead was negligible relative to program generation and loading.
Test plan
chain_update.shandchain_update_set.shUnit tests forbf_fnv1aandbf_set_equalE2E test covering rule reordering and set index shuffling