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
- Filter types are defined in
bgp { policy { } }as named instances. - Per-peer
filter { import/export [ names ] }references filter instances. - Default filters (e.g., loop-detection) auto-populate in every peer's import chain.
- On each received UPDATE, the engine runs the import filter chain.
- On each forwarded UPDATE, the engine runs the export chain per destination peer.
- 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.