Restore counter values on chain update#416
Restore counter values on chain update#416yaakov-stein wants to merge 4 commits intofacebook:mainfrom
Conversation
This will be used by the counter restoration logic to content-hash rules and sets for matching across chain updates.
992a545 to
518e88f
Compare
Add bf_set_equal() to compare two sets by key structure and element content, independent of insertion order. Elements are sorted internally for efficient comparison. This will be used to verify set identity when restoring counters across chain updates.
When bf_cgen_update() replaces a chain, counter values were lost because the new BPF program starts with a zeroed counter map. Restore counters by content-matching old rules to new rules before freeing the old program. The algorithm first builds a set index mapping using FNV-1a hashing with sorted-array binary search, so that set matchers can be compared across chains where set positions may differ. It then hashes and matches rules using the same sort-and-search approach. Matched counters are copied from the old program's counter map to the new one. Policy and error counters are always preserved.
Test that counters survive chain updates with rule reordering and set index shuffling. Verifies both rule-level and policy counter preservation.
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. |
As mentioned in #389, when
bf_cgen_update()replaces a chain, the new BPF program starts with a zeroed counter map. This restores counter values by content-matching old rules to new rules before freeing the old program.Design
The implementation assumes:
Set 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 with
bf_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 after
bf_program_loadbut beforebf_link_update, so there is no race.Performance
Tested 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
bf_fnv1aandbf_set_equal