Documentation
¶
Overview ¶
Package reconcile owns the periodic Neutron reconcile: a 5-minute safety net that re-fetches the full snapshot and applies only the rows that changed, so metadata staleness stays bounded by one interval even through a Kafka outage.
It shares kernelwriter.ApplyTrieDelta with the Kafka path, so the insert-then-delete ordering holds for both.
docs/architecture/trie-construction.md#incremental-updates
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DesiredMACs ¶
func DesiredMACs(snap *neutron.Snapshot) map[uint64]metadata.TenantMeta
DesiredMACs maps each admitted VM port to its full attribution — the target state of the metadata map. Amphora ports resolve to their load balancer's owning project. Ports failing admission are skipped silently: a persistently malformed port must not log every pass.
Exported because it is the SINGLE definition of what the map should hold, and it has two callers — the reconciler every pass, cold start once before any packet. Two implementations would be a billing bug: if cold start applied the Amphora rewrite and the reconciler did not, the first pass after boot would settle every Amphora port's flows under the LB owner and re-attribute to the service project, and the next cold start would swing it back.
Diagnostics stay OUT — they belong to cold start's audit pass, which produces no attribution and so cannot mis-bill if it drifts.
docs/architecture/octavia.md
Types ¶
type AmphoraGauge ¶
type AmphoraGauge interface {
SetAmphoraPorts(n int)
}
AmphoraGauge publishes how many Amphora ports the latest pass re-attributed to their load balancer's owner. Cold start sets it once, so without this seam the gauge would freeze at the boot value — a load balancer created later would never move it, and the very failure it exists to catch would read healthy. nil skips publishing.
docs/architecture/octavia.md
type FlowSettler ¶
type FlowSettler interface {
Settle(mode state.SettleMode, resolve func(bpf.FlowKey) (tenant, extNet, server string, ok bool)) int
// PruneServerSettled releases server-settled buckets whose server is
// no longer in the Nova server list — the server tier's lifecycle
// rule. The reconciler owns the call: it is the one place a fresh,
// successful Nova fetch is in hand.
//
// Settled bytes: docs/architecture/data-structures.md#settled-bytes
PruneServerSettled(alive map[string]struct{}) int
// PruneTenantSettled releases tenant-settled buckets whose project is
// no longer in the Keystone project list, folding each into the
// total-settled absorber — the tenant tier's lifecycle rule. Same
// ownership rationale as PruneServerSettled.
//
// Settled bytes: docs/architecture/data-structures.md#settled-bytes
PruneTenantSettled(alive map[string]struct{}) int
}
FlowSettler folds flow rows into the settled-bytes accumulator. The MAC reconcile calls it just before re-pointing a live MAC, so bytes earned under the old attribution settle there instead of re-binding wholesale at the next scrape.
docs/architecture/data-structures.md#settled-bytes
type MacWriter ¶
type MacWriter interface {
// value is the packed (Amphora flag ++ tenant id) the kernel stores,
// built by [bpf.TenantValue] — not a bare tenant id.
Update(mac uint64, value uint32) error
}
MacWriter writes one (mac → tenant id) binding into the kernel mac_tenant_map. Removals are deliberately not its job: a gone MAC becomes a lingering ghost and the GC sweeps the kernel entry after the grace window.
docs/architecture/data-structures.md#lingering-ghost
type MapGauge ¶
MapGauge refreshes a kernel map's current-entry gauge (lachesis_bpf_map_current_entries). Cold-start sets it once; the incremental path must keep it current or it drifts as the reconcile rewrites the trie and mac_tenant_map. Consumer-defined seam; *bpf.Metrics satisfies it.
type MetadataSource ¶
type MetadataSource interface {
Sync(ctx context.Context) (neutron.SyncResult, error)
Trie() []neutron.TrieEntry
Commit(result neutron.SyncResult, at time.Time)
}
MetadataSource is the subset of neutron.Neutron the reconcile loop drives: a full list-and-build MetadataSource.Sync, the retained trie of the last committed sync (MetadataSource.Trie, the "old" side of the diff), and MetadataSource.Commit to publish the new state once the kernel has acknowledged it. Defined here as the consumer's minimal seam so the loop can be unit-tested with a fake; *neutron.Neutron satisfies it.
type Metrics ¶
type Metrics struct {
// contains filtered or unexported fields
}
Metrics holds the Prometheus instruments for the reconcile subsystem. It is the dedicated error sink for the runtime incremental-update path: a kernel trie-write failure during a reconcile surfaces as lachesis_reconcile_runs_total{result="apply_error"} rather than a generic counter.
Metric catalogue: docs/architecture/metrics.md
The instruments are:
- lachesis_reconcile_runs_total{result} counter
func NewMetrics ¶
func NewMetrics() *Metrics
NewMetrics constructs the bundle with all three result outcomes seeded at zero so each series exists before the first reconcile fires.
func (*Metrics) Collectors ¶
func (m *Metrics) Collectors() []prometheus.Collector
Collectors returns the underlying prometheus.Collector values for registration by the agent.
type Options ¶
type Options struct {
Source MetadataSource
Trie kernelwriter.MapUpdateDeleter
// AmphoraIPs writes the Octavia base-address set
// (docs/architecture/octavia.md). Optional: nil skips the write, as
// the trie-only unit tests do.
AmphoraIPs kernelwriter.MapUpdater
Meta *metadata.ShardedMetadataMap
MacWriter MacWriter
// Settler folds a MAC's flow rows to its old tenant before a
// tenant reassignment replaces the binding. Optional (nil skips
// the fold — trie-only unit tests); the agent wires its
// *state.GlobalState.
Settler FlowSettler
Interner *metadata.TenantInterner
Seq *boot.Sequencer
Metrics *Metrics
// Routers is the router-interface-MAC → external-network map the
// pass rebuilds and swaps (per-flow external attribution).
// Optional (nil skips — trie-only unit tests); the agent wires the
// store its Resolver reads.
//
// Billing tiers: docs/architecture/billing.md
Routers *metadata.RouterMACs
// BPFGauge refreshes the kernel map-fill gauges after each pass.
// Optional (nil skips); the agent wires its bpf metrics bundle.
BPFGauge MapGauge
// AmphoraGauge republishes the Amphora re-attribution count each
// pass. Optional; nil skips it.
AmphoraGauge AmphoraGauge
// Tunables supplies the live reconcile interval and ghost grace
// (hot-reload; the interval applies at the next tick). REQUIRED —
// operational knobs have exactly one source; unit tests construct
// a store with the values they exercise.
Tunables *tunables.Store
}
Options bundles the inputs to New. Source, Trie, Interner, and Metrics are required. Meta and MacWriter enable the mac_tenant_map reconcile; both nil (the trie-only unit tests) skips it. Seq is optional (nil skips the boot barrier, used by reconcileOnce unit tests); Interval defaults to [defaultInterval] when zero.
type Reconciler ¶
type Reconciler struct {
// contains filtered or unexported fields
}
Reconciler periodically reconciles the kernel subnet_zone_trie against a fresh Neutron snapshot. Construct with New, then run Reconciler.Run on a long-lived goroutine.
func (*Reconciler) Kick ¶
func (r *Reconciler) Kick()
Kick requests an immediate reconcile pass out of band. The Kafka consumer calls it when a Neutron notification shows metadata changed, so the trie and mac_tenant_map refresh within one pass instead of waiting up to a full interval. It is non-blocking and coalescing — the buffered channel holds at most one pending kick, so a burst of events costs a single extra pass — and safe to call from any goroutine.
func (*Reconciler) Run ¶
func (r *Reconciler) Run(ctx context.Context)
Run reconciles on each tick and on each Reconciler.Kick until ctx is cancelled — one applier goroutine for both, so passes never overlap. Blocks on boot.PhaseStateRestored first: a delta computed before cold-start committed the initial trie would be wrong. No immediate first pass; cold start already populated the trie.