.. _bfd_doc:

BFD module
==========

Overview
--------

Bidirectional Forwarding Detection in VPP currently supports single-hop
UDP transport based on RFC 5880 and RFC 5881.

Usage
-----

General usage
~~~~~~~~~~~~~

BFD sessions are created using APIs only. The following CLIs are
implemented, which call the APIs to manipulate the BFD:

Show commands:
^^^^^^^^^^^^^^

   show bfd [keys|sessions|echo-source]

Show the existing keys, sessions or echo-source.

Key manipulation
^^^^^^^^^^^^^^^^

Create a new key or modify an existing key
''''''''''''''''''''''''''''''''''''''''''

   bfd key set conf-key-id type <keyed-sha1|meticulous-keyed-sha1>
   secret

Parameters:

-  conf-key-id - local configuration key ID, used to uniquely identify
   this key
-  type - type of the key
-  secret - shared secret (hex data)

Example:

   bfd key set conf-key-id 2368880803 type meticulous-keyed-sha1 secret
   69d685b0d990cdba46872706dc

Notes:

-  in-use key cannot be modified

Delete an existing key
''''''''''''''''''''''

   bfd key del conf-key-id

Parameters:

-  conf-key-id - local configuration key ID, used to uniquely identify
   this key

Example:

   bfd key del conf-key-id 2368880803

Notes:

-  in-use key cannot be deleted

Create a new (plain or authenticated) BFD session
'''''''''''''''''''''''''''''''''''''''''''''''''

   bfd udp session add interface local-addr

   .. raw:: html

      <address>

   peer-addr

   .. raw:: html

      <address>

   desired-min-tx required-min-rx detect-mult [ conf-key-id bfd-key-id ]

Parameters:

-  interface - interface to which this session is tied to
-  local-addr - local address (ipv4 or ipv6)
-  peer-addr - peer address (ipv4 or ipv6, must match local-addr family)
-  desired-min-tx - desired minimum tx interval (microseconds)
-  required-min-rx - required minimum rx interval (microseconds)
-  detect-mult - detect multiplier (must be non-zero)
-  conf-key-id - local configuration key ID
-  bfd-key-id - BFD key ID, as carried in BFD control frames

Example:

   bfd udp session add interface pg0 local-addr fd01:1::1 peer-addr
   fd01:1::2 desired-min-tx 100000 required-min-rx 100000 detect-mult 3
   conf-key-id 1029559112 bfd-key-id 13

Notes:

-  if conf-key-id and bfd-key-id are not specified, session is
   non-authenticated
-  desired-min-tx controls desired transmission rate of both control
   frames and echo packets

Modify BFD session
''''''''''''''''''

   bfd udp session mod interface local-addr

   .. raw:: html

      <address>

   peer-addr

   .. raw:: html

      <address>

   desired-min-tx required-min-rx detect-mult

Parameters:

-  interface - interface to which this session is tied to
-  local-addr - local address (ipv4 or ipv6)
-  peer-addr - peer address (ipv4 or ipv6, must match local-addr family)
-  desired-min-tx - desired minimum tx interval (microseconds)
-  required-min-rx - required minimum rx interval (microseconds)
-  detect-mult - detect multiplier (must be non-zero)

Example:

   bfd udp session mod interface pg0 local-addr 172.16.1.1 peer-addr
   172.16.1.2 desired-min-tx 300000 required-min-rx 200000 detect-mult
   12

Notes:

-  desired-min-tx controls desired transmission rate of both control
   frames and echo packets

Delete an existing BFD session
''''''''''''''''''''''''''''''

   bfd udp session del interface local-addr

   .. raw:: html

      <address>

   peer-addr

   .. raw:: html

      <address>

Parameters:

-  interface - interface to which this session is tied to
-  local-addr - local address (ipv4 or ipv6)
-  peer-addr - peer address (ipv4 or ipv6, must match local-addr family)

Example:

   bfd udp session del interface pg0 local-addr 172.16.1.1 peer-addr
   172.16.1.2

Set session admin-up or admin-down
''''''''''''''''''''''''''''''''''

   bfd udp session set-flags interface local-addr

   .. raw:: html

      <address>

   peer-addr

   .. raw:: html

      <address>

   admin <up|down>

Parameters:

-  interface - interface to which this session is tied to
-  local-addr - local address (ipv4 or ipv6)
-  peer-addr - peer address (ipv4 or ipv6, must match local-addr family)
-  admin - up/down based on desired action

Example:

   bfd udp session set-flags admin down interface pg0 local-addr
   172.16.1.1 peer-addr 172.16.1.2

Activate/change authentication for existing session
'''''''''''''''''''''''''''''''''''''''''''''''''''

   bfd udp session auth activate interface local-addr

   .. raw:: html

      <address>

   peer-addr

   .. raw:: html

      <address>

   conf-key-id bfd-key-id [ delayed <yes|no> ]

Parameters:

-  interface - interface to which this session is tied to
-  local-addr - local address (ipv4 or ipv6)
-  peer-addr - peer address (ipv4 or ipv6, must match local-addr family)
-  conf-key-id - local configuration key ID
-  bfd-key-id - BFD key ID, as carried in BFD control frames
-  delayed - is yes then this action is delayed until the peer performs
   the same action

Example:

   bfd udp session auth activate interface pg0 local-addr 172.16.1.1
   peer-addr 172.16.1.2 conf-key-id 540928695 bfd-key-id 239 delayed yes

Notes:

-  see `Delayed option <#delayed-option>`__ for more information

Deactivate authentication for existing session
''''''''''''''''''''''''''''''''''''''''''''''

   bfd udp session auth deactivate interface local-addr

   .. raw:: html

      <address>

   peer-addr

   .. raw:: html

      <address>

   [ delayed <yes|no> ]

Parameters:

-  interface - interface to which this session is tied to
-  local-addr - local address (ipv4 or ipv6)
-  peer-addr - peer address (ipv4 or ipv6, must match local-addr family)
-  delayed - is yes then this action is delayed until the peer performs
   the same action

Example:

   bfd udp session auth deactivate interface pg0 local-addr 172.16.1.1
   peer-addr 172.16.1.2

Notes:

-  see `Delayed option <#delayed-option>`__ for more information

Set echo-source interface
'''''''''''''''''''''''''

   bfd udp echo-source set interface

Parameters:

-  interface - interface used for getting source address for echo
   packets

Example:

   bfd udp echo-source set interface loop0

Delete echo-source interface
''''''''''''''''''''''''''''

   bfd udp echo-source del

Example:

   bfd udp echo-source del

Authentication
~~~~~~~~~~~~~~

BFD sessions should be authenticated for security purposes. SHA1 and
meticulous SHA1 authentication is supported by VPP. First,
authentication keys are configured in VPP and afterwards they can be
used by sessions.

There are two key IDs in the scope of BFD session:

-  configuration key ID is the internal unique key ID inside VPP and is
   never communicated to any peer, it serves only the purpose of
   identifying the key
-  BFD key ID is the key ID carried in BFD control frames and is used
   for verifying authentication

Turning auth on/off
^^^^^^^^^^^^^^^^^^^

Authentication can be turned on or off at any time. Care must be taken
however, to either synchronize the authentication manipulation with
peer’s actions to avoid the session going down.

Delayed option
''''''''''''''

Delayed option is useful for synchronizing authentication changes with a
peer. If it’s specified, then authentication change is not performed
immediately. In this case, VPP continues to transmit packets using the
old authentication method (unauthenticated or using old sha1 key). If a
packet is received, which does not pass the current authentication, then
VPP tries to authenticate it using the new method (which might be none,
if deactivating authentication) and if it passes, then the new
authentication method is put in use.

The recommended procedure for enabling/changing/disabling session
authentication is:

1. perform authentication change on vpp’s side with delayed option set
   to yes
2. perform authentication change on peer’s side (without delayed option)

Notes:

-  if both peers use delayed option at the same time, the change will
   never be carried out, since none of the peers will see any packet
   with the new authentication which could trigger the change
-  remote peer does not need to support or even be aware of this
   mechanism for it to work properly

Echo function
~~~~~~~~~~~~~

Echo function is used by VPP whenever a peer declares the willingness to
support it, echo-source is set and it contains a usable subnet (see
below). When echo function is switched on, the required min rx interval
advertised to peer is set to 1 second (or the configured value, if its
higher).

Echo source address
^^^^^^^^^^^^^^^^^^^

Because echo packets are only looped back (and not processed in any way)
by a peer, it’s necessary to set the source address in a way which
avoids packet drop due to spoofing protection by VPP. Per RFC, the
source address should not be in the subnet set on the interface over
which the echo packets are sent. Also, it must not be any VPP-local
address, otherwise the packet gets dropped on receipt by VPP. The
solution is to create a loopback interface with a (private) IPv4/IPv6
subnet assigned as echo-source. The BFD then picks an unused address
from the subnet by flipping the last bit and uses that as source address
in the echo packets, thus meeting RFC recommendation while avoiding
spoofing protection.

Example: if 10.10.10.3/31 is the subnet, then 10.10.10.2 will be used as
source address in (IPv4) echo packets

Demand mode
~~~~~~~~~~~

Demand mode is respected by VPP, but not used locally. The only scenario
when demand mode could make sense currently is when echo is active.
Because echo packets are inherently insecure against an adversary
looping them back a poll sequence would be required for slow periodic
connectivity verification anyway. It’s more efficient to just ask the
remote peer to send slow periodic control frames without VPP initiating
periodic poll sequences.

Admin-down
~~~~~~~~~~

Session may be put admin-down at any time. This immediately causes the
state to be changed to AdminDown and remain so unless the session is put
admin-up.

BFD implementation notes
------------------------

Because BFD can work over different transport layers, the BFD code is
separated into core BFD functionality - main module implemented in
bfd_main.c and transport-specific code implemented in bfd_udp.c.

Main module
~~~~~~~~~~~

Main module is responsible for handling all the BFD functionality
defined in RFC 5880.

Internal API
^^^^^^^^^^^^

Internal APIs defined in bfd_main.h are called from transport-specific
code to create/modify/delete

Packet receipt
^^^^^^^^^^^^^^

When a packet is received by the transport layer, it is forwarded to
main module (to main thread) via an RPC call. At this point, the
authentication has been verified, so the packet is consumed, session
parameters are updated accordingly and state change (if applicable).
Based on these, the timeouts are adjusted if required and an event is
sent to the process node to wake up and recalculate sleep time.

Packet transmit
^^^^^^^^^^^^^^^

Main module allocates a vlib_buffer_t, creates the required BFD frame
(control or echo in it), then calls the transport layer to add the
transport layer. Then a frame containing the buffer to the appropriate
node is created and enqueued.

Process node
^^^^^^^^^^^^

Main module implements one process node which is a simple loop. The
process node gets next timeout from the timer wheel, sleeps until the
timeout expires and then calls a timeout routine which drives the state
machine for each session which timed out. The sleep is interrupted
externally via vlib event, when a session is added or modified in a way
which might require timer wheel manipulation. In this case the caller
inserts the necessary timeout to timer wheel and then signals the
process node to wake up early, handle possible timeouts and recalculate
the sleep time again.

State machine
^^^^^^^^^^^^^

Default state of BFD session when created is Down, per RFC 5880. State
changes to Init, Up or Down based on events like received state from
peer and timeouts. The session state can be set AdminDown using a binary
API, which prevents it from going to any other state, until this
limitation is removed. This state is advertised to peers in slow
periodic control frames.

For each session, the following timeouts are maintained:

1. tx timeout - used for sending out control frames
2. rx timeout - used for detecting session timeout
3. echo tx timeout - used for sending out echo frames
4. echo rx timeout - used for detecting session timeout based on echo

These timeouts are maintained in cpu clocks and recalculated when
appropriate (e.g. rx timeout is bumped when a packet is received,
keeping the session alive). Only the earliest timeout is inserted into
the timer wheel at a time and timer wheel events are never deleted,
rather spurious events are ignored. This allows efficient operation,
like not inserting events into timing wheel for each packet received or
ignoring left-over events in case a bfd session gets removed and a new
one is recreated with the same session index.

Authentication keys management
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Authentication keys are managed internally in a pool, with each key
tracking it’s use count. The removal/modification is only allowed if the
key is not in use.

UDP module
~~~~~~~~~~

UDP module is responsible for:

1. public APIs/CLIs to configure BFD over UDP.
2. support code called by main module to encapsulate/decapsulate BFD
   packets

This module implements two graph nodes - for consuming ipv4 and ipv6
packets target at BFD ports 3874 and 3875.

.. _packet-receipt-1:

Packet receipt
^^^^^^^^^^^^^^

BFD packet receipt receipt starts in the bfd udp graph nodes. Since the
code needs to verify IP/UDP header data, it relies on ip4-local (and
ip6-local) nodes to store pointers to the appropriate headers. First,
your discriminator is extracted from BFD packet and used to lookup the
existing session. In case it’s zero, the pair of IP addresses and
sw_if_index is used to lookup session. Then, main module is called to
verify the authentication, if present. Afterwards a check is made if the
IP/UDP headers are correct. If yes, then an RPC call is made to the main
thread to consume the packet and take action upon it.

Packet transmission
^^^^^^^^^^^^^^^^^^^

When process node decides that there is a need to transmit the packet,
it creates a buffer, fills the BFD frame data in and calls the UDP
module to add the transport layer. This is a simple operation for the
control frames consisting of just adding UDP/IP headers based on session
data. For echo frames, an additional step, looking at the echo-source
interface and picking and address is performed and if this fails, then
the packet cannot be transmitted and an error is returned to main
thread.
