BFD (Bidirectional Forwarding Detection) control packet encoding and decoding — mandatory section only (RFC 5880 section 4.1).

A BFD control packet opens with a fixed 24-byte mandatory section. RFC 5880 also defines an optional authentication section that follows it when the authenticationPresent flag is set, but this coder does not model it — see "Scope" below.

 0      7 8     15 16    23 24    31
+--------+--------+--------+--------+
|Ver/Diag| Flags  | DetMult| Length |
+--------+--------+--------+--------+
|                                   |
|          My Discriminator         |
+--------+--------+--------+--------+
|                                   |
|         Your Discriminator        |
+--------+--------+--------+--------+
|                                   |
|      Desired Min TX Interval      |
+--------+--------+--------+--------+
|                                   |
|      Required Min RX Interval     |
+--------+--------+--------+--------+
|                                   |
|   Required Min Echo RX Interval   |
+-----------------------------------+

The first byte packs a 3-bit version and 5-bit diagnostic code; the second byte packs the 2-bit session state and five single-bit flags (poll, final, controlPlaneIndependent, authenticationPresent, demand, multipoint — six flags plus 2-bit state is 8 bits). Both bytes are exposed as nested objects via bitStruct, keeping the on-wire layout faithful while preserving named-field access.

Scope (v0.0.1)

This package covers only the 24-byte mandatory section:

  • No authentication section — when flags.authenticationPresent is set, the caller is responsible for the bytes that follow the mandatory section; this coder neither reads nor writes them.
  • No checksum, no compression, no crypto — BFD control packets carry none of these, so there is nothing to add.
  • Interval fields (desiredMinTxInterval, requiredMinRxInterval, requiredMinEchoRxInterval) are surfaced as raw microsecond counts, not refined into Temporal/Duration values — that conversion is left to the caller.

Examples

Round-trip a BFD Up control packet

import { assertEquals } from "@std/assert";
import { bfdControlPacket, BFD_CONTROL_SIZE, BFD_STATE } from "@binstruct/bfd";

const coder = bfdControlPacket();
const packet = {
  versionDiagnostic: { version: 1, diagnostic: 0 },
  flags: {
    state: BFD_STATE.UP,
    poll: 0,
    final: 0,
    controlPlaneIndependent: 0,
    authenticationPresent: 0,
    demand: 0,
    multipoint: 0,
  },
  detectMultiplier: 3,
  length: BFD_CONTROL_SIZE,
  myDiscriminator: 0x11111111,
  yourDiscriminator: 0x22222222,
  desiredMinTxInterval: 1_000_000,
  requiredMinRxInterval: 1_000_000,
  requiredMinEchoRxInterval: 0,
};

const buffer = new Uint8Array(BFD_CONTROL_SIZE);
const written = coder.encode(packet, buffer);
const [decoded, read] = coder.decode(buffer);

assertEquals(written, BFD_CONTROL_SIZE);
assertEquals(read, BFD_CONTROL_SIZE);
assertEquals(decoded.flags.state, BFD_STATE.UP);
assertEquals(decoded.myDiscriminator, 0x11111111);