Files
ferrix/docs/examples/ferrix.service
T
Rayhaan JaufeerallyandClaude Opus 5.5 65f136048e Graceful restart (RFC 4724, RFC 8538)
A peer that restarts keeps its routes with us, and we keep ours with our
peers while we restart, so that a restart withdraws nothing across the
network and the machine goes on forwarding. On by default for every
peer; `graceful_restart` sets the restart time we give, caps how long a
peer's routes are kept, or turns it off.

When a peer restarts: its routes are marked stale in the routing table,
and chosen as before, for at most its restart time. When it is back, what
it sends again is fresh, and the stale routes of a family go at its
End-of-RIB marker, or after the cap; at once for a family whose
forwarding it did not keep. Only a connection that failed counts as a
restart, and, with RFC 8538 agreed, an expired hold timer or a
NOTIFICATION other than a Hard Reset. The stale mark is a bit of the
route's word that selection never looks at.

When we restart: SIGUSR1 leaves the kernel's routes where they are,
closes the sessions without a word where graceful restart is agreed, and
exits with status 75, on which the systemd unit starts us again. The next
start finds the routes in the kernel, says so in its OPENs (R, and F where
forwarding was kept), and has them go once every peer has sent its
End-of-RIB. Our own End-of-RIB markers for learned routes wait for that
too. SIGTERM still stops for good, now with a Hard Reset where RFC 8538 is
agreed, as are errors of ours.

The status page and API show what was agreed with each peer, the routes
kept while a peer restarts, and which routes are stale. Tested against
FRR and BIRD in a new phase of the interoperability lab, and with routes
kept in a real kernel over a restart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 22:43:47 +02:00

57 lines
1.7 KiB
Desktop File

# /etc/systemd/system/ferrix.service
#
# Runs the Ferrix daemon as an unprivileged user, with only the
# capabilities that it requires, and restricts its access to the system.
# The log is written to the journal: journalctl -u ferrix.
[Unit]
Description=Ferrix BGP daemon
Documentation=https://ferrix.rayhaan.net/docs/
Wants=network-online.target
After=network-online.target
[Service]
Type=exec
User=ferrix
Group=ferrix
# Validate the configuration before starting. An invalid configuration
# prevents the start, and the error is written to the journal.
ExecStartPre=/usr/local/bin/bgp --check /etc/ferrix/server.textpb
ExecStart=/usr/local/bin/bgp /etc/ferrix/server.textpb --level info
Restart=on-failure
RestartSec=5s
# On SIGUSR1 the daemon leaves its routes in place for a graceful restart
# and exits with status 75: start it again at once.
SuccessExitStatus=75
RestartForceExitStatus=75
# Time to notify all neighbors and remove the kernel routes.
TimeoutStopSec=30s
# TCP port 179, and the kernel routing table.
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
NoNewPrivileges=yes
# BGP, RTR, HTTP, and netlink sockets only.
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
ProtectClock=yes
ProtectHostname=yes
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
LockPersonality=yes
MemoryDenyWriteExecute=yes
SystemCallArchitectures=native
SystemCallFilter=@system-service
UMask=0077
[Install]
WantedBy=multi-user.target