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>
158 lines
8.4 KiB
HTML
158 lines
8.4 KiB
HTML
{% extends "base.html" %}
|
|
{%- import "macros/icons.html" as icons -%}
|
|
|
|
{% block title %}{{ config.title }} · Routing security for every network{% endblock title %}
|
|
{% block body_class %}layout-home{% endblock body_class %}
|
|
|
|
{% block body %}
|
|
<main id="main">
|
|
<section class="hero">
|
|
{#- The photograph is set in two colours by the stylesheet; see .hero-photo. #}
|
|
<div class="hero-photo" aria-hidden="true">
|
|
<img src="{{ get_url(path='images/hero-2400.jpg') }}"
|
|
srcset="{{ get_url(path='images/hero-1200.jpg') }} 1200w, {{ get_url(path='images/hero-2400.jpg') }} 2400w"
|
|
sizes="100vw" alt="" decoding="async" fetchpriority="high">
|
|
<div class="hero-tone"></div>
|
|
<div class="hero-shade"></div>
|
|
</div>
|
|
<div class="hero-copy">
|
|
<span class="eyebrow">BGP-4 · RFC 4271 · version {{ config.extra.version }}</span>
|
|
<h1 class="hero-title">Routing security for every network.</h1>
|
|
<p class="hero-text">
|
|
Ferrix is a BGP daemon for Linux routers. It filters the routes it
|
|
receives, validates them with the RPKI, prevents route leaks with
|
|
BGP roles, and installs the best paths in the kernel. It is free
|
|
software, written in Rust.
|
|
</p>
|
|
<div class="hero-actions">
|
|
<a class="button button-light" href="{{ get_url(path='docs/getting-started/quick-start/') }}">Quick start {{ icons::arrow_right() }}</a>
|
|
<a class="button button-outline-light" href="{{ get_url(path='docs/getting-started/introduction/') }}">Documentation</a>
|
|
</div>
|
|
<p class="hero-foot"><span class="prompt">$</span>cargo build --release -p bgp</p>
|
|
</div>
|
|
<p class="hero-credit">Source: <a href="https://unsplash.com/photos/a-bunch-of-yellow-and-green-wires-and-wires-8oR7XykOjk4">Unsplash</a></p>
|
|
</section>
|
|
|
|
<section class="home-section">
|
|
<div class="home-grid">
|
|
<div class="home-label"><span class="eyebrow">01</span>Default Import Policy</div>
|
|
<div>
|
|
<p class="home-note">Ferrix applies the following checks to every route from an external neighbor by default. Nine of them can be disabled per neighbor where required.</p>
|
|
<ol class="checks">
|
|
<li><span>01</span>Bogon prefixes</li>
|
|
<li><span>02</span>Bogon AS numbers in the path</li>
|
|
<li><span>03</span>Prefixes longer than /24 or /48</li>
|
|
<li><span>04</span>Default route</li>
|
|
<li><span>05</span>AS paths longer than 64</li>
|
|
<li><span>06</span>AS_SET in the path</li>
|
|
<li><span>07</span>First AS is not the neighbor</li>
|
|
<li><span>08</span>Local AS in the path</li>
|
|
<li><span>09</span>Next hop is not the neighbor</li>
|
|
<li><span>10</span>Next hop is unusable</li>
|
|
<li><span>11</span>Local prefixes</li>
|
|
</ol>
|
|
<p class="home-note">Each check reports a distinct rejection reason. RPKI origin validation, ASPA verification, BGP roles, prefix limits, and prefix and origin lists are configured per neighbor.</p>
|
|
<a class="text-link" href="{{ get_url(path='docs/guides/import-policy/') }}#comparison-with-the-nlnog-bgp-filter-guide">Comparison with the NLNOG BGP Filter Guide {{ icons::arrow_right() }}</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="home-section">
|
|
<div class="home-grid">
|
|
<div class="home-label"><span class="eyebrow">02</span>Specifications</div>
|
|
<dl class="spec">
|
|
<div><dt>Protocol</dt><dd>BGP-4, four-octet AS numbers, MP-BGP</dd></div>
|
|
<div><dt>Address families</dt><dd>IPv4 and IPv6 unicast; IPv4 with IPv6 next hops (RFC 8950)</dd></div>
|
|
<div><dt>Validation</dt><dd>RPKI origin validation and ASPA; RTR versions 0 through 2</dd></div>
|
|
<div><dt>Route leak prevention</dt><dd>BGP roles and Only to Customer (RFC 9234)</dd></div>
|
|
<div><dt>Neighbors</dt><dd>Global and link-local addresses</dd></div>
|
|
<div><dt>Policy</dt><dd>Prefix and origin lists, prefix limits, communities, control communities</dd></div>
|
|
<div><dt>Forwarding</dt><dd>Linux kernel over netlink, with nexthop objects</dd></div>
|
|
<div><dt>Kernel installation</dt><dd>1 million routes in about 1 second</dd></div>
|
|
<div><dt>Monitoring</dt><dd>Status page, JSON API, Prometheus metrics</dd></div>
|
|
<div><dt>License</dt><dd>Apache 2.0</dd></div>
|
|
</dl>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="home-section">
|
|
<div class="home-grid">
|
|
<div class="home-label"><span class="eyebrow">03</span>Features</div>
|
|
<div class="features">
|
|
<a class="feature" href="{{ get_url(path='docs/guides/import-policy/') }}">
|
|
<span class="eyebrow">03.1</span>
|
|
<h3>Import Policy</h3>
|
|
<p>Rejects bogon prefixes and AS numbers, third-party next hops, and local prefixes by default. Supports prefix lists, origin AS lists, and prefix limits.</p>
|
|
</a>
|
|
<a class="feature" href="{{ get_url(path='docs/guides/rpki/') }}">
|
|
<span class="eyebrow">03.2</span>
|
|
<h3>RPKI Validation</h3>
|
|
<p>Route origin validation and ASPA verification. Routes are revalidated when the RPKI data changes.</p>
|
|
</a>
|
|
<a class="feature" href="{{ get_url(path='docs/guides/roles/') }}">
|
|
<span class="eyebrow">03.3</span>
|
|
<h3>Route Leak Prevention</h3>
|
|
<p>BGP role negotiation and the Only to Customer attribute, as specified in RFC 9234.</p>
|
|
</a>
|
|
<a class="feature" href="{{ get_url(path='docs/guides/kernel/') }}">
|
|
<span class="eyebrow">03.4</span>
|
|
<h3>Kernel Route Installation</h3>
|
|
<p>Installs active routes over netlink. Routes with unresolvable next hops are excluded from best path selection.</p>
|
|
</a>
|
|
<a class="feature" href="{{ get_url(path='docs/guides/passing-routes-on/') }}">
|
|
<span class="eyebrow">03.5</span>
|
|
<h3>Route Advertisement</h3>
|
|
<p>Advertises learned routes as BGP roles permit, with export policy and route server control communities.</p>
|
|
</a>
|
|
<a class="feature" href="{{ get_url(path='docs/guides/peers/') }}">
|
|
<span class="eyebrow">03.6</span>
|
|
<h3>Neighbor Types</h3>
|
|
<p>Link-local neighbors such as <code>fe80::1%eth0</code>, IPv4 routes with IPv6 next hops, and ADD-PATH.</p>
|
|
</a>
|
|
<a class="feature" href="{{ get_url(path='docs/operations/monitoring/') }}">
|
|
<span class="eyebrow">03.7</span>
|
|
<h3>Monitoring</h3>
|
|
<p>Records every rejected route with its reason. Provides Prometheus metrics and alerting rules.</p>
|
|
</a>
|
|
<a class="feature" href="{{ get_url(path='docs/development/architecture/') }}">
|
|
<span class="eyebrow">03.8</span>
|
|
<h3>Reliability</h3>
|
|
<p>No <code>unsafe</code> code and fuzz-tested parsers. A failure in one session does not affect other sessions.</p>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="home-section">
|
|
<div class="home-grid">
|
|
<div class="home-label"><span class="eyebrow">04</span>Interoperability</div>
|
|
<div>
|
|
<p class="home-note">An automated lab tests Ferrix with FRR 10.5.1, BIRD 2.18, and Routinator 0.15.2, in the following phases:</p>
|
|
<ol class="phases">
|
|
{%- for phase in ["basics", "roles", "rpki", "refresh", "flaps", "restart", "scale", "limits", "hijacks", "nexthops", "transit", "v6only", "linklocal"] %}
|
|
<li><span>{% if loop.index < 10 %}0{% endif %}{{ loop.index }}</span>{{ phase }}</li>
|
|
{%- endfor %}
|
|
</ol>
|
|
<a class="text-link" href="{{ get_url(path='docs/development/testing/') }}#interoperability-lab">Test phases {{ icons::arrow_right() }}</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="home-section">
|
|
<div class="home-grid">
|
|
<div class="home-label"><span class="eyebrow">05</span>Getting Started</div>
|
|
<div class="start">
|
|
<div>
|
|
<p>Establish a BGP session with a test peer on a single host, without privileges and without modifying the kernel routing table.</p>
|
|
<a class="text-link" href="{{ get_url(path='docs/getting-started/quick-start/') }}">Quick start {{ icons::arrow_right() }}</a>
|
|
</div>
|
|
<pre><span class="prompt">$ </span>cargo run -p bgp -- docs/examples/quick-start.textpb
|
|
<span class="prompt">$ </span>cargo run -p bgp-integration-tests --example fake_peer -- \
|
|
--server 127.0.0.1:1790 --asn 65001 --announce 203.0.113.0/24
|
|
<span class="comment"># then http://127.0.0.1:8080/statusz</span></pre>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
{% endblock body %}
|