Skip to content
Thomas Mangin edited this page Apr 11, 2026 · 8 revisions

Pre-Alpha. This page describes behavior that may change.

Ze validates received BGP routes against RPKI ROA data. Invalid routes are rejected before they enter the RIB. The feature connects to RTR cache servers (RFC 8210), downloads Validated ROA Payloads, and applies the RFC 6811 origin validation algorithm to each received prefix. The implementation is a plugin (bgp-rpki) that depends on bgp-adj-rib-in for the validation gate.

A minimal setup

bgp-rpki and bgp-adj-rib-in are internal plugins loaded automatically.

bgp {
    rpki {
        cache-server 192.0.2.1 {
            port 323;
        }
    }

    peer upstream {
        connection {
            remote { ip 10.0.0.1; }
            local  { ip 10.0.0.2; }
        }
        session {
            asn { local 65000; remote 65001; }
            family { ipv4/unicast { prefix { maximum 1000000; } } }
        }

        process bgp-rpki        { receive [ update ]; }
        process bgp-adj-rib-in  { receive [ update state ]; }
    }
}

bgp-rpki must be bound to the peer with process bgp-rpki { receive [ update ] }. bgp-adj-rib-in must be bound with process bgp-adj-rib-in { receive [ update state ] }. bgp-adj-rib-in is what holds routes pending validation.

Configuration reference

Path Type Default Description
rpki/cache-server <addr> list required RTR cache server, keyed by IP or hostname.
rpki/cache-server/port uint16 323 RTR TCP port.
rpki/cache-server/preference uint8 100 Server preference. Lower is preferred.
rpki/validation-timeout uint16 30 Seconds before fail-open on pending routes.
rpki/policy/invalid-action enum reject Action for Invalid routes: reject, log-only, accept.
rpki/policy/not-found-action enum accept Action for NotFound routes: accept, reject, log-only.

Multiple cache servers are supported for redundancy. The VRP tables from all servers are merged as a union.

The validation states

Each received route gets one of three states, per RFC 6811.

State Meaning Default action
Valid Origin AS and prefix length match a VRP. Accept.
Invalid A VRP covers the prefix, but the origin AS or the prefix length does not match. Reject.
NotFound No VRP covers the prefix. Accept.

Override the actions with rpki/policy/invalid-action and rpki/policy/not-found-action. Setting invalid-action reject is what you want in production: it implements RPKI-based route origin validation. Setting it to log-only is useful during deployment while you build confidence in your cache.

How the validation flows

The order is deterministic and the same on every UPDATE.

  1. Ze connects to the configured RTR cache servers and downloads the VRPs.
  2. A BGP UPDATE arrives from a peer.
  3. bgp-adj-rib-in stores the route as "pending".
  4. rpki extracts the origin AS (the rightmost AS in the final AS_SEQUENCE segment).
  5. For each NLRI prefix in the UPDATE, rpki looks up covering VRPs and computes the validation state.
  6. Valid and NotFound routes are promoted to "installed". Invalid routes are discarded (or logged, depending on policy).

Fail-open safety

If the bgp-rpki plugin does not respond within validation-timeout seconds (default 30), pending routes are automatically promoted. This prevents route black-holing when the RPKI infrastructure is down.

If every RTR cache server disconnects, the existing VRP cache is retained until a connection is re-established. Routes continue to be validated against the last known good cache. The failure mode is graceful: a cache outage does not immediately invalidate everything.

AS_PATH edge cases

A few edge cases worth knowing about.

AS_PATH Origin AS Result
Normal sequence [65000 65001] 65001 (rightmost) Normal validation.
Ends with AS_SET {65001 65002} None Always Invalid when a covering VRP exists.
Empty (iBGP, no prepend) None NotFound.

An AS_SET at the end of the path has no single origin, so RPKI cannot validate it. The safest default is Invalid when a VRP covers the prefix.

CLI commands

ze cli -c "rpki status"      # RTR session count, VRP counts
ze cli -c "rpki cache"       # Cache server connection details
ze cli -c "rpki roa"         # ROA table summary
ze cli -c "rpki summary"     # Validation statistics

Example output:

{"running":true,"vrp-count-ipv4":3,"vrp-count-ipv6":0,"sessions":1}

RPKI events

The bgp-rpki plugin emits validation events that other plugins can subscribe to. A plugin that subscribes to bgp-rpki direction received receives a JSON event for each validated UPDATE.

{
  "type": "bgp",
  "bgp": {
    "peer":    {"address": "10.0.0.1", "remote": {"as": 65001}},
    "message": {"id": 42, "type": "rpki"},
    "rpki": {
      "ipv4/unicast": {
        "10.0.1.0/24": "valid",
        "10.0.2.0/24": "invalid"
      }
    }
  }
}

When the ROA cache is empty, the event is "rpki": {"status": "unavailable"}.

Merged events with bgp-rpki-decorator

Instead of receiving separate UPDATE and RPKI events, subscribe to merged update-rpki events from the bgp-rpki-decorator plugin. Each event carries the full UPDATE plus the validation state in one envelope.

plugin {
    external rpki-decorator {
        use bgp-rpki-decorator;
        encoder json;
    }
}

bgp {
    peer upstream {
        process my-consumer   { receive [ update-rpki ] }
        process bgp-rpki          { receive [ update ] }
        process rpki-decorator    { receive [ update rpki ] }
        process bgp-adj-rib-in    { receive [ update state ] }
    }
}

The merged event is the full UPDATE JSON with an rpki section injected. If the RPKI validation does not arrive within the decorator's 2-second timeout, the event is emitted without the rpki section (graceful degradation).

Testing locally

ze-test rpki --port 3323

ze-test rpki starts a deterministic mock RTR server that auto-generates VRPs based on the first octet of each /8 prefix. Validation states are predictable for routes from AS 65001.

First octet State
0, 3, 6, 9, 12, ... Valid
1, 4, 7, 10, 13, ... Invalid
2, 5, 8, 11, 14, ... NotFound

Without RPKI

When the bgp-rpki plugin is not loaded, routes flow directly into bgp-adj-rib-in with zero overhead. No pending state, no validation delay. The validation gate only activates when the bgp-rpki plugin sends bgp-adj-rib-in enable-validation during startup.

Troubleshooting

Symptom Cause Fix
Routes delayed 30 seconds then accepted RTR cache server unreachable. Check connectivity, verify the port.
All routes Invalid Wrong cache server data, or origin AS mismatch. Check rpki roa, verify VRP coverage.
No VRPs loaded RTR session not established. Check rpki status, verify the cache server is running.
Routes accepted without validation The bgp-rpki plugin is not bound to the peer. Add process bgp-rpki { receive [ update ] } to the peer config.

See also

  • Overview for the surrounding config model.
  • BGP peers for the peer-level settings.
  • Plugins for bgp-rpki and bgp-rpki-decorator.

Adapted from main/docs/guide/rpki.md.

Home

About

First Steps

Configuration

Operation

Interfaces

Plugins

Plugin Development

Chaos Testing

Blueprints

Development

Reference

Clone this wiki locally