Files
ferrix/docs/content/docs/guides/import-policy.md
T
Rayhaan JaufeerallyandClaude Opus 5.5 dc275f99d7
ci / check (push) Canceled after 0s
ci / docs (push) Canceled after 0s
ci / interop (push) Canceled after 0s
ci / fuzz (push) Canceled after 0s
Add a documentation website, built with Zola
The documentation moves from READMEs into a site in docs/: getting
started, a user guide, operations, a reference, and development pages,
written in the style of network vendors' documentation (docs/STYLE.md).
bin/bgp/README.md and docs/RFCs.md are folded into it.

- A theme of its own in the International Typographic Style, in blues,
  with self-hosted Inter and JetBrains Mono, search over Zola's index,
  dark mode, and no resources loaded from other hosts.
- Example configurations in docs/examples/, shown on the pages and
  checked with `bgp --check` in CI.
- A test that fails when a field of config.proto is missing from the
  configuration reference.
- A CI job that builds the site; Zola fails on broken links and anchors.
- A hardened systemd unit, tried under systemd with kernel routes on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:12:43 +02:00

11 KiB

+++ title = "Import Policy" description = "Describes how Ferrix validates routes received from neighbors: the default checks, per-neighbor prefix and origin lists, prefix limits, and attribute modification." weight = 2 +++

The import policy determines which routes received from a neighbor are accepted into the routing table. Ferrix evaluates every route in an UPDATE message against the import policy of the neighbor that advertised it. You configure the import policy with the import statement of each neighbor.

Understanding Import Policy

A neighbor can advertise any prefix with any attributes. If a route that a neighbor is not authorized to advertise is accepted, the local router uses it for forwarding and can advertise it to other neighbors. The import policy rejects such routes before they enter the routing table.

When Ferrix rejects a route, it also removes any route previously accepted from the same neighbor for the same prefix. Ferrix counts rejected routes by reason and retains the most recent rejections for inspection. See Rejected Routes.

Default Checks

Ferrix applies the checks in Table 1 to routes from every neighbor, without configuration. Each check can be disabled for a neighbor that requires it, such as a test network or a transit provider that advertises a default route.

Rejected route Statement to disable Rejection reason
Prefix that is not routed on the Internet: private, loopback, link-local, documentation, multicast, or reserved accept_bogons bogon prefix
Private, reserved, or documentation AS number in the AS path accept_bogons bogon AS in path
IPv4 prefix longer than /24, or IPv6 prefix longer than /48 max_ipv4_prefix_length, max_ipv6_prefix_length prefix too specific
Default route, 0.0.0.0/0 or ::/0 accept_default_route prefix too short
AS path that does not begin with the neighbor's AS number accept_any_first_as path does not begin with the peer's AS
AS path longer than 64 AS numbers max_as_path_length path too long
AS path that contains an AS_SET (RFC 9774) accept_as_sets AS_SET in path
Next hop other than the neighbor's address accept_third_party_next_hop next hop is not the peer
Prefix originated by the local router, or a more specific prefix within it Listing the prefix in the neighbor's prefixes prefix is our own

For an Internet exchange route server, configure accept_any_first_as, because a route server does not prepend its AS number to the AS path. The next hop check does not apply to a neighbor with the role ROUTE_SERVER.

For IBGP neighbors (where remote_asn equals local_asn), Ferrix applies only the checks on the prefix. The AS path checks do not apply, and the next hop can be any usable address.

Ferrix always rejects the routes in Table 2. These checks cannot be disabled.

Rejected route Rejection reason
Route from an EBGP neighbor whose AS path contains the local AS number own AS in path
Route whose next hop is unusable: unspecified, loopback, multicast, or an address of the local router next hop unusable
Route with the Only to Customer attribute received from the wrong direction (see BGP Roles) route leak (Only to Customer)

Next Hop Check

The next hop of a route is the address to which the local router forwards traffic for the prefix. By default, Ferrix requires the next hop of a route from an EBGP neighbor to be the neighbor's own address. This prevents a neighbor from directing traffic to a third party, such as another member of an Internet exchange or a host in another network of the local operator.

An Internet exchange route server advertises routes with the addresses of the originating members as next hops. For this reason, the check does not apply to a neighbor with the role ROUTE_SERVER.

Local Prefix Check

By default, Ferrix rejects routes from EBGP neighbors for prefixes that it originates, and for more specific prefixes within them. Accepting such a route would direct traffic for the local network to an external network.

If a customer is authorized to advertise part of the local address space, include the prefix in the customer's prefixes list. When a neighbor has a prefixes list, the local prefix check does not apply to it.

Comparison with the NLNOG BGP Filter Guide

The NLNOG BGP Filter Guide lists the inbound filters that operators commonly configure on EBGP sessions. Many BGP implementations, including FRR, BIRD, and Cisco IOS XR, reject all routes from an EBGP neighbor until a policy is configured (RFC 8212), and the operator writes these filters in the implementation's policy language. Ferrix applies most of them by default. Table 3 compares the guide with Ferrix.

Filter in the guide Ferrix
Reject RPKI invalid routes One statement: rpki
Attest trust anchor prefixes (SLURM) Configured in the RPKI validator
Bogon ASN filtering Default
Bogon prefix filtering Default
No small prefixes Default: longer than /24 or /48
No IXP peering LAN leaks Partial: such routes are never installed in the kernel, but they are not rejected
No long AS paths Default: longer than 64 AS numbers
No known transit ASNs in the AS path Not supported. BGP roles and ASPA verification detect many of the same route leaks.
Strip high community counts Not supported
Remainder accept term with communities and local preference add_communities, add_large_communities, local_pref
Graceful shutdown support Not supported

Ferrix also applies the following checks, which the guide does not list, by default: the next hop must be the neighbor, routes for local prefixes are rejected, AS paths with an AS_SET are rejected, and the AS path must begin with the neighbor's AS number.

Note

Ferrix does not implement the default behavior of RFC 8212 on import: it accepts routes from an EBGP neighbor that pass the default checks. On export, Ferrix advertises only originated routes unless learned_routes is enabled, so that learned routes are not advertised without explicit configuration.

Configuring Prefix and Origin Lists

To restrict the routes that a neighbor can advertise, configure a prefix list, an origin AS list, or both:

import {
  prefixes { prefix: "193.0.0.0/21" max_length: 24 }
  prefixes { prefix: "2001:67c:2e8::/48" }
  origin_asns: 3333
}
  • prefixes lists the prefixes that the neighbor can advertise. The max_length option also permits more specific prefixes up to the specified length. If the list is empty, all prefixes are permitted. Rejection reason: prefix not allowed.
  • origin_asns lists the AS numbers from which the neighbor's routes can originate. The origin AS is the last AS number in the AS path. If the list is empty, all origin AS numbers are permitted. Rejection reason: origin AS not allowed.

Generating Lists with bgpq4

You can generate prefix and origin AS lists from Internet Routing Registry (IRR) data with bgpq4. The following commands query the registry for an AS-SET and convert the output to Ferrix configuration statements with jq:

bgpq4 -4 -R 24 -j -l prefixes AS-EXAMPLE > v4.json
bgpq4 -6 -R 48 -j -l prefixes AS-EXAMPLE > v6.json
bgpq4 -t -j -l asns AS-EXAMPLE > asns.json

jq -r '.prefixes[] | "prefixes { prefix: \"\(.prefix)\""
    + (if .exact then "" else " max_length: \(."less-equal")" end) + " }"' v4.json v6.json
jq -r '.asns[] | "origin_asns: \(.)"' asns.json

The commands produce statements such as the following, for the neighbor's import statement:

prefixes { prefix: "193.0.0.0/21" max_length: 24 }
prefixes { prefix: "193.0.10.0/23" max_length: 24 }
origin_asns: 3333

Tip

Regenerate the lists periodically, validate the new configuration with bgp --check, and restart the daemon. An outdated list rejects the neighbor's new prefixes with the reason prefix not allowed.

Prefix Limits

The max_prefixes statement specifies the maximum number of routes that a neighbor can have in the routing table. If the neighbor exceeds the limit, Ferrix sends a Cease NOTIFICATION message with the subcode Maximum Number of Prefixes Reached, tears down the session, and places the neighbor in hold-down for hold_down_seconds. During hold-down, Ferrix neither initiates nor accepts connections for the neighbor.

import {
  max_prefixes: 1500000
  hold_down_seconds: 600
}

By default, the number of prefixes is not limited. The default hold-down is 600 seconds.

Important

Configure max_prefixes for every neighbor, with a value somewhat above the number of routes that the neighbor is expected to advertise. Without a limit, a neighbor that leaks a full routing table is accepted.

The metrics bgp_peer_routes and bgp_peer_max_prefixes report the current number of routes and the limit for each neighbor. See Alerting Rules.

RPKI and ASPA Validation

If RPKI validation is configured, Ferrix also rejects routes whose origin is RPKI invalid and, for neighbors with a role, routes whose AS path is ASPA invalid. See RPKI.

Modifying Route Attributes

The import policy can add and remove communities on accepted routes, and set their local preference:

peers {
  name: "ixp-a-rs"
  import {
    remove_communities: "64500:2:*"
    remove_communities: "64500:3:*"
    add_large_communities: "64500:2:1001"
    local_pref: 150
  }
}

The statements have the following effect:

  • remove_communities removes matching communities. Ferrix applies it before adding communities. A pattern has two fields for a standard community and three for a large community; each field is a number or *. Examples: 64500:100, 64500:*, 64500:2:*, *:*.
  • add_communities and add_large_communities add communities to every accepted route. Use them to record where a route was learned, for other routers in the local AS and for export policy.
  • local_pref sets the local preference of every accepted route. Best path selection compares local preference first; the route with the higher value is preferred. Default: 100.

Tip

Remove the local AS's informational communities from received routes, so that a neighbor cannot set them. A common local preference scheme assigns 200 to customer routes, 150 to peer and route server routes, and 100 to transit routes.

The examples in this documentation use large communities 64500:2:x to record where a route was learned and 64500:3:r to record the router that advertised it. These values do not overlap the control communities, which use 64500:0:* and 64500:1:*, or the standard communities 64500:n, which control communities interpret as "advertise to AS n".

Performance

Ferrix evaluates each route once, when the session's task processes the UPDATE message. Each check is a comparison or a table lookup. Attribute modifications are applied once for each UPDATE message, because all routes in a message share the same attributes. A full routing table from one neighbor is accepted into the routing table in less than 0.5 seconds.