Skip to content

route server at an ixp

Thomas Mangin edited this page Apr 11, 2026 · 5 revisions

Pre-Alpha. This page describes behavior that may change. Not for production use.

Running Ze as an IXP route server. The scenario is the one every IXP route server addresses: a handful of member networks peer with the route server, the server forwards every received route to every other member (with policy), and nobody has to do N-by-N bilateral sessions. ADD-PATH is on so every downstream router can make its own best-path decision. RPKI origin validation rejects obviously wrong routes at the door.

Topology

                            +-----------------+
                            |    Ze Route     |
                            |  Server AS65000 |
                            |  192.0.2.254    |
                            +--------+--------+
                                     |
                 +-------------------+-------------------+
                 |                   |                   |
         +-------+------+    +-------+------+    +------+-------+
         | Member A     |    | Member B     |    | Member C     |
         | AS65001      |    | AS65002      |    | AS65003      |
         | 192.0.2.1    |    | 192.0.2.2    |    | 192.0.2.3    |
         +--------------+    +--------------+    +--------------+

Every member has one session with the route server. The route server has no best-path selection: it forwards everything. ADD-PATH means every member gets every path it needs.

Configuration

plugin {
    external rs          { use bgp-rs;          encoder json; }
    external adj-rib-in  { use bgp-adj-rib-in;  encoder json; }
    external rpki        { use bgp-rpki;        encoder json; }
    external role        { use bgp-role;        encoder json; }
}

system {
    host ix-rs-01;
}

bgp {
    router-id 192.0.2.254;
    session { asn { local 65000; } }

    rpki {
        cache-server 192.0.2.100 { port 323; }
        policy { invalid-action reject; }
    }

    group members {
        session {
            capability {
                asn4;
                route-refresh;
                add-path send/receive;
                graceful-restart { restart-time 120; }
            }
            family {
                ipv4/unicast { prefix { maximum 1000000; } }
                ipv6/unicast { prefix { maximum 200000;  } }
            }
        }
        role {
            import rs;
            strict false;
        }
        process rs          { receive [ update ]; send [ update ]; }
        process adj-rib-in  { receive [ update state ]; }
        process rpki        { receive [ update ]; }
    }

    peer member-a {
        inherit members;
        connection { remote { ip 192.0.2.1; } local { ip 192.0.2.254; } }
        session    { asn { remote 65001; } }
    }

    peer member-b {
        inherit members;
        connection { remote { ip 192.0.2.2; } local { ip 192.0.2.254; } }
        session    { asn { remote 65002; } }
    }

    peer member-c {
        inherit members;
        connection { remote { ip 192.0.2.3; } local { ip 192.0.2.254; } }
        session    { asn { remote 65003; } }
    }
}

The members group holds everything shared: capabilities, the role declaration, the family list, and the plugin bindings. Each peer inherits from the group and only overrides the remote IP and ASN.

Verification

After ze signal reload:

ze cli -c "peer list"
ze cli -c "bgp summary"

Every peer should reach ESTABLISHED. If any stays in ACTIVE, check connectivity (port 179) and the peer's ASN.

Check the negotiated capabilities on each session:

ze cli -c "peer member-a capabilities"

Every member must have ADD-PATH send/receive, Graceful Restart, and the RS role negotiated. If ADD-PATH is missing, the route server will silently fall back to single-path forwarding and your downstream best-path will be broken.

Check the RIB is forwarding:

ze cli -c "rib routes sent member-a ipv4/unicast | count"
ze cli -c "rib routes sent member-b ipv4/unicast | count"

The counts from member A's routes received should match member B's routes sent (modulo filters).

Expose the Looking Glass:

environment {
    looking-glass {
        enabled true;
        server main { ip 0.0.0.0; port 8443; }
    }
}

Members use the Looking Glass to verify what the route server thinks it sees from them. GET /lg/peers gives the peer dashboard, GET /lg/lookup?prefix=... gives the route search.

Policy notes

This configuration does not show per-member filters. A real IX route server applies at least:

  • Prefix sanity. Reject bogons, reject routes with no-export, reject routes longer than /24 (v4) or /48 (v6), reject routes with a default route.
  • AS-path sanity. Reject routes with known bad AS_PATH attributes.
  • Community scrubbing. Strip communities the IXP owns to prevent members from injecting control communities.
  • RPKI Invalid dropping. Already in this config via invalid-action reject.

Those filters are implemented as policy plugins. The redistribution page covers the mechanism. The specific filter set is deployment-specific: not every filter ships in-tree, and some deployments use external scripts for parts of the chain.

What could go wrong

Forgotten prefix limits. Every family on every peer needs a prefix { maximum }. Ze refuses to start without them. Pick a generous number for full-table peers and a tight one for leaf customers.

Missing ADD-PATH on a peer. The route server silently forwards only the best path to a non-ADD-PATH peer, which is almost certainly not what you want. strict mode is not available on ADD-PATH negotiation; you enforce it with monitoring instead.

Next-hop rewriting. The RFC 7947 route server model does not rewrite the next hop. Routes from member A keep member A's IP as the next hop, which is what downstream members expect at the IX LAN.

Role strict mode off. This config runs with strict false for the RS role. That is the right choice during a deployment where not every member has updated to announce the Role capability. Tighten it to strict true once every member has caught up.

RPKI cache unreachable. If the RPKI cache server is down, routes are fail-open after a 30-second validation timeout. Tune validation-timeout per your risk tolerance.

Congestion. Under heavy churn, the forwarding pool can congest. Watch ze_bgp_pool_used_ratio in Prometheus. Values above 0.8 in steady state mean you are close to congestion teardown for slow peers.

See also

Home

About

First Steps

Configuration

Operation

Interfaces

Plugins

Plugin Development

Chaos Testing

Blueprints

Development

Reference

Clone this wiki locally