bfdl

package
v0.21.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 30, 2026 License: AGPL-3.0 Imports: 12 Imported by: 0

Documentation

Overview

Package bfdl implements a BFD-lite (RFC 5880 subset) protocol for application-level liveness detection between tunnel agents and the tunnelproxy server.

Index

Constants

View Source
const BFDPort = 3784

BFDPort is the well-known UDP port for BFD control packets (RFC 5880).

View Source
const DefaultDetectMult = 3

DefaultDetectMult is the number of missed packets before declaring the session down.

View Source
const DefaultTxInterval = 2 * time.Second

DefaultTxInterval is the interval between BFD control packet transmissions. With DetectMult=3, the detect time is 3 × 2s = 6s.

Variables

View Source
var (

	// BFDSessionsActive tracks the number of BFD sessions currently in each state.
	// Labels: "role" (server|client), "state" (Down|Init|Up).
	BFDSessionsActive = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Name: "tunnel_bfd_sessions_active",
			Help: "Number of active BFD sessions by role and state.",
		},
		[]string{"role", "state"},
	)

	// BFDPacketsTx counts BFD control packets transmitted.
	// Labels: "role" (server|client).
	BFDPacketsTx = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "tunnel_bfd_packets_tx_total",
			Help: "Total BFD control packets transmitted.",
		},
		[]string{"role"},
	)

	// BFDPacketsRx counts BFD control packets received.
	// Labels: "role" (server|client).
	BFDPacketsRx = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "tunnel_bfd_packets_rx_total",
			Help: "Total BFD control packets received.",
		},
		[]string{"role"},
	)

	// BFDStateTransitions counts BFD state transitions.
	// Labels: "role" (server|client), "from" (Down|Init|Up), "to" (Down|Init|Up).
	BFDStateTransitions = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "tunnel_bfd_state_transitions_total",
			Help: "Total BFD session state transitions.",
		},
		[]string{"role", "from", "to"},
	)

	// BFDDetectTimeouts counts detect-timer expirations (session went Down due to missed packets).
	// Labels: "role" (server|client).
	BFDDetectTimeouts = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "tunnel_bfd_detect_timeouts_total",
			Help: "Total BFD detect-timer expirations (session timed out).",
		},
		[]string{"role"},
	)

	// BFDPacketErrors counts BFD packet errors (unmarshal, write).
	// Labels: "role" (server|client), "direction" (tx|rx).
	BFDPacketErrors = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "tunnel_bfd_packet_errors_total",
			Help: "Total BFD packet errors.",
		},
		[]string{"role", "direction"},
	)

	// BFDHeartbeatsReceived counts valid BFD heartbeat packets received.
	// Labels: "role" (server|client).
	BFDHeartbeatsReceived = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "tunnel_bfd_heartbeats_received_total",
			Help: "Total valid BFD heartbeat packets received.",
		},
		[]string{"role"},
	)
)

BFDServerAddr is the well-known server-side BFD address (proxySourceAddr).

Functions

func Marshal

func Marshal(p *Packet) []byte

Marshal encodes a BFD control packet into a newly allocated 24-byte slice.

func MarshalTo

func MarshalTo(buf []byte, p *Packet)

MarshalTo encodes a BFD control packet into buf, which must be at least bfdPacketLen (24) bytes. Use with a stack-allocated [bfdPacketLen]byte to avoid heap allocation.

Wire format (RFC 5880 section 4.1):

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Vers |  Diag   |Sta|P|F|C|A|D|M|  Detect Mult  |    Length     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       My Discriminator                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Your Discriminator                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Desired Min TX Interval                    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                   Required Min RX Interval                    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                 Required Min Echo RX Interval                 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

func UnmarshalInto

func UnmarshalInto(p *Packet, b []byte) error

UnmarshalInto decodes a BFD control packet from wire format into p. Use with a stack-allocated Packet to avoid heap allocation.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client drives a BFD session from the tunnel agent side.

func NewClient

func NewClient(conn net.PacketConn, serverAddr netip.AddrPort) *Client

NewClient creates a new BFD client.

func (*Client) Down

func (c *Client) Down() <-chan struct{}

Down returns a channel that is closed when the BFD session transitions from Up to Down (detect timer expired). The channel is closed at most once.

func (*Client) LastAlive

func (c *Client) LastAlive() time.Time

LastAlive returns when the last valid BFD packet was received from the server.

func (*Client) Run

func (c *Client) Run(ctx context.Context) error

Run drives the BFD session: sends periodic control packets and processes responses. Blocks until ctx is canceled.

func (*Client) State

func (c *Client) State() State

State returns the current BFD session state.

type OnAliveFunc

type OnAliveFunc func(ctx context.Context, connID string)

OnAliveFunc is called on each valid BFD packet received from a client.

type OnDownFunc

type OnDownFunc func(ctx context.Context, connID string)

OnDownFunc is called when a BFD session transitions from Up to Down (detect timer expired — the client has not sent packets within the detection interval). This fires before the QUIC connection closes, giving the caller a chance to mark the endpoint as not-ready so that DNS-based service discovery stops routing to it immediately.

type OnStateChangeFunc

type OnStateChangeFunc func(old, new State)

OnStateChangeFunc is called when a BFD session transitions between states.

type Packet

type Packet struct {
	Version         uint8
	Diag            uint8
	State           State
	Poll            bool
	Final           bool
	DetectMult      uint8
	MyDiscr         uint32
	YourDiscr       uint32
	DesiredMinTx    uint32 // Microseconds.
	RequiredMinRx   uint32 // Microseconds.
	RequiredMinEcho uint32 // Microseconds, always 0 (no echo mode).
}

Packet represents a BFD control packet (RFC 5880 section 4.1).

func Unmarshal

func Unmarshal(b []byte) (*Packet, error)

Unmarshal decodes a BFD control packet from wire format into a newly allocated Packet.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server listens for BFD packets from all tunnel clients and manages per-client sessions. It runs on the kernel network stack, bound to [listenAddr]:3784.

The server both responds to incoming BFD packets (RX loop) and independently sends periodic BFD probes to each client (TX loop), so both directions of the data plane are exercised.

func NewServer

func NewServer(listenAddr netip.Addr, onAlive OnAliveFunc, onDown OnDownFunc) *Server

NewServer creates a new BFD server.

func (*Server) AddPeer

func (s *Server) AddPeer(addr netip.Addr, connID string)

AddPeer registers a client for BFD. Called when setupConn assigns an overlay address.

func (*Server) Drain

func (s *Server) Drain()

Drain transitions all active sessions to AdminDown and sends a burst of packets to notify clients. This causes clients to close their downCh sub-second instead of waiting for the detect timer (30s).

func (*Server) RemovePeer

func (s *Server) RemovePeer(addr netip.Addr)

RemovePeer tears down a client's BFD session. Called on connection close.

func (*Server) ResumeHeartbeat

func (s *Server) ResumeHeartbeat(connID string)

ResumeHeartbeat removes the blackhole for a connection, restoring normal BFD traffic.

func (*Server) Start

func (s *Server) Start(ctx context.Context) error

Start binds UDP on [listenAddr]:3784 and runs the receive and transmit loops. Blocks until ctx is canceled.

func (*Server) SuppressHeartbeat

func (s *Server) SuppressHeartbeat(connID string)

SuppressHeartbeat blackholes all BFD traffic for the given connection: the server stops sending probes, stops responding to the client's packets, and stops firing the onAlive callback. The client's detect timer will fire after detectMult * txInterval (default 30s).

type Session

type Session struct {
	// contains filtered or unexported fields
}

Session implements the BFD-lite state machine (RFC 5880 section 6.8.6, simplified). It supports three states: Down, Init, and Up.

func NewSession

func NewSession(localDiscr uint32, detectMult uint8, txInterval time.Duration) *Session

NewSession creates a new BFD session starting in Down state.

func (*Session) AdminDown

func (s *Session) AdminDown()

AdminDown transitions the session to AdminDown state. This signals the remote peer that this session is being intentionally shut down (e.g., during graceful drain). The remote peer should transition to Down.

func (*Session) BuildTx

func (s *Session) BuildTx(pkt *Packet)

BuildTx writes an outgoing BFD control packet into pkt for periodic transmission.

func (*Session) Expired

func (s *Session) Expired() bool

Expired returns true if the detect timer has expired (no Rx within detectMult * txInterval).

func (*Session) LastRx

func (s *Session) LastRx() time.Time

LastRx returns when the last valid BFD packet was received.

func (*Session) ProcessRx

func (s *Session) ProcessRx(rx, resp *Packet)

ProcessRx handles an incoming BFD packet and writes the response into resp.

Simplified RFC 5880 section 6.8.6 state transitions:

Local=Down  + Remote=Down  -> Init
Local=Down  + Remote=Init  -> Up
Local=Init  + Remote=Init  -> Up
Local=Init  + Remote=Up    -> Up
Local=Up    + Remote=Down  -> Down

func (*Session) SetOnStateChange

func (s *Session) SetOnStateChange(fn OnStateChangeFunc)

SetOnStateChange sets the callback for state transitions.

func (*Session) State

func (s *Session) State() State

State returns the current session state.

type State

type State uint8

State represents a BFD session state.

const (
	StateAdminDown State = 0
	StateDown      State = 1
	StateInit      State = 2
	StateUp        State = 3
)

func (State) String

func (s State) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL