Traffic control and reports
Aster can account upload and download for traffic the core handled, LAN devices, matched routing rules, proxy nodes, and policy groups, limit aggregate bandwidth, and apply rolling quotas. Nikki users should prefer the LuCI “Traffic Control” page. Nikki injects UCI settings into the runtime profile and updates source addresses from the neighbor table by MAC.
Nikki firewall-bypass traffic that never enters Aster is not counted or rate-limited.
Minimal configuration
traffic-control:
enabled: true
store: traffic-control.db
checkpoint-interval: 5m
max-store-size: 67108864
portal:
listen: 0.0.0.0:7893
url: http://192.168.1.1:7893
reports:
enabled: true
hourly-retention: 31d
daily-retention: 397d
monthly-retention: 397d
orphan-retention: 90d
global:
id: global
enabled: true
download-bps: 100000000
quota:
total-bytes: 107374182400
window: 30d
overage-upload-bps: 64000
overage-download-bps: 256000
portal: trueRate units are bit/s and traffic units are bytes. 0 or omitting a field means no limit. Quota windows support m, h, d, and w, from one hour to 365 days.
Devices, rules, and proxies
traffic-control:
enabled: true
devices:
- id: phone
name: Phone
mac: aa:bb:cc:dd:ee:ff
source-cidrs: [192.168.1.20/32]
download-bps: 20000000
rules:
- id: video-rule
type: DOMAIN-SUFFIX
payload: example.video
target: Proxy
quota:
total-bytes: 10737418240
window: 7d
targets:
- id: proxy-group
kind: group
target: Proxy
download-bps: 50000000Rules produce a content signature from type, normalized matcher, and target policy, so reordering rules does not lose history. Changing rule content or a quota window creates a new generation.
mac can remain a stable device identity for Nikki or another manager, but the core does not perform a neighbor lookup for every flow and currently has no ingress MAC attribution. Every device policy must include source-cidrs; MAC-only configuration is rejected instead of being accepted but never matching.
Persistence and compression
Governance state and reports live in bbolt. Ordinary traffic is checkpointed every five minutes. Overage, reset, configuration changes, and a clean shutdown commit immediately. Each policy or report series is stored as a Zstandard blob with original length and CRC32C. Startup loads and decodes the current data, and report queries filter the in-memory hour/day/month maps. This is not query-time lazy segmented storage.
The primary database creates a verified backup and can recover automatically when it is damaged. The Nikki package adds the database and backup to the sysupgrade keep list.
Controller API
Every endpoint uses the standard Controller Bearer secret:
GET /api/aster/capabilitiesGET /api/aster/kernel-direct/statusGET /api/aster/traffic-control/statusGET/PUT /api/aster/traffic-control/policiesGET /api/aster/traffic-control/rulesPOST /api/aster/traffic-control/policies/{id}/resetGET /api/aster/traffic-control/reportsGET /api/aster/traffic-control/reports/summaryGET /api/aster/traffic-control/reports/export.csv
The kernel_direct object from GET /api/aster/capabilities currently uses schema version 4. deprecated_fields includes proxy_traffic.
Besides the existing backend / fast_paths, GET /api/aster/kernel-direct/status also returns:
learned_sets: snapshot per kernel-direct consumer, includingmax_entries,max_records(domain budget, usuallymax_entries × 4),learned_addresses,direct_addresses,proxy_addresses,learned_domains,evictions.process: controller processpidandstarted_at(Unix seconds).aster_traffic: estimate of all traffic Aster currently handles, including TUN DIRECT / default-tun fallback, excluding DIRECT already bypassed by kernel-direct.proxy_traffic: deprecated alias with the same content asaster_traffic. It is not “proxy-only traffic.”
learned_sets[].evictions is how many address-LRU entries were dropped because of the capacity cap since process start. TTL expiry, rule-reload flush, or set collapse are not counted.
GET /api/aster/traffic-control/policies returns {revision, config}. PUT must send the same envelope; a stale revision returns 409. Controller JSON bodies are limited to 1 MiB. A failed Configure/PUT leaves the previous runtime, revision, store, flusher, and portal in place. The same store path and portal listen address are reused, and live sessions rebind to the new generation. Policy count is capped at 256, each session at 128 report keys, and the global report-series table at 4,096.
Report queries accept key, granularity=hour|day|month, and from / to Unix timestamps. The range must be positive and no longer than 400 days. An unknown key returns buckets: []; an invalid granularity returns 400 even when the key is absent. Cross-dimension keys are joined with |, for example device:phone|rule:video-rule.
