Guide

Route Filters

Route filters let plugins act as route filters on import (ingress) and export (egress). Filters are configured per peer, group, or globally using named references in a filter {} config block. Named filter types are defined under bgp { policy { } }.

Quick Start

bgp {
    policy {
        loop-detection no-self-as {
            allow-own-as 0;
        }
    }
    filter {
        import [ no-self-as rpki:validate ];
    }
    group customers {
        filter {
            import [ community:scrub ];
            export [ aspath:prepend ];
        }
    }
}

Filter Types

Filter types are YANG lists under bgp/policy, each marked with ze:filter. Plugins add new filter types via YANG augment. Each list entry is a named filter instance referenced by name in peer filter { import/export } chains.

Built-in: loop-detection

Facade over the in-process LoopIngress wire-bytes filter. Configures AS loop detection (RFC 4271 Section 9) and cluster-list loop detection (RFC 4456 Section 8).

Leaf Type Default Description
allow-own-as uint8 (0-10) 0 Own-AS occurrences to tolerate before rejecting
cluster-id ipv4-address (router-id) Override Router ID for CLUSTER_LIST loop check

External plugin filters

External plugins declare filters at startup using <plugin>:<filter> names. Example: rpki:validate, community:scrub.

How It Works

  1. Filter types are defined in bgp { policy { } } as named instances.
  2. Per-peer filter { import/export [ names ] } references filter instances.
  3. Default filters (e.g., loop-detection) auto-populate in every peer's import chain.
  4. On each received UPDATE, the engine runs the import filter chain.
  5. On each forwarded UPDATE, the engine runs the export chain per destination peer.
  6. Each filter responds accept, reject, or modify (delta-only).

Deactivating Filters

Default filters can be deactivated per-peer using the inline inactive: prefix:

bgp {
    peer special {
        filter {
            import [ inactive:no-self-as ];
        }
    }
}

The inactive: prefix is an input shorthand: it is normalized at parse time into an out-of-band per-member deactivation marker (the stored filter name stays clean), so on serialize it round-trips to the canonical inactive: import no-self-as statement form. The deactivated ref stays in the chain but is skipped at runtime.

In the CLI editor, use deactivate and activate:

deactivate bgp peer special filter import no-self-as
activate bgp peer special filter import no-self-as

Chain Order

Chains are cumulative across config levels:

Level Merge rule
Default Auto-populated first (loop-detection)
bgp Base user chain
group Appended to bgp chain
peer Appended to group chain

Use the insert command in the CLI editor to control position:

insert filter import reject-bogons before no-self-as
insert filter import new-filter last

Filter Responses

Response Meaning
accept Pass update through unchanged
reject Drop update, short-circuit chain
modify Change specific attributes (delta-only)

Conditioning a modifier without dropping the rest

A chain is a pipe in which a reject DROPS the route, so a match filter placed before a modifier can only express "modify these and discard everything else". When the routes the modifier does not touch must keep flowing, put the condition on the modifier itself with a match block. A route that meets none of the stated values returns accept and passes through unchanged.

bgp {
    policy {
        modify blackhole-to-discard {
            match { community [ blackhole ]; }
            set   { next-hop 192.0.2.1; }
        }
    }
    peer customer {
        filter { import [ blackhole-to-discard ]; }
    }
}

A definition with no match block applies to every route that reaches it. See internal/component/bgp/plugins/filter_modify/yang/ze-filter-modify.yang for the full leaf reference.

Filters Cannot Override the RFC 4271 Egress Rules

Four Section 5 rules are asked after the export chain has run, so no filter can grant what the RFC refuses: LOCAL_PREF is removed toward an external peer (5.1.5), a relayed MULTI_EXIT_DISC is removed toward another neighboring AS (5.1.4), a route whose final next hop is the destination peer's own address is withheld (5.1.3), and an UPDATE advertising no reachable NLRI keeps no attribute a filter would have created on it (4.3 and 6.3). See BGP protocol features for the full table.

A modification that cannot be applied suppresses the route for that destination rather than forwarding it unmodified, and increments ze_bgp_update_modify_failed_total{reason}.

Failure Handling

Each filter declares its own failure mode at startup:

Mode Behavior on IPC error/timeout
reject Fail-closed: drop the update
accept Fail-open: pass the update through

Writing a Filter Plugin

A filter plugin is a normal ze plugin that includes filters in its stage 1 declare-registration. See Plugin Guide for general plugin development and docs/architecture/api/process-protocol.md for the wire protocol.