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 ¶
const BFDPort = 3784
BFDPort is the well-known UDP port for BFD control packets (RFC 5880).
const DefaultDetectMult = 3
DefaultDetectMult is the number of missed packets before declaring the session down.
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 ¶
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"}, ) )
var BFDServerAddr = netip.MustParseAddr(apoxynet.ApoxyULAAddr)
BFDServerAddr is the well-known server-side BFD address (proxySourceAddr).
Functions ¶
func MarshalTo ¶
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 ¶
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 ¶
LastAlive returns when the last valid BFD packet was received from the server.
type OnAliveFunc ¶
OnAliveFunc is called on each valid BFD packet received from a client.
type OnDownFunc ¶
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).
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 ¶
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 ¶
RemovePeer tears down a client's BFD session. Called on connection close.
func (*Server) ResumeHeartbeat ¶
ResumeHeartbeat removes the blackhole for a connection, restoring normal BFD traffic.
func (*Server) Start ¶
Start binds UDP on [listenAddr]:3784 and runs the receive and transmit loops. Blocks until ctx is canceled.
func (*Server) SuppressHeartbeat ¶
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 ¶
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 ¶
BuildTx writes an outgoing BFD control packet into pkt for periodic transmission.
func (*Session) Expired ¶
Expired returns true if the detect timer has expired (no Rx within detectMult * txInterval).
func (*Session) ProcessRx ¶
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.