Files
ferrix/docs/content/docs/guides/import-policy.md
T
Rayhaan JaufeerallyandClaude Opus 5.5 4e945b278f Import rules: preference and communities for some routes only
The import policy did the same to every route of a session. Now `rules`
can do more to some of them: those with certain communities, those for
certain prefixes, or both. Each rule can set the local preference and put
communities on; each route takes the first rule that holds for it.

Rules see a route as the session's own statements leave it, with our
communities taken off and the session's marks put on. So a router can act
on where another router of ours learned a route, by the mark that router
put on it, and a customer's single prefix can be marked for a prepend.

Routes of one UPDATE that different rules hold for go into the table with
attribute sets of their own. An UPDATE that no rule touches is taken as
before, without its attributes being written out again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 16:34:17 +02:00

17 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.

An IBGP neighbor can advertise a prefix that the local router also originates, for example an anycast prefix that both routers originate. Ferrix ignores such a route: it does not accept the route, and does not count it as rejected. This applies only to the originated prefix itself, not to more specific prefixes within it.

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)
Route from an EBGP neighbor with the BLACKHOLE community (RFC 7999) blackhole request

Blackhole Requests

A network under a denial-of-service attack can advertise a route for the attacked address with the BLACKHOLE community (65535:666), to request that other networks discard traffic to the address. At an Internet exchange, the route server distributes such routes to its members with the exchange's blackhole address as the next hop. These routes are usually host routes (/32 or /128).

Ferrix does not support blackhole routing. It rejects every route with the BLACKHOLE community from an EBGP neighbor, with the reason blackhole request, regardless of the prefix length. A route with the BLACKHOLE community that is accepted as an ordinary route directs traffic to the blackhole next hop, which discards it, so Ferrix does not accept these routes as ordinary routes either.

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, the AS path must begin with the neighbor's AS number, and routes with the BLACKHOLE community are rejected.

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: "64496:*"
    add_large_communities: "64500:2:1001"
    local_pref: 150
  }
}

The statements have the following effect:

  • remove_communities removes matching communities. Ferrix applies it after it removes the communities of the local AS (see Communities of the Local AS), and 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

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, or the standard communities 64500:n, which control communities interpret as "advertise to AS n".

Recording Where Routes Are Learned

Informational communities record, on each route, where the local AS learned it. Other routers in the local AS, neighbors, and looking glasses can then see it, and import rules and control communities can act on it. A consistent scheme uses large communities with a function number of 100 or higher, for example:

Community Meaning
64500:100:R Learned by router R.
64500:101:V Learned at venue V: an Internet exchange, a transit provider, or customers.
64500:102:S Learned over interconnection S.

Each router adds them with add_large_communities on every EBGP session:

peers {
  name: "exchange-a-rs1-v4"
  import {
    add_large_communities: "64500:100:1"
    add_large_communities: "64500:101:1"
    add_large_communities: "64500:102:1001"
  }
}

The communities are retained on IBGP sessions, so that each router sees where the other routers learned their routes. Because Ferrix removes the local AS's communities from routes from EBGP neighbors (see Communities of the Local AS), a neighbor cannot set them: every such community on a route was added by a router of the local AS.

Import Rules

Import rules apply local preference and communities to some routes only: routes with certain communities, routes for certain prefixes, or both. Ferrix evaluates the rules of a session in order, and applies the first rule that matches a route. The communities that the rules match are those of the route after the session's other import statements are applied, so rules can match the session's own informational communities.

The following example, on an IBGP session, prefers routes that the other router learned at exchange A over routes that it learned at exchange B, and marks the routes of one prefix:

peers {
  name: "router-2"
  remote_asn: 64500
  import {
    rules { match_communities: "64500:101:1" local_pref: 200 }
    rules { match_communities: "64500:101:2" local_pref: 130 }
    rules {
      match_prefixes { prefix: "192.0.2.0/24" }
      add_large_communities: "64500:31:10"
    }
  }
}

Routes that the rules do not match keep the local preference that they were advertised with. Routes for one prefix that arrive in one UPDATE message can match different rules; Ferrix stores each group separately.

Tip

Choose local preferences so that the local AS's outbound traffic leaves through the same venue through which other networks send their traffic in. If a route is preferred at venue A for outbound traffic, use control communities to prepend the local AS number at the venues that are less preferred. Otherwise traffic to and from a network uses different venues, which makes troubleshooting harder and can overload a link that was meant as a fallback.

Communities of the Local AS

By default, Ferrix removes the local AS's communities from every route that it receives from an EBGP neighbor, before add_communities and add_large_communities are applied. The following communities are removed, where L is the local AS number:

  • Standard communities L:n, if L is 65535 or lower.
  • Large communities L:n:m.
  • Standard communities 0:n, if control_communities is enabled.

These communities are instructions and records of the local AS: control communities decide where Ferrix advertises a route, and informational communities record where a route was learned. A neighbor at an Internet exchange must not be able to set them. Ferrix retains them on routes from IBGP neighbors.

A customer that sets control communities on its own routes requires the following statement:

peers {
  name: "customer-a"
  role: CUSTOMER
  import { accept_control_communities: true }
}

Ferrix then retains all communities of the local AS on the customer's routes. The customer can affect only its own routes. Use remove_communities to remove informational communities that the customer must not set, for example 64500:2:*.

Ferrix examines the communities of every UPDATE message from an EBGP neighbor. A message without communities of the local AS is accepted unchanged.

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.