Documentation
¶
Overview ¶
Package lsdb implements the per-level IS-IS link-state database store.
Index ¶
- Constants
- func NonLinkLocalV6Addrs(in []netip.Addr) []netip.Addr
- type AdjacencyInfo
- type CircuitID
- type CircuitsFunc
- type Entry
- func (e *Entry) Checksum() uint16
- func (e *Entry) Decode() (packet.LSP, error)
- func (e *Entry) IsOverloaded() bool
- func (e *Entry) IsOwn() bool
- func (e *Entry) IsPurged() bool
- func (e *Entry) IsReceivedPurge() bool
- func (e *Entry) LSPID() types.LSPID
- func (e *Entry) Lifetime() types.RemainingLifetime
- func (e *Entry) Raw() []byte
- func (e *Entry) Sequence() types.SequenceNumber
- type FloodCircuit
- type Flooder
- func (f *Flooder) FloodTick()
- func (f *Flooder) InitialCSNP(c FloodCircuit, level Level, srcID types.SourceID)
- func (f *Flooder) PendingCount(cid CircuitID, level Level) int
- func (f *Flooder) ReceiveCSNP(cid CircuitID, csnp *packet.CSNP)
- func (f *Flooder) ReceiveLSP(cid CircuitID, p2p bool, lsp *packet.LSP, raw []byte) ReceiveResult
- func (f *Flooder) ReceivePSNP(cid CircuitID, psnp *packet.PSNP)
- func (f *Flooder) RecordBadChecksum(pt packet.PDUType)
- func (f *Flooder) SendCSNP(c FloodCircuit, level Level, srcID types.SourceID)
- func (f *Flooder) SendPSNP(c FloodCircuit, level Level, srcID types.SourceID)
- func (f *Flooder) SetMetrics(reg metrics.Registry)
- func (f *Flooder) SetSigner(sign func(pdu []byte) []byte)
- func (f *Flooder) SetSystemID(sys types.SystemID)
- type Freshness
- type LSDB
- func (d *LSDB) ClearCircuit(cid CircuitID)
- func (d *LSDB) ClearSRM(level Level, id types.LSPID, cid CircuitID)
- func (d *LSDB) ClearSSN(level Level, id types.LSPID, cid CircuitID)
- func (d *LSDB) Delete(level Level, id types.LSPID) bool
- func (d *LSDB) Insert(level Level, lsp *packet.LSP, raw []byte)
- func (d *LSDB) LSPEntries(level Level) []packet.LSPEntry
- func (d *LSDB) LSPIDs(level Level) []types.LSPID
- func (d *LSDB) Len(level Level) int
- func (d *LSDB) Lookup(level Level, id types.LSPID) *Entry
- func (d *LSDB) Receive(level Level, lsp *packet.LSP, raw []byte, own bool) ReceiveResult
- func (d *LSDB) SRM(level Level, id types.LSPID, cid CircuitID) bool
- func (d *LSDB) SSN(level Level, id types.LSPID, cid CircuitID) bool
- func (d *LSDB) SetMetrics(reg metrics.Registry)
- func (d *LSDB) SetSRM(level Level, id types.LSPID, cid CircuitID)
- func (d *LSDB) SetSSN(level Level, id types.LSPID, cid CircuitID)
- func (d *LSDB) Snapshot(level Level) []LSPSnapshot
- func (d *LSDB) Tick() TickResult
- type LSPSnapshot
- type Level
- type LevelState
- type NodeInfo
- type OriginateResult
- type Originator
- func (o *Originator) Originate(level Level, node NodeInfo, state LevelState) OriginateResult
- func (o *Originator) OriginatePseudonode(level Level, info PseudonodeInfo) OriginateResult
- func (o *Originator) PurgePseudonode(level Level, sys types.SystemID, pnid uint8) []types.LSPID
- func (o *Originator) SetSigner(sign func(pdu []byte) []byte)
- type PrefixInfo
- type PrefixInfoV6
- type PseudonodeInfo
- type PurgeEvent
- type ReceiveResult
- type TickResult
- type TxFunc
Constants ¶
const ( // DefaultMaxAge is the default LSP Remaining Lifetime at origination // (ISO/IEC 10589 clause 7.3.16.1: MaxAge, default 1200 s). DefaultMaxAge = 1200 * time.Second // DefaultRefreshInterval is the default age at which an own LSP is refreshed // before MaxAge (clause 7.3.16.1, typically 900 s). The originator bumps the // sequence and resets the lifetime so the LSP never ages out in the network. DefaultRefreshInterval = 900 * time.Second // ZeroAgeLifetime is the grace period a purged LSP (Remaining Lifetime 0) is // kept in the database after the purge is flooded, before garbage collection // (ISO/IEC 10589 clause 7.3.16.4 / 7.3.17). It is also part of the // post-wraparound suspension window. RFC default 60 s. ZeroAgeLifetime = 60 * time.Second )
Aging timer constants (ISO/IEC 10589 clause 7.3). The MaxAge / refresh values are operator-configurable (the lsp-lifetime / lsp-refresh-interval YANG leaves resolved by isis-4); these are the RFC defaults the engine passes when no override is set. ZeroAgeLifetime is fixed.
const DefaultMaxLSPSize = 1492
DefaultMaxLSPSize is the default maximum LSP PDU size used for fragmentation when no circuit MTU is known (ISO/IEC 10589: typically 1492 for Ethernet, spec A-5). The originator splits its TLVs so no fragment exceeds this.
const MaxLSPsPerLevel = 16384
MaxLSPsPerLevel caps the number of LSPs stored per level so a flood of distinct LSP IDs from a misbehaving or hostile peer cannot exhaust memory (security review: resource exhaustion). A real area never approaches this; an own LSP set is at most 256 fragments. A received LSP for a brand-new LSP ID is rejected once the level is full (an existing entry is always updatable so a refresh/purge of a known LSP is never dropped).
Variables ¶
This section is empty.
Functions ¶
func NonLinkLocalV6Addrs ¶
NonLinkLocalV6Addrs returns the subset of in that are non-link-local IPv6 addresses, for the LSP TLV 232 (RFC 5308 sec 3: an LSP carries only non-link-local addresses). Invalid or non-IPv6 addresses are dropped. The link-local addresses are advertised separately in the IIH TLV 232 by the circuit layer (the Hello scope).
Types ¶
type AdjacencyInfo ¶
type AdjacencyInfo struct {
// Neighbor is the neighbor's Source ID (System ID + pseudonode). For a P2P
// or LAN router adjacency the pseudonode is 0; the DIS pseudonode (isis-8)
// uses a non-zero pseudonode.
Neighbor types.SourceID
// Metric is the wide IS-reachability metric to the neighbor (24-bit,
// RFC 5305 sec 3).
Metric types.Metric
}
AdjacencyInfo is one IS neighbor the node advertises in TLV 22 (Extended IS Reachability). The engine fills it from the adjacency tables (isis-5) for the circuits forming the level being originated.
type CircuitID ¶
type CircuitID uint16
CircuitID is a stable, small per-circuit identifier the LSDB uses to index the SRM/SSN flag sets (spec A-3: one bit per circuit). The engine assigns one ID per open circuit; the flooding spec (isis-7) sets and clears the flags by this ID. It is deliberately not the kernel ifindex (which is large and sparse): the engine maps interface name -> CircuitID so the flag sets stay compact.
type CircuitsFunc ¶
type CircuitsFunc func() []FloodCircuit
CircuitsFunc returns the currently-open circuits the flooder may transmit on. The engine wires it to derive the set from the running InterfaceConfig under its own lock, so the Flooder always sees the live circuit set without holding engine state itself.
type Entry ¶
type Entry struct {
// contains filtered or unexported fields
}
Entry is one LSP in the database: the verbatim PDU bytes plus the parsed freshness metadata and the per-circuit flooding flags. It is owned by the LSDB (guarded by the LSDB mutex); callers receive copies of the metadata via Snapshot and never a live pointer.
func (*Entry) Decode ¶
Decode parses the stored raw bytes into the typed LSP on demand (lazy parse, ai/rules/buffer-first.md). SPF (isis-9) and `show isis database detail` (isis-13) call this to read TLVs; the LSDB never holds the parsed form. The returned LSP's TLV value slices alias the entry's raw bytes, which are stable for the entry's lifetime, so the caller need not copy unless it outlives the entry. A malformed stored PDU (which the codec validated before store) returns the codec error.
func (*Entry) IsOverloaded ¶
IsOverloaded reports whether the LSP-database-overload (OL) bit is set in the type block (RFC 3787 sec 4): the originator is reachable but must not be used as a transit router (enforced in isis-9 SPF).
func (*Entry) IsPurged ¶
IsPurged reports whether the entry is in the zero-age purge state (Remaining Lifetime 0, retained for the grace period).
func (*Entry) IsReceivedPurge ¶
IsReceivedPurge reports whether the entry's purge arrived on the wire (a received purge, ISO/IEC 10589 clause 7.3.16) rather than from local expiry. A received purge is re-flooded and retained for the grace period; a local expiry is only garbage-collected. The engine reads this to decide the distinct flooding behavior (spec AC-9, R-4).
func (*Entry) Lifetime ¶
func (e *Entry) Lifetime() types.RemainingLifetime
Lifetime returns the entry's current Remaining Lifetime in seconds.
func (*Entry) Raw ¶
Raw returns the verbatim PDU bytes for re-flood (isis-7). The slice is the entry's owned copy; callers MUST NOT mutate it (the flooding path only reads and frames it). It is returned directly (not copied) because the flooding hot path sends it unchanged; the LSDB never mutates raw in place after store.
func (*Entry) Sequence ¶
func (e *Entry) Sequence() types.SequenceNumber
Sequence returns the entry's LSP Sequence Number.
type FloodCircuit ¶
type FloodCircuit struct {
Name string
ID CircuitID
P2P bool
Passive bool
FormsL1 bool
FormsL2 bool
}
FloodCircuit is the engine's view of one open circuit, as the flooding/SNP layer needs it. The engine builds it from the running InterfaceConfig so the Flooder never imports the circuit or transport packages. ID is the LSDB CircuitID the SRM/SSN flags are keyed by; Name is the transport circuit key for tx; P2P selects the initial-CSNP-at-Up behavior (SRM is cleared on acknowledgement on both P2P and LAN, so P2P no longer picks a distinct clear policy); Passive circuits are skipped on the flood timer (ISO/IEC 10589: a passive circuit forms no adjacency and floods nothing); FormsL1/FormsL2 gate per-level eligibility (an L1L2 circuit forms both).
type Flooder ¶
type Flooder struct {
// contains filtered or unexported fields
}
Flooder runs the reliable-flooding algorithm over an LSDB. It is constructed by the engine with the LSDB, the transmit hook, and the circuit-set provider. The SNP (CSNP/PSNP) build/receive logic and the per-circuit pending-request set live in snp.go on the same type.
func NewFlooder ¶
func NewFlooder(db *LSDB, tx TxFunc, circuits CircuitsFunc) *Flooder
NewFlooder constructs a Flooder over db. tx and circuits are the engine hooks; either may be nil in a unit test that drives only the receive/flag path (the transmit then no-ops). Metrics start as no-ops until SetMetrics wires a real registry.
func (*Flooder) FloodTick ¶
func (f *Flooder) FloodTick()
FloodTick drains the SRM flags once: for every open, non-passive circuit and every LSP at each level the circuit forms, if SRM is set on that circuit the stored raw LSP bytes are (re-)transmitted (ISO/IEC 10589 clause 7.3.14: send the LSP verbatim, preserving unknown TLVs). On BOTH point-to-point and broadcast circuits SRM is LEFT SET after a successful send and is cleared only when the flood is ACKNOWLEDGED: a PSNP at our sequence (ReceivePSNP), an equal CSNP entry (ReceiveCSNP), or -- on P2P -- the reciprocal PSNP the neighbor emits after it stores our LSP. Leaving SRM set is what makes flooding reliable: a first transmission lost or arriving before the neighbor can store it is retried on the next tick instead of being silently dropped (ISO/IEC 10589 clause 7.3.15.1: the SRM flag is cleared on acknowledgement, with periodic retransmission while it remains set). Each such unacknowledged resend bumps ze_isis_srm_resends_total so a storm is observable (AC-5, AC-6, R-2).
The transmit re-uses the entry's owned raw slice without copying (buffer-first, the hot path makes no per-LSP allocation); raw is immutable after store.
func (*Flooder) InitialCSNP ¶
func (f *Flooder) InitialCSNP(c FloodCircuit, level Level, srcID types.SourceID)
InitialCSNP sends the one-shot CSNP a point-to-point circuit emits the moment its adjacency reaches Up, to synchronize the two LSDBs fast (ISO/IEC 10589 clause 7.3.15.2 / spec AC-11, R-5). The engine calls it from the P2P adjacency Up hook. A non-P2P circuit is ignored (LAN periodic CSNP is DIS-sourced, isis-8). srcID is the node's own Source ID.
func (*Flooder) PendingCount ¶
PendingCount returns the number of pending-request entries for circuit cid at level (exposed for tests and diagnostics).
func (*Flooder) ReceiveCSNP ¶
ReceiveCSNP processes a received CSNP on circuit cid and reconciles its TLV 9 entries against our LSDB (ISO/IEC 10589 clause 7.3.15.2). For each listed LSP:
- We hold it at the SAME sequence (and checksum): the neighbor confirms it has our copy, so clear SRM on this circuit (an implicit ack) and clear any matching pending-request entry (AC-13 equal case).
- The neighbor is NEWER (higher seq, or equal seq with a purge it advertises and we do not): we either hold an older copy or none. Either way the authoritative request is a per-circuit pending-request entry so a PSNP can request it (AC-7, AC-15). When we DO hold a (stale) entry we also set SSN on it (a held entry can carry the flag); when we hold nothing there is no entry to flag, which is exactly why the pending-request set exists.
- We are NEWER (we hold a higher seq than listed): set SRM on this circuit to send our copy (AC-8).
An LSP we hold that is ABSENT from a CSNP whose range covers it is handled by reconcileCSNPRange below (set SRM to send it). The level comes from the PDU type.
func (*Flooder) ReceiveLSP ¶
ReceiveLSP applies a received LSP PDU arriving on circuit cid and drives the SRM/SSN flags per ISO/IEC 10589 clause 7.3.14-16. raw is the verbatim PDU (the engine passes the transport's owned copy); lsp is the codec-parsed header (isis-2). The level is taken from the PDU type. The freshness decision is made by isis-6 (LSDB.Receive); this method maps the outcome to flags:
- Newer (stored): set SRM on every OTHER eligible circuit (flood onward) and SSN on the incoming circuit (acknowledge); clear any pending-request entry the arriving LSP satisfies (clause 7.3.16, AC-1, AC-15, AC-16 purge case).
- Equal (duplicate): no replace, no SRM; on a LAN set SSN on the incoming circuit so a PSNP acknowledges it (AC-3). isis-6 refreshed the lifetime.
- Older: isis-6 kept our copy. Two sub-cases distinguished by sequence:
- incoming seq EQUALS our held seq (a differing-checksum/ambiguous copy): set SSN on the incoming circuit so a PSNP requests the correct copy (AC-2, clause 7.3.16.1 -- the held copy may be corrupt).
- incoming seq is strictly LOWER: set SRM on the incoming circuit to send our newer copy back to the sender (AC-4).
"do not re-flood on the incoming circuit" (ISO/IEC 10589 clause 7.3.14) is enforced by skipping cid when arming SRM-on-others.
It returns the LSDB freshness/store outcome so the engine wiring can decide whether the receive actually changed the database (Stored => Newer) and only then emit an LSP-change event / re-run SPF; an Older or Equal LSP is not a topology change (ISO/IEC 10589 clause 7.3.15: only a newer LSP supersedes).
func (*Flooder) ReceivePSNP ¶
ReceivePSNP processes a received PSNP on circuit cid (ISO/IEC 10589 clause 7.3.15.3). For each TLV 9 entry:
- The neighbor acknowledges our LSP at OUR sequence (or newer): clear SRM on this circuit -- the flood is confirmed delivered (AC-9).
- The neighbor lists an LSP it does NOT have, or has an OLDER copy of (its entry sequence is lower than ours, including a zero-sequence "please send" request): set SRM on this circuit to supply it (AC-10).
func (*Flooder) RecordBadChecksum ¶
RecordBadChecksum bumps ze_isis_lsps_dropped_total{level,reason="bad-checksum"} for an LSP the engine dropped on receive because its Fletcher checksum failed (ISO/IEC 10589 clause 7.3.14.2). The verification (and the drop) happen in the engine receive wiring BEFORE the LSP reaches ReceiveLSP/LSDB.Receive, so the LSDB is never touched; this only surfaces the drop on the flooding-owned counter (the dropped series belongs to isis-7). pt selects the level label.
func (*Flooder) SendCSNP ¶
func (f *Flooder) SendCSNP(c FloodCircuit, level Level, srcID types.SourceID)
SendCSNP builds and transmits the CSNP(s) for level on circuit c, sourced from srcID. Used by the periodic CSNP cadence and the P2P initial CSNP (AC-11). Increments ze_isis_csnp_sent_total per PDU sent.
func (*Flooder) SendPSNP ¶
func (f *Flooder) SendPSNP(c FloodCircuit, level Level, srcID types.SourceID)
SendPSNP builds and transmits the PSNP(s) for level on circuit c (ack + request list), sourced from srcID. Increments ze_isis_psnp_sent_total per PDU sent. Used by the periodic PSNP cadence; clears SSN for the acknowledged LSPs.
func (*Flooder) SetMetrics ¶
SetMetrics registers the flooding/SNP Prometheus series on reg. This spec OWNS and registers exactly these rows from the umbrella canonical Metrics table (owner isis-7); isis-13 only scrapes them. Other ze_isis_* series belong to their owning specs.
func (*Flooder) SetSigner ¶
SetSigner installs the per-level CSNP/PSNP signer (spec-isis-10). The signer takes a fully-encoded SNP and returns the signed bytes (TLV 10 inserted first; SNPs carry no Fletcher checksum). nil disables signing. Safe to call before any circuit opens; read under signMu on the build path.
func (*Flooder) SetSystemID ¶
SetSystemID records the node's own System ID so a received copy of our own LSP is recognized as own (LSDB.Receive own flag). Safe to call before circuits open.
type Freshness ¶
type Freshness uint8
Freshness is the result of comparing a received LSP against the stored entry (ISO/IEC 10589 clause 7.3.15/7.3.16): the received copy is Newer, Equal, or Older than what the database holds.
const ( // Older means the received LSP is staler than the stored entry; the database // keeps its copy and (isis-7) sends the newer copy back on the receiving // circuit (SRM on that circuit). Older Freshness = iota // Equal means the received LSP matches the stored entry; the database updates // the Remaining Lifetime and (isis-7) acknowledges via PSNP (SSN on the // receiving circuit). Equal // Newer means the received LSP supersedes the stored entry; it replaces the // stored copy and (isis-7) floods it on all other circuits (SRM). Newer )
Freshness outcomes.
type LSDB ¶
type LSDB struct {
// contains filtered or unexported fields
}
LSDB is the two-level Link-State Database.
func New ¶
New constructs an empty LSDB. now may be nil (defaults to time.Now). Metrics start as no-ops until SetMetrics wires a real registry.
func (*LSDB) ClearCircuit ¶
ClearCircuit drops circuit cid from every LSP's SRM/SSN sets at both levels. The engine calls it when a circuit closes so a stale circuit index is never left flagged (spec: flags cleared on entry removal / circuit removal).
func (*LSDB) ClearSRM ¶
ClearSRM clears the SRM flag for (level, id) on circuit cid (isis-7 clears it once the LSP has been sent and, on a P2P link, acknowledged).
func (*LSDB) Delete ¶
Delete removes the entry for id at level, returning whether it existed. Used by the aging path after the purge grace period and by the engine on shutdown.
func (*LSDB) Insert ¶
Insert stores an originated own LSP (the origination path, origination.go). Unlike Receive it performs no freshness compare: the originator is authoritative for its own LSP IDs and assigns monotonically increasing sequence numbers. raw is copied into an entry-owned slice. An originated Remaining-Lifetime-0 LSP is a locally-generated purge (NOT a receivedPurge): it is re-flooded and retained for the grace period, then garbage-collected.
func (*LSDB) LSPEntries ¶
LSPEntries returns one packet.LSPEntry (TLV 9 record) per LSP at level, in LSP-ID (CSNP range) order, built directly from the typed entry metadata under a single read lock. It is the source for CSNP/PSNP build (isis-7): no string round-trip (the old Snapshot-then-ParseLSPID path stringified every LSP ID and reparsed it), and one lock acquisition for the whole set rather than a Lookup per ID. LSPEntry is a small fixed value with no pointer into the store, so the returned slice never exposes a live entry (ISO/IEC 10589 clause 9.10/9.14).
func (*LSDB) LSPIDs ¶
LSPIDs returns the LSP IDs stored at level, sorted in LSP-ID (CSNP range) order. It is the read-only enumerator the flooding spec (isis-7) uses to drain SRM flags and to reconcile a CSNP range without holding a live entry pointer: the caller then uses SRM/SSN/Lookup by ID. Sorting makes the flood/CSNP order deterministic (ISO/IEC 10589 clause 9.10 CSNP ordering). It takes the read lock and returns a COPY of the cached sorted-ID slice (idsSorted), so it never sorts on the hot path (the sort happens once per key-set change, under the write lock), never blocks the single writer for long, and never exposes the store or the live cache slice (the caller may iterate while a later writer rebuilds it).
func (*LSDB) Lookup ¶
Lookup returns the stored entry for id at level, or nil. The returned pointer is the live entry; callers that only read metadata are fine, but MUST NOT mutate it outside the LSDB lock. (isis-7 flooding uses the flag methods, which lock internally; SPF uses Snapshot/Decode.)
func (*LSDB) Receive ¶
Receive applies a received, codec-validated LSP to the database (the data path the flooding spec, isis-7, calls after the wire codec has parsed the header and validated lengths). It compares the incoming LSP against any stored entry (clause 7.3.16):
- Newer: replace the stored copy (a single OWNED copy of raw is taken so the transport may reuse its receive buffer) and report Stored.
- Equal: refresh the stored Remaining Lifetime to the received value and acknowledge (no re-store of bytes).
- Older: keep the stored copy untouched.
A received LSP with Remaining Lifetime 0 is a purge: it is stored (when newer) and marked receivedPurge so the aging path re-floods and retains it for the grace period rather than garbage-collecting it (clause 7.3.16/17, spec AC-9). own marks an LSP whose System ID is ours (the originator); the engine passes this so a received copy of our own LSP is recognized.
raw is the verbatim PDU; Receive copies it (never aliases the caller's buffer).
func (*LSDB) SetMetrics ¶
SetMetrics registers the LSDB-owned Prometheus series on reg. This spec OWNS and registers exactly these rows from the umbrella canonical Metrics table (owner isis-6); other ze_isis_* series are registered by their owning specs.
func (*LSDB) SetSRM ¶
SetSRM arms the Send-Routeing-Message flag for (level, id) on circuit cid: the LSP must be (re-)sent on that circuit. No-op when the LSP is absent. Arming (or re-arming) SRM clears the circuit's "already sent since armed" marker so the NEXT transmit counts as a first send, not a resend (ISO/IEC 10589 clause 7.3.15.1: the periodic-retransmission counter tracks unacknowledged re-sends).
func (*LSDB) SetSSN ¶
SetSSN arms the Send-Sequence-Number flag for (level, id) on circuit cid: a PSNP acknowledging/requesting the LSP must be sent on that circuit.
func (*LSDB) Snapshot ¶
func (d *LSDB) Snapshot(level Level) []LSPSnapshot
Snapshot returns a stable, sorted copy of the LSPs at level for the CLI. It takes the read lock so it never exposes a live entry pointer across the boundary and never blocks the single writer for long. Rows are ordered by LSP ID (the CSNP order), so the CLI output is deterministic.
func (*LSDB) Tick ¶
func (d *LSDB) Tick() TickResult
Tick advances the database by one second (ISO/IEC 10589 clause 7.3.16.4): it decrements every entry's Remaining Lifetime, transitions an entry that reaches 0 to the purged state (re-flood + retain, NOT delete), and garbage-collects a purged entry whose ZeroAgeLifetime grace period has elapsed. It returns the purge and deletion events for the engine to flood / recompute. Single-writer: it takes the LSDB write lock.
type LSPSnapshot ¶
type LSPSnapshot struct {
LSPID string `json:"lsp-id"`
Sequence uint32 `json:"sequence"`
Lifetime uint16 `json:"lifetime"`
Checksum uint16 `json:"checksum"`
Overload bool `json:"overload"`
Purged bool `json:"purged,omitempty"`
}
LSPSnapshot is one row of the `show isis database` view (rendered by isis-13). It is a flat value with no pointers so it crosses the CLI/RPC boundary cleanly (JSON-tagged for the show output). It carries the freshness metadata plus the overload flag (spec AC-10).
type Level ¶
type Level uint8
Level is the routing level a database holds LSPs for (1 or 2). The LSDB keeps one independent database per level; an L1L2 node populates both.
type LevelState ¶
type LevelState struct {
Neighbors []AdjacencyInfo
Prefixes []PrefixInfo
// InterfaceAddrs are the node's own IPv4 interface addresses (TLV 132,
// RFC 1195): peers use them as the SPF next-hop. De-duplicated by the engine.
InterfaceAddrs []netip.Addr
// PrefixesV6 are the node's own IPv6 prefixes (TLV 236, RFC 5308 sec 2),
// originated only when the node advertises IPv6 (isis-12). Link-local prefixes
// are excluded by the engine before they reach here (RFC 5308 sec 2).
PrefixesV6 []PrefixInfoV6
// InterfaceAddrsV6 are the node's own NON-LINK-LOCAL IPv6 interface addresses
// (TLV 232 in an LSP, RFC 5308 sec 3: an LSP carries only non-link-local
// addresses; the link-local addresses go in the IIH TLV 232, owned by the
// circuit layer). De-duplicated by the engine.
InterfaceAddrsV6 []netip.Addr
}
LevelState is the live state the node advertises at one level: its neighbors (TLV 22), its connected/redistributed prefixes (TLV 135), and its own IPv4 interface addresses (TLV 132). The engine builds one per level from the adjacency tables and the prefix sources.
type NodeInfo ¶
type NodeInfo struct {
// SystemID is the node's 6-octet System ID (the Source ID of its own LSPs,
// pseudonode 0).
SystemID types.SystemID
// Areas are the node's area addresses (TLV 1), originated in fragment 0.
Areas []types.AreaID
// Hostname is the node's dynamic hostname (TLV 137, RFC 5301); empty omits it.
Hostname string
// AdvertiseIPv4 adds NLPID 0xCC to TLV 129 (always true for an IPv4 node).
AdvertiseIPv4 bool
// AdvertiseIPv6 adds NLPID 0x8E to TLV 129 (dual-stack). The IPv6 reachability
// TLV 236 itself is originated by isis-12; this only advertises the protocol.
AdvertiseIPv6 bool
// Overload, when set, sets the LSP-database-overload (OL) bit in the
// non-pseudonode LSP fragment 0 (RFC 3787 sec 4): the node stays reachable but
// is not used as a transit router (SPF honors it in isis-9).
Overload bool
// MaxLifetime is the Remaining Lifetime stamped on a freshly originated LSP
// (MaxAge; the lsp-lifetime leaf, default DefaultMaxAge). Zero defaults to
// DefaultMaxAge in seconds.
MaxLifetime uint16
// MaxLSPSize is the maximum LSP PDU size for fragmentation (derived from the
// circuit MTU, spec A-5). Zero defaults to DefaultMaxLSPSize.
MaxLSPSize int
}
NodeInfo is the node's own identity and global LSP attributes for origination. It is a plain value the engine fills from the resolved config (isis-4) so the lsdb package does not import the config/circuit layer.
type OriginateResult ¶
type OriginateResult struct {
// Originated lists the own LSP IDs (re)written this pass, in fragment order.
Originated []types.LSPID
// Purged lists own LSP IDs flooded as a purge this pass: fragments that are
// no longer needed (state shrank) and any LSP ID that hit sequence wraparound.
Purged []types.LSPID
// Wrapped is true when at least one LSP ID hit sequence wraparound (the
// engine logs it; the suspension is internal).
Wrapped bool
}
OriginateResult reports the outcome of an origination so the engine can flood (isis-7 sets SRM on the listed fragments) and emit LSP-change events.
type Originator ¶
type Originator struct {
// contains filtered or unexported fields
}
Originator builds and stores the node's own LSPs. It holds the LSDB it writes into and the per-LSP-ID sequence-number state (so a regeneration increments monotonically) plus the wraparound suspension deadlines. It is safe for the engine to call Originate from its origination goroutine; the sequence/suspend state is guarded by its own mutex and the LSDB locks itself.
func NewOriginator ¶
func NewOriginator(lsdb *LSDB, now func() time.Time) *Originator
NewOriginator constructs an Originator writing into lsdb. now may be nil (defaults to time.Now).
func (*Originator) Originate ¶
func (o *Originator) Originate(level Level, node NodeInfo, state LevelState) OriginateResult
Originate regenerates the node's own LSP set for level from the live state and stores it in the LSDB (ISO/IEC 10589 clause 7.3.12: full regeneration on a topology change). It:
- builds fragment 0 with the non-fragmentable TLVs (area 1, protocols 129, interface addresses 132, hostname 137) and the overload bit, then packs TLV 22 neighbor entries and TLV 135 prefix entries across fragments 0..N without splitting a single entry (spec AC-5, R-3);
- assigns each fragment a monotonically increasing sequence number, skipping any LSP ID currently suspended after a wraparound, and triggers wraparound handling at 0xFFFFFFFF (purge + suspend + re-originate-from-1, clause 7.3.3, spec AC-4);
- stamps MaxLifetime and lets the codec compute the Fletcher checksum on encode (clause 7.3.11), then stores the fragment;
- purges any previously-originated fragment that this pass no longer needs (state shrank), so a stale fragment does not linger (spec AC-5).
It returns the affected LSP IDs for the engine to flood and emit events.
func (*Originator) OriginatePseudonode ¶
func (o *Originator) OriginatePseudonode(level Level, info PseudonodeInfo) OriginateResult
OriginatePseudonode builds and stores the pseudo-node LSP set for level from info (ISO/IEC 10589 clause 8.4.5), reusing the spec-isis-6 origination path: it assigns monotonically increasing sequence numbers from the Originator's own per-LSP-ID state, handles wraparound identically, and stores each fragment via LSDB.Insert. It returns the affected LSP IDs (the engine arms SRM so spec-isis-7 floods them, and emits LSP-change events).
The pseudo-node Source ID is <info.SystemID>.<info.PseudonodeID> with a NON-ZERO pseudonode octet; a zero PseudonodeID is rejected (it would collide with the node's own router LSP). Each member is a TLV 22 entry at metric 0, the DIS included. TLV 1 (area addresses) is intentionally NOT carried on the pseudo-node LSP: areas are advertised by each real router's own LSP, and a pseudo-node has no area of its own (FRR/IOS originate an area-less pseudo-node LSP); this keeps the pseudo-node a pure topology hub.
func (*Originator) PurgePseudonode ¶
PurgePseudonode purges every fragment of the pseudo-node LSP <sys>.<pnid> at level (ISO/IEC 10589 clause 8.4.5 / 7.3.16.1): the local node has lost the DIS role (R-2) or the circuit went away, so the pseudo-node it originated MUST be withdrawn before another node's SPF can see a phantom node. Each existing fragment is re-flooded as a purge (Remaining Lifetime 0) at a bumped sequence so peers accept it as newer. The pseudonode ID is released (its sequence state cleared) once purged. It returns the purged LSP IDs (the engine arms SRM so the purge floods). A zero pnid is a no-op (not a pseudo-node).
func (*Originator) SetSigner ¶
func (o *Originator) SetSigner(sign func(pdu []byte) []byte)
SetSigner installs the per-level LSP signer (spec-isis-10). The signer takes a fully-encoded LSP (Fletcher checksum already computed) and returns the signed bytes (TLV 10 inserted first, checksum recomputed). nil disables signing. Safe to call before any origination; the originator holds it under its own mutex.
type PrefixInfo ¶
type PrefixInfo struct {
// Prefix is the IPv4 prefix.
Prefix netip.Prefix
// Metric is the 32-bit prefix metric (RFC 5305 sec 4).
Metric types.PrefixMetric
// UpDown is the up/down bit (RFC 2966): set when an L1L2 node leaks an
// L2-derived prefix into L1 (applied in isis-9; the originator carries it).
UpDown bool
}
PrefixInfo is one IPv4 prefix the node advertises in TLV 135 (Extended IP Reachability). Connected and redistributed prefixes (isis-11) become these.
type PrefixInfoV6 ¶
type PrefixInfoV6 struct {
// Prefix is the (non-link-local) IPv6 prefix.
Prefix netip.Prefix
// Metric is the 32-bit prefix metric (RFC 5308 sec 2, same width as TLV 135).
Metric types.PrefixMetric
// UpDown is the up/down bit (RFC 2966 applied to IPv6, RFC 5308 sec 5): set
// when an L1L2 node leaks an L2-derived prefix into L1.
UpDown bool
// External is the X bit (RFC 5308 sec 2): set when the prefix was distributed
// into IS-IS from another protocol (redistribution).
External bool
}
PrefixInfoV6 is one IPv6 prefix the node advertises in TLV 236 (IPv6 Reachability, RFC 5308 sec 2). Connected and redistributed IPv6 prefixes (isis-12) become these. The origination layer (isis-12) filters out link-local (fe80::/10) prefixes before building these (RFC 5308 sec 2: link-local prefixes MUST NOT be advertised in TLV 236).
func NonLinkLocalV6Prefixes ¶
func NonLinkLocalV6Prefixes(in []PrefixInfoV6) []PrefixInfoV6
NonLinkLocalV6Prefixes returns the subset of in that are non-link-local IPv6 prefixes, ready to originate as TLV 236 entries (RFC 5308 sec 2: link-local prefixes MUST NOT be advertised in TLV 236). A prefix is link-local when its network address is in fe80::/10. Invalid or non-IPv6 prefixes are dropped.
type PseudonodeInfo ¶
type PseudonodeInfo struct {
// SystemID is the DIS's System ID; the pseudo-node's Source ID is
// <SystemID>.<PseudonodeID> (ISO/IEC 10589 clause 8.4.5).
SystemID types.SystemID
// PseudonodeID is the non-zero pseudonode octet the DIS allocated for this
// circuit+level. It MUST be 1..255 (0 means a real router, not a pseudo-node);
// OriginatePseudonode rejects 0.
PseudonodeID uint8
// Members are the System IDs of every router on the segment (the DIS included),
// each advertised as a TLV 22 neighbor at metric 0. The engine de-duplicates
// and orders them (so the originated bytes are deterministic).
Members []types.SystemID
// MaxLifetime is the Remaining Lifetime stamped on the fresh pseudo-node LSP
// (MaxAge). Zero defaults to DefaultMaxAge in seconds, like an own LSP.
MaxLifetime uint16
// MaxLSPSize is the maximum LSP PDU size for fragmentation (the circuit MTU).
// Zero defaults to DefaultMaxLSPSize. A LAN with more members than fit one
// fragment splits across fragments via the same packer the own LSP uses (A-4).
MaxLSPSize int
}
PseudonodeInfo is the input to a pseudo-node LSP origination: the identity of the pseudo-node (the DIS System ID plus the non-zero pseudonode octet) and the member set. The engine builds it from the DIS election result (circuit/dis.go) and the segment membership. It is a plain value so the lsdb package does not import the circuit/engine layer.
type PurgeEvent ¶
PurgeEvent names an LSP the tick reports for flooding, with whether it was a local expiry or a received purge so the engine can decide flooding behavior (ISO/IEC 10589 clause 7.3.16: a received purge is re-flooded and retained; a local expiry is only garbage-collected). own marks our own LSP (the engine re-originates a suspended own LSP only after the wraparound window; an aged-out own LSP is normally refreshed long before 0). ReceivedPurge is true when the purge arrived on the wire (the engine re-arms SRM to re-flood it once within the grace window, distinct from a local expiry).
type ReceiveResult ¶
type ReceiveResult struct {
// Freshness is the compare outcome (Newer / Equal / Older).
Freshness Freshness
// Stored is true when the received LSP was actually written to the database
// (Newer, or a first sighting). Equal updates only the lifetime; Older stores
// nothing.
Stored bool
}
ReceiveResult reports what the freshness compare decided for a received LSP so the flooding spec (isis-7) can set SRM/SSN per ISO/IEC 10589 clause 7.3.16.
type TickResult ¶
type TickResult struct {
// Purged lists LSP IDs (per level) that reached Remaining Lifetime 0 on this
// tick and must now be flooded as a purge (isis-7 sets SRM). They remain in
// the database for the grace period.
PurgedL1 []PurgeEvent
PurgedL2 []PurgeEvent
// DeletedL1 / DeletedL2 list LSP IDs garbage-collected on this tick (their
// grace period elapsed). SPF (isis-9) drops them from the graph.
DeletedL1 []deletedEvent
DeletedL2 []deletedEvent
}
TickResult reports the effect of one 1s aging tick so the engine can drive the follow-on actions this spec does NOT own: flooding a fresh purge (isis-7) and recomputing SPF (isis-9). Per-level lists keep the engine's wiring simple.