lib: cgen: add per-rule state map for log rate limiting#553
Conversation
|
@claude review |
Claude review of PR #553 (f0f37fc)Suggestions
Nits
|
| double v; | ||
| char *end; | ||
|
|
||
| v = strtod(s, &end); |
There was a problem hiding this comment.
Claude: suggestion: _parse_log_rate does not guard against overflow. If the user provides a very large number (e.g., 99999999999999999s), strtod returns HUGE_VAL/infinity which passes the v <= 0.0 check, and (uint64_t)(HUGE_VAL * multiplier + 0.5) is undefined behavior (casting a non-representable float to integer). Consider adding a check:
if (!isfinite(v) || v > (double)UINT64_MAX / multiplier)
return -1;| btf__add_field(kbtf, "count", 1, 0, 0); | ||
| btf__add_field(kbtf, "size", 1, 64, 0); | ||
| break; | ||
| case BF_MAP_TYPE_STATE: |
There was a problem hiding this comment.
Claude: suggestion: The BTF construction for BF_MAP_TYPE_STATE creates an extra btf__add_int(kbtf, "u32", 4, 0) (the one before btf->key_type_id = ...) that produces an unreferenced BTF type entry. The BF_MAP_TYPE_COUNTERS case only pre-creates types it actually references. Consider removing the extraneous call to keep the BTF section clean.
Rules with a log action currently emit one entry per matching packet
with no throttling. To support rate-limited logging, BPF programs need
mutable per-rule state that persists across invocations.
Introduce bf_smap, a single-entry BPF_MAP_TYPE_ARRAY map per chain
whose value is a flat array of bf_rule_state entries (one per rule).
The map is looked up once in the program prologue and the base pointer
stored in bf_runtime.state_map; per-rule access is then a constant
offset, avoiding one bpf_map_lookup_elem call per rule at packet time.
For each rule with log_rate_ns set, the generated code reads
last_log_ts, calls bpf_ktime_get_ns(), and skips the log elfstub if
the elapsed time falls short of the configured interval. R9
(callee-saved) holds the state entry pointer across the ktime call.
Writes to last_log_ts are best-effort: no CAS, but a naturally aligned
8-byte store is atomic on x86-64, so no torn writes occur.
Expose the rate in the DSL as 'log [<headers>] every <N>{ns,us,ms,s}'
and wire it to the new bf_rule.log_rate_ns field serialized alongside
the existing rule fields.
Stale bpffs pins from a previous benchmark run with a different binary can cause deserialization failures when the new binary tries to reload them (e.g. missing map keys added since the pin was written). Flush /sys/fs/bpf/bpfilter before each run to start from a clean state.
81e5c26 to
bb247f3
Compare
Rules with a log action currently emit one entry per matching packet with no throttling. To support rate-limited logging, BPF programs need mutable per-rule state that persists across invocations.
Introduce bf_smap, a single-entry BPF_MAP_TYPE_ARRAY map per chain whose value is a flat array of bf_rule_state entries (one per rule). The map is looked up once in the program prologue and the base pointer stored in bf_runtime.state_map; per-rule access is then a constant offset, avoiding one bpf_map_lookup_elem call per rule at packet time.
For each rule with log_rate_ns set, the generated code reads last_log_ts, calls bpf_ktime_get_ns(), and skips the log elfstub if the elapsed time falls short of the configured interval. R9 (callee-saved) holds the state entry pointer across the ktime call. Writes to last_log_ts are best-effort: no CAS, but a naturally aligned 8-byte store is atomic on x86-64, so no torn writes occur.
Expose the rate in the DSL as 'log [] every {ns,us,ms,s}' and wire it to the new bf_rule.log_rate_ns field serialized alongside the existing rule fields.