



= BFD (Bidirectional Forwarding Detection)

The purpose of `BFD` is to quickly detect if a link is up or down.

We are using it to determine if a `peer` application is up or down.
For example, when two servers are configured in primary / secondary
mode, they should be set up as BFD peers.  They can then detect
when the other one goes down.

The code is in FreeRADIUS because we want to know if the *application*
is running. It doesn't matter if the link is up, or if the host system
is running. If the FreeRADIUS daemon is down, then we want to know ASAP.

NOTE: See also `raddb/trigger.conf`.  There are BFD-specific triggers
which are executed when the link is started, goes up, down, or is
administratively down.



## server bfd  { ... }

The virtual server which manages BFD.


namespace::

The Bidirectional Forwarding Detection (BFD) protocol.



Common configuration for the BFD state machine.
For now, unused.




### listen { ... }


Only IP transport is supported for BFD.
There is no ethernet type for BFD.






ipaddr::

 IP address, or IPv6 address as with other



port:: Port as normal.



only_state_changes::

In general the server only needs to know if the BFD session state has changed.  Set
this value to "false" if you want every received and every sent packet to be
processed through this virtual server.



peer:: BFD peer

The peer definition is based on the `client` definition.  The standard client configuration items will work
here.


ipaddr:: address of the peer



port:: the peers port where we send packets



src_ipaddr:: Source address used when sending packets to this peer.

This source address should match a `listen` section above.  If not source address is given, then a
"wildcard" listener will be chosen.  i.e. A listener which has `ipaddr = *`

If the source IP address does not match any listener, then the peer will be ignored.



auth_type:: BFD Authentication method.

May be one of:

[options="header,autowidth"]
|===
| Option         | Description
| none           | no password, not recommended
| simple         | cleartext password in the packet, not recommended
| keyed-md5      | MD5 based, like  RADIUS style shared secret key
| met-keyed-md5  | similar to above
| keyed-sha1     | SHA1 based, like RADIUS style shared secret key
| met-keyed-sha1 | similar to above
|===

NOTE: The other side of the BFD connection has to have the same
kind of authentication set.



secret:: The secret key used for authentication.

If it starts with "0x", then it is treated as a hex string. This is recommended
for security.  The secrets should be no more than 16 octets long, and random.



min_transmit_interval:: Minimum time interval to transmit.



min_receive_interval:: Minimum time interval to receive.



max_timeouts:: Max number of timeouts before the session is declared dead.



demand:: BFD Demand mode.

allowed values: {no, yes}



## Packet Processing sections

Unlike other protocols, BFD does not follow a "request / reply" process.  Instead, there are two
independent streams of packets.  One where the peer sends us packets (`recv foo { ... }`), and the other
where we send packets to the peer (`send foo { ... }`).

Note that when running `send`, the packet contents *cannot be changed*.  The contents of the BFD packet
are defined by the protocol.  The `send` section is called only for informational purposes.



### Receive "Admin-Down" packets from the peer.



### Receive "Down" packets from the peer.



### Receive "Init" packets from the peer.



### Receive "Up" packets from the peer.



### Send "Admin-Down" packets to the peer.



### Send "Down" packets to the peer.



### Send "Init" packets to the peer.



### Send "Up" packets to the peer.




Sneak in more data after a BFD packet!



== Default Configuration

```
server main {
	namespace = bfd
	bfd {
	}
	listen {
		transport = udp
		udp {
			ipaddr = 192.0.2.1
			port = 3784
			only_state_changes = true
		}
	}
peer other {
	ipaddr = 192.0.2.2
	port = 3784
#	src_ipaddr = 192.0.2.1
	auth_type = none
#	secret = "hello"
	min_transmit_interval = 250ms
	min_receive_interval = 250ms
	max_timeouts = 3
	demand = no
}
recv Admin-Down {
	ok
}
recv Down {
	ok
}
recv Init {
	ok
}
recv Up {
	ok
}
send Admin-Down {
	ok
}
send Down {
	ok
}
send Init {
	ok
}
send Up {
#	octets more-data
	ok
#	&reply.Additional-Data := {
#		&more-data := 0xabcdef
#	}
}
}
```
