Bidirectional Forwarding Detection (BFD) is a small UDP protocol that lets two routers prove to each other, many times a second, that the forwarding path between them still works. It was standardised in June 2010 as RFC 5880. Routing protocols such as BGP, OSPF and IS-IS register with it so a dead link is noticed in milliseconds instead of tens of seconds.
The protocol is simple on paper and easy to get wrong in production: a detection time that is too aggressive turns a busy control plane into a flapping network, and a session with no authentication lets anyone who can reach UDP port 3784 or 4784 declare your links down. This post goes one level deeper than our guides to VRRP, OSPF and BGP. It covers the state machine, timer arithmetic with worked numbers, the modes and variants, every authentication type in the IANA registry, and a FRRouting lab.
Key takeaways
- BFD is defined by RFC 5880, published in June 2010 together with RFC 5881 (single hop IPv4 and IPv6), RFC 5882 (how applications use it), RFC 5883 (multihop paths) and RFC 5884 (MPLS label switched paths).
- A session has four states: AdminDown, Down, Init and Up. Two systems reach Up through a three way handshake, and each side identifies the session with a nonzero discriminator it chooses itself.
- Detection time is calculated by the receiver, separately in each direction: the remote side's Detect Mult multiplied by the larger of the local Required Min RX Interval and the remote Desired Min TX Interval. Three packets at 300 ms gives 900 ms; three at 50 ms gives 150 ms.
- Transmit intervals carry a random 0 to 25% reduction to avoid self synchronisation, and while a session is not Up each side must transmit no faster than once a second.
- Asynchronous mode is the normal mode. Demand mode stops periodic packets and relies on something else to verify the path. The echo function loops packets through the neighbour's forwarding plane and works only on a single hop.
- Single hop BFD uses UDP port 3784 and requires a TTL or Hop Limit of 255 on send and receive. Multihop uses port 4784, cannot use echo and should use authentication. Micro-BFD on LAG member links uses port 6784, and Seamless BFD reflectors listen on port 7784.
- The IANA registry now lists authentication types 1 to 8: simple password, keyed and meticulous keyed MD5 and SHA1, a NULL type for loss measurement (RFC 9978), and two optimised ISAAC types (RFC 9986). The MD5 and SHA1 types use a secret suffix construction, not HMAC.
What BFD is and why routing protocols need it
Every routing protocol already has a liveness check. OSPF routers exchange Hello packets and declare a neighbour dead after the RouterDeadInterval; RFC 2328 gives 10 seconds as a sample Hello interval on a LAN and suggests a dead interval of some multiple of it, such as four. BGP sends keepalives and tears a session down when the hold timer expires; RFC 4271 suggests a default HoldTime of 90 seconds and says a non-zero hold time must be at least three seconds. VRRP version 3 (RFC 9568) defaults to an advertisement every second and a backup declares the active router down after three intervals plus a skew time.
RFC 5882 puts numbers on the floor: OSPF has a minimum detection time of two seconds and IS-IS one second. At 10 Gb/s, two seconds is 2.5 gigabytes sent into a black hole. Shortening every protocol's hellos is possible but means every protocol runs its own fast timers.
BFD separates the question "is the forwarding path alive?" from the protocols that need the answer. RFC 5880 describes it as detecting faults in the bidirectional path between two forwarding engines, independently of media, data protocols and routing protocols. BGP, OSPF and a static route to the same neighbour can all subscribe to one session.
RFC 5880 states plainly that there is no discovery mechanism in BFD. Its own example is OSPF: OSPF learns a neighbour from its Hello, asks BFD for a session to that address, and from then on treats a BFD Down as a neighbour failure.
Dated timeline of the BFD standards
Dates come from each RFC header and the IETF datatracker.
| Date | Document | What it added |
|---|---|---|
| October 2007 | RFC 5082 | Generalized TTL Security Mechanism (GTSM), the TTL 255 check BFD single hop relies on; obsoletes RFC 3682 |
| June 2010 | RFC 5880 | Base BFD protocol: packet format, state machine, timers, modes, authentication |
| June 2010 | RFC 5881 | BFD for IPv4 and IPv6 single hop: UDP ports 3784 and 3785, TTL 255 |
| June 2010 | RFC 5882 | Generic application of BFD: how clients such as OSPF, IS-IS, BGP and static routes should react |
| June 2010 | RFC 5883 | BFD for multihop paths: UDP port 4784, no echo |
| June 2010 | RFC 5884, RFC 5885 | BFD for MPLS label switched paths and for pseudowire connectivity verification |
| February 2014 | RFC 7130 | BFD on LAG interfaces: micro-BFD sessions per member link, UDP port 6784 |
| December 2014 | RFC 7419 | Common interval set for hardware implementations (Informational) |
| July 2016 | RFC 7880, RFC 7881, RFC 7882 | Seamless BFD (S-BFD), its IPv4, IPv6 and MPLS encapsulation (port 7784), and use cases |
| October 2021 | RFC 9127 | YANG data model for BFD |
| March 2023 | RFC 9384 | BGP Cease NOTIFICATION subcode 10, "BFD Down" |
| August 2023 | RFC 9468 | Unsolicited BFD for sessionless applications |
| March 2025 | RFC 9747 | Unaffiliated BFD Echo, echo without a control session; updates RFC 5880 |
| April 2025 | RFC 9764 | BFD encapsulated in large packets, to verify path MTU |
| June 2026 | RFC 9978 | BFD Stability: packet loss detection, NULL authentication type (Experimental) |
| June 2026 | RFC 9985 | Optimizing BFD authentication: costly checks on significant changes, cheap checks on the rest (Experimental) |
| June 2026 | RFC 9986 | Meticulous Keyed ISAAC authentication types 7 and 8 (Experimental) |
| June to August 2026 | draft-ietf-bfd-rfc5880bis and companions | Working group drafts to revise RFC 5880 to 5884; the 5880bis draft states it obsoletes RFC 5880 and strongly discourages MD5 |
The bis drafts are work in progress. The datatracker lists them as working group documents with a December 2026 milestone, so treat RFC 5880 as the current standard until a replacement is published.
How a BFD session comes up
The control packet
A BFD control packet is a UDP datagram with a 24 byte mandatory section and an optional authentication section. RFC 5880 section 4.1 defines these fields:
| Field | Size | What it carries |
|---|---|---|
| Vers | 3 bits | Protocol version, currently 1 |
| Diag | 5 bits | Why the sender's session last changed state (see the next table) |
| Sta | 2 bits | Sender's state: AdminDown (0), Down (1), Init (2), Up (3) |
| P, F | 1 bit each | Poll and Final, used to confirm parameter changes |
| C | 1 bit | Control Plane Independent: the sender's BFD runs in the forwarding plane and survives a control plane restart |
| A | 1 bit | Authentication section present |
| D | 1 bit | Demand mode requested |
| M | 1 bit | Multipoint, reserved in the base spec and later used by RFC 8562 |
| Detect Mult | 8 bits | Detection time multiplier, 1 to 255 |
| Length | 8 bits | Packet length in bytes |
| My Discriminator | 32 bits | Nonzero value the sender chose for this session |
| Your Discriminator | 32 bits | The value received from the peer, or zero if not yet known |
| Desired Min TX Interval | 32 bits | Fastest the sender wants to transmit, in microseconds |
| Required Min RX Interval | 32 bits | Fastest the sender can receive, in microseconds; zero means "send me nothing periodic" |
| Required Min Echo RX Interval | 32 bits | Fastest the sender can loop echo packets; zero means no echo support |
The intervals are in microseconds, which matters when you read a packet capture: 300 ms appears as 300000. RFC 5880 also says the Desired Min TX Interval value zero is reserved.
The diagnostic codes are kept in the IANA "BFD Diagnostic Codes" registry:
| Code | Meaning | Typical cause |
|---|---|---|
| 0 | No Diagnostic | Normal operation |
| 1 | Control Detection Time Expired | Packets stopped arriving for a full detection time |
| 2 | Echo Function Failed | Looped echo packets stopped returning |
| 3 | Neighbor Signaled Session Down | The peer sent Down |
| 4 | Forwarding Plane Reset | Local forwarding plane restarted |
| 5 | Path Down | A path the session depends on failed |
| 6 | Concatenated Path Down | A segment of a concatenated path failed |
| 7 | Administratively Down | Operator shut the session |
| 8 | Reverse Concatenated Path Down | Reverse direction of a concatenated path failed |
| 9 | Mis-connectivity defect | Added for MPLS transport profile use (RFC 6428) |
When troubleshooting, read the remote diagnostic: remote code 1 means the peer stopped hearing you.
The state machine
RFC 5880 section 6.2 calls the state machine "quite straightforward", and it is. A session normally moves through three states, Down, Init and Up, and a fourth state, AdminDown, lets an operator hold it down indefinitely without implying the path has failed.
The rules come from the State field in the packets each side receives:
- Both routers start in Down and send packets with Sta set to Down and Your Discriminator set to zero, because neither knows the other's discriminator yet.
- Router A receives Down from B. A records B's discriminator, moves to Init and sends Init.
- Router B receives Init from A. B moves straight to Up and sends Up.
- Router A receives Up (or Init) from B and moves to Up.
That is a three way handshake: each side has proof that the other can hear it. Teardown works the same way. If either side signals Down, or the detection time expires, the other moves to Down and records the reason in Diag.
Discriminators let a router demultiplex many sessions to the same neighbour. And RFC 5880 section 6.8.3 says that while a session is not Up, a system must transmit no faster than once a second, so a neighbour not running BFD sees negligible traffic. That is why a new FRRouting peer shows the remote side at 1000 ms until the session comes up.
Poll and Final: changing timers safely
Timers can change during a session. Any change to the intervals is confirmed with a Poll Sequence: the side making the change sets the P bit until it receives a packet with the F bit set. RFC 5880 forbids a packet with both bits set. When slowing down, the new, slower transmit rate takes effect only after the Final arrives; when the receiver lowers its Required Min RX Interval, it keeps using the old detection time until the poll completes.
How the timers and the detect multiplier work
The formula
In asynchronous mode, RFC 5880 section 6.8.4 defines the detection time on the receiving system as:
Detection Time = remote Detect Mult
x max(local Required Min RX Interval,
remote Desired Min TX Interval)
Three points follow from that definition and cause most of the confusion in real networks:
- The detection time is calculated by the receiver, not carried in the packet. Each direction can have a different detection time.
- The multiplier that counts is the one the remote side sends. If you set Detect Mult 3 locally, you are telling your peer how many of your packets it may miss, not how many of its packets you will tolerate.
- The slower of the two sides wins. A router that can only receive every 300 ms forces its peer to transmit no faster than that, however aggressive the peer's own configuration.
The transmit side has two more rules from section 6.8.7. Each periodic transmission must be reduced by a random 0 to 25%, so the average interval is about 12.5% below the negotiated value. If Detect Mult is 1, the interval must stay between 75% and 90% of the negotiated value, so that the single packet always arrives before the receiver's timer runs out.
Worked example 1: symmetric defaults
FRRouting's bfdd defaults are a transmit interval of 300 ms, a receive interval of 300 ms and a detect multiplier of 3. With both sides on defaults:
- Each side transmits at max(300, 300) = 300 ms, less jitter, so packets leave every 225 to 300 ms.
- Each side's detection time is 3 x max(300, 300) = 900 ms.
FRRouting's own documentation gives a slightly different example worth working through. The local system has detect-multiplier 3 and transmit-interval 300; the remote system has receive-interval 200. The remote system uses max(200, 300) = 300 ms and multiplies by the local multiplier of 3, so it "will detect failures only after 900 milliseconds" without packets. Lowering the remote receive interval did nothing, because the local transmit interval was the larger value.
Worked example 2: asymmetric configuration
Two routers are configured differently, which is common when one is an older platform:
| Parameter | Router A | Router B |
|---|---|---|
| Desired Min TX Interval | 50 ms | 300 ms |
| Required Min RX Interval | 100 ms | 50 ms |
| Detect Mult | 3 | 5 |
Direction A to B. A transmits every max(A's desired TX 50, B's required RX 50) = 50 ms. B's detection time is A's Detect Mult multiplied by max(B's required RX 50, A's desired TX 50): 3 x 50 = 150 ms.
Direction B to A. B transmits every max(B's desired TX 300, A's required RX 100) = 300 ms. A's detection time is B's Detect Mult multiplied by max(A's required RX 100, B's desired TX 300): 5 x 300 = 1,500 ms.
So B notices a failure in 150 ms and A notices the same failure in 1.5 seconds. If A is the router that must reroute traffic quickly, this configuration fails its design goal even though one side's settings look aggressive. Always compute both directions, or better, configure both sides the same.
Worked example 3: packet rate, bandwidth and hashing cost
Take 200 single hop sessions at 50 ms with Detect Mult 3, giving a 150 ms detection time.
- Each session sends 1,000 / 50 = 20 packets a second and receives 20. Two hundred sessions mean about 4,000 packets a second out and 4,000 in, before jitter, which raises the rate slightly because intervals are shortened.
- An unauthenticated IPv4 BFD packet is 24 bytes of BFD, 8 bytes of UDP and 20 bytes of IPv4: 52 bytes before link framing. At 20 packets a second that is 8,320 bits a second per direction per session.
- Keyed SHA1 adds a 28 byte authentication section (RFC 5880 section 4.4), making 80 bytes and 12,800 bits a second per direction per session.
- With meticulous keyed SHA1 every packet carries a new sequence number and a fresh hash, so each session needs about 40 hash computations a second (20 to send, 20 to verify), or roughly 8,000 a second across 200 sessions.
Bandwidth is never the problem. The cost is scheduling: thousands of timers that must fire on time and thousands of packets that must be processed within a fraction of the detection time. That is why RFC 7419 describes vendors moving periodic transmission and timeout detection to network processors, FPGAs and other hardware, and why the same RFC recommends a common set of intervals (3.3 ms, 10 ms, 20 ms, 50 ms, 100 ms and 1 second) so that hardware implementations can agree.
Detection is only part of failover
Detection time is the time to notice. Total failover also includes the client's reaction (BGP tearing down a session, OSPF running SPF), the routing table update and the forwarding table update in hardware. If you size BFD at 150 ms and the platform takes a second to program a new next hop, faster BFD buys little. Measure the whole chain in a lab before you promise a convergence figure.
Asynchronous mode, demand mode and the echo function
Asynchronous mode
Both systems send control packets periodically and each declares the session down when a detection time passes without a valid packet. Most networks need nothing else.
Demand mode
In demand mode a system asks its peer to stop sending periodic control packets, "on the understanding" that connectivity is being verified some other way, in FRRouting's words. The path is checked only when a Poll Sequence is started. RFC 5880 computes demand mode detection time from the local side: the local Detect Mult multiplied by the larger of the local Desired Min TX Interval and the remote Required Min RX Interval, counted from the first packet with the Poll bit set.
FRRouting's documentation warns that if both ends enable demand mode without echo, neither system transmits and neither runs a detection timer, so a failed path can go unnoticed. Pair it with echo or do not use it.
The echo function
With echo, a router sends BFD echo packets addressed so that the neighbour's forwarding plane loops them straight back without its BFD process ever seeing them. If enough echo packets fail to return, the session goes down with diagnostic 2, Echo Function Failed.
Echo tests the neighbour's forwarding path rather than its BFD process. FRRouting suggests slowing control packets once echo is on, for example transmit-interval 2000. Echo has hard limits:
- RFC 5881 puts echo on UDP port 3785, and the neighbour advertises how fast it can loop packets in Required Min Echo RX Interval; zero means it will not loop them.
- Because echo packets come back with the sender's own address as destination, RFC 5881 says ingress filtering in the BCP 38 style is incompatible with them, and implementations must exempt echo packets or not filter on that interface. Unicast reverse path checks are a common place to trip over this.
- RFC 5880 says that while echo is active a system should set its Required Min RX Interval for control packets to at least one second, because the detection is now done by echo.
- RFC 5883 says the echo function must not be used over multiple hops.
- FRRouting's documentation says that without distributed BFD, its echo mode only works when the peer is also FRRouting.
RFC 9747 (March 2025) adds Unaffiliated BFD Echo, which runs echo without an associated control session, for networks where setting up control sessions is impractical.
| Mode | Packets on the wire | Detects | Good for | Watch out for |
|---|---|---|---|---|
| Asynchronous | Periodic control packets both ways | Loss of control packets for a detection time | Almost everything | Timer and CPU cost at low intervals |
| Asynchronous with echo | Echo looped through the peer's forwarding plane, slower control packets | Forwarding plane failure on the neighbour | Single hop links where the peer supports echo | Ingress filtering and reverse path checks; single hop only |
| Demand | Control packets only during a Poll Sequence | Failure when a poll is not answered | Paths verified by another mechanism | No detection at all if nothing triggers a poll |
| Unaffiliated echo (RFC 9747) | Echo only, no control session | Forwarding path failure | Hosts or devices that cannot run full BFD | Newer, check implementation support |
Single hop, multihop, LAG and Seamless BFD
Single hop (RFC 5881)
Single hop BFD runs between directly connected neighbours. Control packets go to UDP destination port 3784 with a source port between 49152 and 65535, the same source port for every packet in a session. Every control packet must be sent with a TTL or Hop Limit of 255, and every received packet for the session must be discarded unless its TTL or Hop Limit is exactly 255. Because each router decrements the TTL, a packet that arrives with 255 cannot have come from further away than the directly connected link. That is GTSM, described in RFC 5082, applied to BFD.
Multihop (RFC 5883)
Multihop BFD runs between systems that are not directly connected, such as eBGP peers between loopbacks, on UDP port 4784. RFC 5883 lists its problems: spoofing, because the TTL 255 trick no longer works; demultiplexing, because the first packet may arrive on any interface; and echo, which must not be used. For spoofing, RFC 5883 says implementations should use cryptographic authentication and strongly encourages strong forms of it. FRRouting's minimum-ttl setting for multihop peers adds a looser check: the default of 254 means one hop is expected, and you lower it to the smallest TTL you expect to see.
BFD on LAG member links (RFC 7130)
A single BFD session over a link aggregation group only proves that at least one member works; hashing may carry BFD over a healthy member while traffic on a broken one is lost. RFC 7130 runs one "micro-BFD" session per member link, per address family, each an independent BFD session with its own state machine. Micro-BFD packets use UDP destination port 6784, and on Ethernet the destination MAC address is the dedicated multicast address 01-00-5E-90-00-01. The separate port removes ambiguity when one side is misconfigured with micro-BFD and the other with ordinary single hop BFD over the bundle.
Seamless BFD (RFC 7880 and RFC 7881)
Seamless BFD removes the handshake classic BFD needs before it can test anything. A network node allocates S-BFD discriminators in advance and runs an SBFDReflector session that listens for them on UDP port 7784. An SBFDInitiator sends control packets to that port with the reflector's discriminator as Your Discriminator, and the reflector answers. The initiator's source port must not be 7784. The result is a path check that can start with the first packet, which suits a headend or controller testing many paths; RFC 7882 lists the use cases the working group had in mind.
Other variants cover MPLS LSPs (RFC 5884), multipoint networks (RFC 8562, RFC 8563, RFC 9780), VXLAN (RFC 8971), sessions that only one side configures (RFC 9468) and padded packets that also prove the path MTU (RFC 9764).
| Variant | UDP destination port | TTL or Hop Limit rule | Echo allowed | Typical use |
|---|---|---|---|---|
| Single hop (RFC 5881) | 3784 (echo 3785) | Must be 255 on send and receive | Yes | Directly connected IGP and eBGP neighbours, static next hops |
| Multihop (RFC 5883) | 4784 | GTSM does not work; use authentication and a minimum TTL policy | No | Loopback eBGP, tunnels, remote static next hops |
| Micro-BFD on LAG (RFC 7130) | 6784 | Per member link | Outside the scope of RFC 7130 | Detecting a single failed member of a bundle |
| Seamless BFD (RFC 7880, RFC 7881) | 7784 at the reflector | Per encapsulation | Not applicable | Fast, handshake free path checks from a headend or controller |
How BGP, OSPF, IS-IS, static routes and VRRP use BFD
RFC 5882 is the document that tells clients what to do with a BFD state change. Its core rules:
- When a BFD session goes Down, clients should treat it as a failure of the path and take the action they would take for an adjacency failure: OSPF tears down the neighbour, IS-IS simulates an adjacency failure, BGP closes the session.
- Whether a session that is not Up means failure depends on the neighbour. For non-protocol uses such as static routes, RFC 5882 says that if the remote system is known or presumed to support BFD and the session is not Up, action such as withdrawing the static route should be taken; if the remote system is known not to support BFD, it should not.
- Implementations may apply hysteresis: section 3.1 allows a system to hide a quick Up, Down, Up sequence from clients if the session recovers within a reasonable period, which helps survive process restarts.
- Not every protocol should register. RFC 5882 gives the example of OSPF and internal BGP: because IBGP depends on OSPF for reachability, faster failure detection relayed to IBGP "may actually be detrimental". A BGP session reset is expensive, and OSPF will reroute around the failure on its own. RFC 5882 describes BFD as useful for external BGP and says BFD authentication should be used there and is strongly encouraged.
RFC 9384 (March 2023) made the BGP side easier to debug. When BGP tears a session down because BFD went Down, it can send a Cease NOTIFICATION with subcode 10, "BFD Down", so the peer's logs show the real reason. If BGP hard reset is in use, the subcode is carried inside the Hard Reset notification.
Graceful restart needs care: if BFD dies with a restarting control plane, the neighbour sees BFD Down and tears everything down. The C bit tells the peer whether the sender's BFD is independent of its control plane, and RFC 5882 section 4.3 explains how to combine the two. In FRRouting, the BGP command neighbor ... bfd check-control-plane-failure uses the C bit so a BFD Down can be ignored while waiting for a gracefully restarting peer.
Static routes have no hello of their own, so BFD suits them well. In FRRouting, a static route with the bfd keyword is installed only while the session to the gateway is Up.
VRRP is the exception in this list. RFC 9568 defines no BFD interaction, and FRRouting's BFD documentation lists BGP, IS-IS, OpenFabric, OSPF, OSPFv3, PIM, RIP and static routes as clients, not VRRP. If you want a VRRP backup to take over faster than three advertisement intervals plus skew time (about 3.6 seconds at the default one second interval and priority 100), check what your own implementation offers rather than assuming BFD can drive it.
What goes wrong with aggressive timers
Fast timers are the reason to run BFD, and the reason BFD causes outages:
- CPU starvation and false failures. If BFD runs in a control plane process, a spike in routing work (a full BGP table arriving, a large SPF run) can delay transmissions or receive processing past the detection time. The session drops, BGP resets, more routing work arrives, and the cycle repeats.
- Congestion. A link saturated by a burst can drop enough BFD packets to declare a working link dead. Check that BFD gets a priority queue.
- Flapping. An intermittently lossy link brings the session down and up repeatedly, resetting BGP and triggering SPF each time. Hold down timers and RFC 5882 style hysteresis trade a little speed for stability.
- Asymmetric results. As worked example 2 showed, one side can detect failure ten times faster than the other.
- Interaction with lower layer protection. If an optical or link layer protection switch takes 50 ms and BFD detects in 30 ms, BFD will fire during every protection switch. Set BFD slower than the layer below it.
- Monitoring blind spots. A session that stays Up proves only that BFD packets get through. RFC 9978 (June 2026, Experimental) adds a way to detect BFD packet loss that does not last long enough to bring the session down, because a link losing one packet in three may still keep BFD Up while it damages traffic.
A practical rule: start at 300 ms with a multiplier of 3, measure CPU and false failures under load, and move faster only where a specific requirement needs it and the platform runs BFD in hardware or a dedicated process.
BFD authentication and GTSM
Why BFD needs protection
RFC 5880's security considerations are blunt. Because BFD is tied to routing, an attack can make a link look down when it is up or up when it is down, and either way the result is denial of service. An attacker who controls the link can drop only BFD packets, or forward only BFD packets, and BFD cannot prevent that. Against less capable attackers, BFD offers two defences: GTSM and the authentication section.
GTSM: the TTL 255 check
For a session across a single link, RFC 5880 says the TTL or Hop Limit must be set to the maximum on transmit and checked to be equal to the maximum on reception. A spoofed packet from anywhere off the link arrives with a TTL lower than 255 and is discarded. This is cheap, stateless and effective, and it is mandatory for single hop BFD under RFC 5881. RFC 5082 describes the general mechanism and its limits: it does nothing against an attacker on the same link, and it does not apply to multihop sessions, which is why RFC 5880 says authentication should be used for multihop sessions and for sessions over an insecure tunnel such as GRE.
The authentication types
The IANA "BFD Authentication Types" registry, last updated on 2 July 2026, lists:
| Type | Name | Defined in | Sequence number | Notes |
|---|---|---|---|---|
| 0 | Reserved | RFC 5880 | ||
| 1 | Simple Password | RFC 5880 | None | Password of 1 to 16 bytes sent in clear |
| 2 | Keyed MD5 | RFC 5880 | Incremented occasionally | 24 byte section; replay possible between increments |
| 3 | Meticulous Keyed MD5 | RFC 5880 | Incremented on every packet | Smaller replay window |
| 4 | Keyed SHA1 | RFC 5880 | Incremented occasionally | 28 byte section |
| 5 | Meticulous Keyed SHA1 | RFC 5880 | Incremented on every packet | Strongest of the original types |
| 6 | NULL | RFC 9978 | Yes | Carries a sequence number for loss measurement without cryptographic protection (Experimental) |
| 7 | Optimized MD5 Meticulous Keyed ISAAC | RFC 9986 | Yes | Experimental |
| 8 | Optimized SHA-1 Meticulous Keyed ISAAC | RFC 9986 | Yes | Experimental |
| 9 to 255 | Unassigned |
How the original types differ:
- Simple password puts the password in every packet. RFC 5880 says to consider it only where the infrastructure is guaranteed not to be subject to packet interception.
- Keyed MD5 and keyed SHA1 add a sequence number and a hash computed with the shared key, so the key cannot be read from a capture. Without meticulous mode the sequence number may stay the same for many packets, so a captured packet can be replayed until it changes. Receivers accept sequence numbers up to three times Detect Mult ahead of the last one.
- Meticulous variants require a new sequence number on every packet and start from a random value, which shrinks the replay window. RFC 5880 notes there is still a window at the start of the session while the sequence number is being learned.
- Not HMAC. RFC 5880 says both keyed MD5 and keyed SHA1 use a "secret suffix" construction, where the key is appended to the data before hashing, instead of HMAC. It considered that acceptable for BFD but encouraged designers of new mechanisms to read the HMAC literature.
- Randomised discriminators. RFC 5880 adds that if both systems randomise their discriminators at the start of a session, replay attacks are harder whatever authentication type is used.
Why authentication is rarely turned on, and what June 2026 changed
The obstacle is cost: a hash on every packet, both ways, across hundreds of fast sessions. A 2014 draft for HMAC-SHA-2 BFD authentication (draft-ietf-bfd-hmac-sha-05) is listed on the datatracker as expired, "Waiting for Implementation".
The three experimental RFCs published in June 2026 address the cost directly:
- RFC 9985, Optimizing BFD Authentication. It splits authentication into a more computationally intensive (MCI) mechanism and a less computationally intensive (LCI) one. Packets that carry a significant change must use MCI. The RFC defines a significant change as a state change, a demand mode (D bit) change or a poll sequence change (P or F bit), and also counts changes that need no poll sequence, such as Detect Mult. The steady stream of identical Up packets can use LCI. A packet that should have been MCI authenticated but was not is discarded. The RFC also says the contents of an Up packet must not change, apart from the authentication section, without MCI authentication.
- RFC 9986, Meticulous Keyed ISAAC. It defines an LCI mode based on the ISAAC pseudorandom number generator, seeded from a mix of secret and public session data, which authenticates Up packets at lower CPU cost than MD5 or SHA-1. The RFC states the trade off plainly: less CPU time, decreased security, and it cannot be used to signal state changes. IANA assigned types 7 and 8 for the MD5 and SHA-1 pairings.
- RFC 9978, BFD Stability. It adds the NULL authentication type 6 so a sequence number can be carried purely for loss measurement.
All three are Experimental, not Standards Track. Treat them as something to test with your vendors, not a baseline you can expect every router to support.
In parallel, the 5880bis draft (draft-ietf-bfd-rfc5880bis-01, June 2026) keeps the original authentication types but adds the line "The use of MD5-based authentication is strongly discouraged." If you are choosing today, meticulous keyed SHA1 is the strongest of the widely implemented types.
Defence in depth around BFD
Authentication protects packet contents. It does not protect the CPU from a flood of packets that fail authentication. Add these around it:
- Filter UDP 3784, 3785, 4784, 6784 and 7784 at the control plane so only configured peers' addresses reach the BFD process.
- Keep GTSM on for single hop sessions, and set a minimum TTL for multihop sessions to the smallest value you actually expect.
- Rate limit BFD at the control plane policer so a flood cannot starve legitimate sessions, and size the limit from the packet rate you computed.
- Rotate keys with key chains that support overlapping lifetimes, and test a rotation in a lab before production.
- Alert on BFD state changes with diagnostic codes, not just routing adjacency changes, so a spoofed or flapping session is visible.
Step by step: BFD between two Linux routers with FRRouting
This lab uses two Linux hosts, R1 (10.0.12.1) and R2 (10.0.12.2), as virtual machines or containers (FRRouting publishes images at quay.io/frrouting/frr, including 10.7.1). Use FRRouting 10.7 or later for the authentication step: BFD key chains appear in the 10.7 documentation, not in 10.6 or earlier. Nothing here deletes data, but it resets routing sessions, so use lab hosts.
Step 1: install FRRouting from the project's Debian repository
On each host (Debian or Ubuntu), following the instructions at deb.frrouting.org:
curl -s https://deb.frrouting.org/frr/keys.gpg | sudo tee /usr/share/keyrings/frrouting.gpg > /dev/null
FRRVER="frr-10.7"
echo deb '[signed-by=/usr/share/keyrings/frrouting.gpg]' https://deb.frrouting.org/frr \
$(lsb_release -s -c) $FRRVER | sudo tee -a /etc/apt/sources.list.d/frr.list
sudo apt update && sudo apt install frr frr-pythontools
The repository page lists the FRRouting signing key fingerprints. Compare the key you downloaded with them before trusting it:
gpg --show-keys /usr/share/keyrings/frrouting.gpg
Step 2: enable the daemons
Edit /etc/frr/daemons on both hosts so the daemons you need start, then restart FRRouting:
sudo sed -i 's/^bgpd=no/bgpd=yes/; s/^ospfd=no/ospfd=yes/; s/^bfdd=no/bfdd=yes/' /etc/frr/daemons
sudo systemctl restart frr
sudo systemctl status frr --no-pager
Step 3: create a BFD profile and peer
On R1 (swap the addresses on R2):
configure terminal
bfd
profile lab
detect-multiplier 3
receive-interval 300
transmit-interval 300
log-session-changes
!
peer 10.0.12.2 interface eth0
profile lab
no shutdown
!
!
end
write memory
Check the session from either side:
show bfd peers brief
show bfd peer 10.0.12.2
Before the other side is configured you will see Status down and remote timers of 1000 ms, which is the one second slow start rule from RFC 5880. Once both sides are configured the state moves to up, and the local timers show 300 ms with a detection timeout of 900 ms.
Step 4: watch the packets
sudo tcpdump -ni eth0 -vv udp port 3784
You should see TTL 255, a source port from 49152 to 65535, and intervals in microseconds (300000).
Step 5: tie BGP to the session
On R1 (AS 65001) with R2 as AS 65002:
configure terminal
router bgp 65001
neighbor 10.0.12.2 remote-as 65002
neighbor 10.0.12.2 bfd profile lab
address-family ipv4 unicast
network 192.0.2.0/24
exit-address-family
!
end
neighbor ... bfd tells BGP to shut the session down as soon as BFD goes Down and to try again when it comes back. The strict form, neighbor 10.0.12.2 bfd strict, also stops BGP from establishing at all until BFD is Up, which avoids a BGP session that is up over a path BFD says is broken.
Step 6: tie OSPF to the session
configure terminal
interface eth0
ip ospf area 0
ip ospf bfd profile lab
!
router ospf
ospf router-id 10.0.12.1
!
end
FRRouting creates a BFD session per OSPF neighbour. Where internal BGP runs over OSPF, register OSPF only, as RFC 5882 advises; here BGP is external, so both is reasonable.
Step 7: monitor a static route
configure terminal
ip route 198.51.100.0/24 10.0.12.2 bfd profile lab
end
show bfd static route
The static route is installed only while the BFD session to 10.0.12.2 is Up.
Step 8: enable authentication (FRRouting 10.7 or later)
FRRouting attaches a key chain to a peer or profile. It supports clear text and keyed SHA1 (keyword hmac-sha-1), with keys of 1 to 16 bytes for clear text and up to 20 bytes for SHA1. Use SHA1 with meticulous mode, on both routers with the same key:
configure terminal
key chain bfd-lab
key 1
key-string Replace-With-20-Byte
cryptographic-algorithm hmac-sha-1
!
!
bfd
profile lab
authentication key-chain bfd-lab
authentication algorithm meticulous
!
!
end
show bfd peer 10.0.12.2 json
The JSON authentication object reports configured once the key chain is attached and enabled once a usable key is in effect. FRRouting documents that a session whose key chain holds no usable key stays down rather than coming up unauthenticated.
FRRouting merged a change titled "bfdd: make keyed SHA1 sequence number validation work" on 15 September 2026, after 10.7.0 shipped, so test authentication on the exact build you run.
Step 9: test failure detection
Simulate a link failure and time the reaction. In one terminal:
show bfd peers
In another, on R2, drop only BFD packets with nftables to show that BFD alone can take the routing down:
sudo nft add table inet bfdlab
sudo nft add chain inet bfdlab input '{ type filter hook input priority 0; }'
sudo nft add rule inet bfdlab input udp dport 3784 drop
Within the detection time R1 reports the session Down, BGP closes and OSPF drops the neighbour. An attacker who controls the link can do the same, which RFC 5880 says BFD cannot prevent. Remove the lab table afterwards:
sudo nft delete table inet bfdlab
Step 10: read the counters
show bfd peers counters
Control packet input and output should rise at roughly the negotiated rate. A session that is Up but shows input counts well below the expected rate is losing packets, and is a flapping risk even before it drops.
Comparison: BFD versus hello timers, LACP and link state
| Mechanism | Detection time (defaults or typical) | What a failure proves | Cost and caveats |
|---|---|---|---|
| Physical link down (carrier loss) | Near immediate on a direct link | The local port lost signal | Misses failures behind a media converter, an intermediate switch or a stuck forwarding engine |
| OSPF hellos (RFC 2328) | Sample hello 10 s; dead interval a multiple such as 4, so 40 s; RFC 5882 gives 2 s as the minimum | OSPF control packets stopped | One timer set per protocol and per interface |
| IS-IS hellos | RFC 5882 gives 1 s as the minimum | IS-IS control packets stopped | Same as OSPF |
| BGP keepalive and hold timer (RFC 4271) | Suggested hold time 90 s; minimum 3 s if non-zero | BGP TCP session stalled | Fast hold timers make BGP fragile |
| VRRP version 3 (RFC 9568) | About 3.6 s at the 1 s default interval and priority 100 | The active router stopped advertising | Only covers the first hop gateway |
| LACP (Linux bonding lacp_rate) | LACPDUs every 30 s (slow, the default) or 1 s (fast) | The partner's LACP stopped | Per member link; detection is a multiple of the interval |
| BFD asynchronous | 300 ms x 3 = 900 ms at FRRouting defaults; 50 ms x 3 = 150 ms with faster timers | Bidirectional forwarding path between the two systems | Timer and CPU cost; must be authenticated or TTL protected |
| Micro-BFD on LAG (RFC 7130) | Same as BFD, per member | A specific bundle member stopped forwarding | One session per member per address family |
| Seamless BFD (RFC 7880) | Initiator chosen | A reflector at the far end answered on this path | Needs discriminator provisioning; no handshake |
Keep protocol timers sensible as a fallback and let BFD carry the fast detection.
Where Safeguard fits
Safeguard does not configure routers, run BFD, inspect packets or analyse network firmware, and nothing in the lab above depends on it. The fit is with the software around the routing plane: the automation that renders FRRouting configurations, the controllers and exporters that collect BFD state, and the container images many teams use to run open source routing stacks in labs and on white box hardware. Those are built from open source packages and shipped as images. Safeguard scans repositories, container images and SBOM files (safeguard scan --dir ., --image <name>, --sbom <file>), shows which projects carry a given component and version, matches them against vulnerability data and applies policies and gates. That tells you which automation or image builds still carry a vulnerable library when a fix ships. Router operating systems from vendors are outside that scope, and their fixes still come from those vendors.
Common mistakes
- Configuring only one side and expecting detection. BFD sessions need both ends configured or an unsolicited BFD policy (RFC 9468). A one sided configuration stays Down, and a static route tied to it is withdrawn, because the router presumes the neighbour runs BFD.
- Reading your own multiplier as your own tolerance. The Detect Mult you send sets your peer's detection time, not yours. Compute both directions.
- Copying sub 100 ms timers onto a software control plane. Without hardware or a dedicated process, a CPU spike becomes a false failure and then a flap.
- Registering every protocol. IBGP over an IGP that already uses BFD gains little and adds expensive session resets.
- Enabling echo where reverse path filtering is on. Echo packets come back addressed to the sender and fail strict reverse path checks unless exempted.
- Using echo or expecting TTL protection on multihop sessions. Neither applies; use authentication and a minimum TTL.
- Turning on demand mode on both ends with no echo. Neither side transmits and neither runs a detection timer.
- Using simple password and calling it authenticated. The password is visible in any packet capture.
- Leaving BFD ports open to the world. Filter UDP 3784, 3785, 4784, 6784 and 7784 to known peers at the control plane.
FAQ
What is BFD in networking?
BFD, Bidirectional Forwarding Detection, is a lightweight UDP protocol defined in RFC 5880 (June 2010) that checks whether the forwarding path between two systems works, usually in well under a second. Routing protocols subscribe to a BFD session and treat a BFD Down as a neighbour failure.
What UDP ports does BFD use?
Single hop control packets use destination port 3784 and echo uses 3785 (RFC 5881). Multihop uses 4784 (RFC 5883). Micro-BFD on LAG member links uses 6784 (RFC 7130). Seamless BFD reflectors listen on 7784 (RFC 7881).
How is BFD detection time calculated?
In asynchronous mode the receiver multiplies the remote Detect Mult by the larger of its own Required Min RX Interval and the remote Desired Min TX Interval. With a 300 ms interval and a multiplier of 3, detection time is 900 ms. Each direction is computed separately.
What is a good BFD timer setting?
There is no single right value. A multiplier of 3 with 300 ms intervals, FRRouting's default, is a safe start for software implementations. Hardware based implementations can go much faster; RFC 7419's common interval set reaches down to 3.3 ms. Pick the slowest value that meets your convergence target, and measure CPU and false failures under load.
What is the difference between BFD asynchronous mode and demand mode?
In asynchronous mode both systems send periodic control packets and each declares failure when packets stop. In demand mode a system asks its peer to stop periodic packets and checks the path only through Poll Sequences, relying on some other mechanism, such as echo, for continuous verification.
Does BFD support authentication?
Yes. RFC 5880 defines simple password, keyed MD5, meticulous keyed MD5, keyed SHA1 and meticulous keyed SHA1. Experimental RFCs from June 2026 add a NULL type and two optimised ISAAC types. Meticulous keyed SHA1 is the strongest widely implemented option; the 5880bis draft strongly discourages MD5.
What is the difference between single hop and multihop BFD?
Single hop BFD runs between directly connected neighbours on port 3784 and relies on the TTL 255 check to reject spoofed packets. Multihop BFD runs across routed paths on port 4784, cannot use the echo function, and should use cryptographic authentication because the TTL check does not work.
Should I enable BFD for internal BGP?
Usually not if the IGP underneath already uses BFD. RFC 5882 notes that faster detection relayed to IBGP may be detrimental because BGP resets are expensive and the IGP will reroute on its own. RFC 5882 describes BFD as useful for external BGP and says to authenticate it.
Fix it without waiting for upstream
BFD itself is a protocol, but the systems that configure and observe it are ordinary software: configuration generators, telemetry collectors and the container images that package open source routing stacks are all built from open source dependencies. When one of those dependencies has a vulnerability, the fix path is the same as for any other code you build, so the habits below apply to network automation as much as to product code.
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.
3. Gold Registry: start from components that are already fixed
registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | The Gold scan GitHub Action in CI, plus Safeguard policies and gates |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch (early access) |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
The first demo is a real session with the Safeguard CLI. The assistant reads a finding and its advisory, asks before each command, upgrades a dependency, runs the tests and pushes nothing. The same flow applies when a library inside your router configuration generator or BFD telemetry exporter needs an upgrade.
Click through it at your own pace, or open it full screen.
The second demo sets up the Safeguard runner on your own machine, approves it with a device code and then scans from the terminal. Network automation repositories and lab images often live on internal hosts, and the runner lets you scan them from a machine you control.
Click through it at your own pace, or open it full screen.
The third demo connects Claude to the Safeguard MCP server with OAuth and lets you choose which tools Claude can use. Granting a narrow set of tools is the same habit as filtering BFD ports to known peers: allow only what each party needs.
Click through it at your own pace, or open it full screen.
Download the apps at safeguard.sh/download and read the CLI docs at docs.safeguard.sh/docs/cli.
Quick check
Router A sends Detect Mult 3 with a Desired Min TX Interval of 100 ms. Router B has a Required Min RX Interval of 250 ms. How long does B wait before declaring the session down?
750 ms. B multiplies A's Detect Mult (3) by the larger of its own Required Min RX Interval (250 ms) and A's Desired Min TX Interval (100 ms), so 3 x 250 ms.
Your eBGP peering runs between loopbacks two hops apart. Can you rely on the TTL 255 check and the echo function?
No. That is a multihop session on UDP port 4784. RFC 5883 says the echo function must not be used over multiple hops, and the TTL 255 check cannot work across routers that decrement TTL. Use cryptographic authentication, preferably meticulous keyed SHA1, plus a minimum TTL policy and control plane filtering.
Sources
- RFC 5880: Bidirectional Forwarding Detection (BFD) (June 2010)
- RFC 5881: BFD for IPv4 and IPv6 (Single Hop) (June 2010)
- RFC 5882: Generic Application of BFD (June 2010)
- RFC 5883: BFD for Multihop Paths (June 2010)
- RFC 5884: BFD for MPLS Label Switched Paths (June 2010)
- RFC 5885: BFD for the Pseudowire Virtual Circuit Connectivity Verification (June 2010)
- RFC 5082: The Generalized TTL Security Mechanism (GTSM) (October 2007)
- RFC 7130: BFD on Link Aggregation Group (LAG) Interfaces (February 2014)
- RFC 7419: Common Interval Support in BFD (December 2014)
- RFC 7726: Clarifying Procedures for Establishing BFD Sessions for MPLS LSPs (January 2016)
- RFC 7880: Seamless Bidirectional Forwarding Detection (S-BFD) (July 2016)
- RFC 7881: S-BFD for IPv4, IPv6 and MPLS (July 2016)
- RFC 8562: BFD for Multipoint Networks (April 2019)
- RFC 8563: BFD Multipoint Active Tails (April 2019)
- RFC 9127: YANG Data Model for BFD (October 2021)
- RFC 9384: A BGP Cease NOTIFICATION Subcode for BFD (March 2023)
- RFC 9468: Unsolicited BFD for Sessionless Applications (August 2023)
- RFC 9747: Unaffiliated BFD Echo (March 2025)
- RFC 9764: BFD Encapsulated in Large Packets (April 2025)
- RFC 9780: BFD for Multipoint Networks over Point-to-Multipoint MPLS Label Switched Paths (May 2025)
- RFC 9978: BFD Stability (June 2026, Experimental)
- RFC 9985: Optimizing BFD Authentication (June 2026, Experimental)
- RFC 9986: Meticulous Keyed ISAAC for BFD Optimized Authentication (June 2026, Experimental)
- draft-ietf-bfd-rfc5880bis-01: Bidirectional Forwarding Detection (BFD), work in progress
- IETF BFD working group: about
- IETF BFD working group: documents
- IANA: Bidirectional Forwarding Detection (BFD) Parameters
- RFC 4271: A Border Gateway Protocol 4 (BGP-4) (January 2006)
- RFC 2328: OSPF Version 2 (April 1998)
- RFC 9568: Virtual Router Redundancy Protocol (VRRP) Version 3 (April 2024)
- FRRouting documentation: BFD (latest)
- FRRouting documentation: BFD (stable 10.7)
- FRRouting Debian repository
- FRRouting releases on GitHub
- FRRouting pull request 23281: bfdd: make keyed SHA1 sequence number validation work
- FRRouting container images on Quay
- Linux kernel documentation: Linux Ethernet Bonding Driver HOWTO
Related reading: VRRP explained, OSPF explained and BGP explained.
Last reviewed: 24 October 2026. The IETF BFD working group is revising RFC 5880 to RFC 5884 and the June 2026 authentication RFCs are experimental; check the RFC Editor, the IANA registry and your implementation's documentation before relying on a specific behaviour.