Skip to main content

Event Federation reference

Diagram showing Event Federation from observed local facts through EventGroup, routerd-eventd push delivery, EventSubscription matching, and plugin-derived DynamicConfigPart output

Experimental (CloudEdge). See ADR 0006: CloudEdge Event Federation for the design and invariants, and the how-to CloudEdge mobility demo for a worked example.

Event Federation lets routerd nodes exchange typed, observed facts (e.g. "this client IPv4 was observed", "this address expired") over the overlay, and lets a subscriber turn matched events into derived configuration via a plugin. It is the control-plane substrate beneath Cloud SAM: an observed address contributes typed ownership facts used by the receiving MobilityPool plan.

The model is at-least-once delivery with idempotent, observed-fact events. Events are immutable statements about the world ("observed"), never imperative commands; a receiver re-deriving the same state from the same events is a no-op. For example, routerd.mobility.arp.request.observed states that a leaf saw a CE ask for an unresolved IPv4 target. A receiving leaf may apply its own MobilityPool scope and rate-limit policy and issue a local probe; the event does not instruct the receiver to execute one.

Kinds​

EventGroup​

The bus a node participates in. One node has one identity per group.

FieldMeaning
nodeNameThis node's identity in the group; stamped as sourceNode on emitted events.
peersFromOptional SAMNodeSet/<name> sources used to derive push peers from each node's eventEndpoint.
retentionBounds how many events / how long the local store keeps them. Empty/zero = unlimited.
authHMAC secret material for peer delivery (push).
listenReceiver bind (address) for inbound peer pushes. Empty = push-only (no receiver).
replayWindowGo duration bounding accepted message timestamp skew for replay protection (default 5m).

peersFrom lets an EventGroup import peer targets from a shared SAMNodeSet. The controller reads SAMNodeSet.spec.nodes[].eventEndpoint, skips the node whose nodeRef matches nodeName, and writes the resolved peers directly into the generated routerd-eventd config. Hand-authored EventPeer resources are still accepted and are overlaid after generated peers, so a static peer with the same nodeName acts as a bootstrap override.

EventPeer​

A remote node this node pushes events to.

FieldMeaning
groupRefThe EventGroup this peer belongs to (required).
nodeNameRemote peer node identity (required).
endpointBase URL to push to, e.g. http://10.99.0.7:8787 (required for push).
directionDelivery direction; only push is supported. Empty defaults to push.
typesOptional event-type allowlist; empty delivers all.
subjectPrefixesOptional subject-prefix allowlist; empty delivers all.

EventSubscription​

Turns matched events into a plugin invocation that emits a DynamicConfigPart.

FieldMeaning
groupRefThe EventGroup to consume from.
matchWhich events to act on (by type / subject).
trigger.pluginRefThe Plugin invoked for matched events.
trigger.batchWindowCoalesce matched events into one invocation (Go duration).
trigger.debounceDelay invocation until after the last matched event (Go duration).

routerctl federation CLI​

routerctl federation event emit --group <g> --type <topic> --subject <entity> [--source-node <n>] [--ttl <dur>] [--payload k=v ...]
routerctl federation event list --group <g>
routerctl federation event deliveries --group <g>

emit records an observed fact into the local store (e.g. --type routerd.client.ipv4.observed --subject 10.88.60.9/32). list shows recorded events; deliveries shows per-peer push delivery state.

Self-capture guard (ADR 0006 no-feedback-loop invariant): a node must not emit routerd.client.ipv4.observed for an address already captured by its local MobilityPool plan, or the delivered capture address would loop back as a fresh observation.

Transport — routerd-eventd​

routerd-eventd@<group> is a long-lived per-group daemon (supervised by a generated systemd unit on Linux, rc.d on FreeBSD) that:

  • pushes locally-recorded events to each EventPeer over HTTP, signed with the group HMAC; the receiver verifies the signature and rejects messages outside the replayWindow.
  • records deliveries (per peer, per event) so at-least-once retry is bounded and observable.
  • prunes the local event store per the group retention.

The outbox carries a sourceNode guard so a received event is not re-forwarded back to its origin (no delivery loop).

When EventGroup.spec.peersFrom is present, routerd-eventd still sees ordinary peer entries in its config. The dynamic part is resolved by the routerd controller before writing config.json; no separate DynamicConfigPart is created for EventPeer derivation.

Subscription → plugin → DynamicConfigPart flow​

  1. A node emits an observed fact (routerctl federation event emit, or a future observer).
  2. routerd-eventd delivers it to peers; each peer records it in its event store.
  3. A peer's EventSubscription matches the event and invokes trigger.pluginRef, coalescing per batchWindow / debounce.
  4. The plugin returns observed facts or ordinary dynamic resources. The Mobility controller consumes the facts and persists one typed local capture plan for the dataplane.

This keeps the operator-authored intent declarative: the operator declares the group/peers/subscription; capture and provider action plans are derived.