IS-IS Component
Overview
The IS-IS component runs the IS-IS link-state protocol (ISO/IEC 10589) for IPv4 (RFC 1195) in each configured VRF. It forms adjacencies with its neighbours, floods link-state PDUs (LSPs) to build a database of the area, computes the shortest path to every prefix, and sends the best routes to the RIB.
What runs:
- Level 1 and level 2 routing, and a level-1-2 system leaking its level-1 routes into level 2 (RFC 1195 § 3.2). A level-1 system routes to the nearest attached level-2 system by default (10589 § 7.2.9.1).
- Broadcast circuits, with a designated system (DIS) elected at each level, and point-to-point circuits, with the three-way handshake (RFC 5303). A point-to-point circuit can run over a broadcast link (RFC 5309).
- Passive circuits, which advertise an interface's subnets without running IS-IS on the link.
- Cleartext and HMAC-MD5 authentication (RFC 5304) of hellos, LSPs and sequence number PDUs.
The following are not yet supported:
- IPv6, wide metrics (RFC 5305) and anything that needs them, such as segment routing and multi-topology. Metrics are narrow: 1 to 63 per circuit.
- Redistribution of other protocols' routes into IS-IS, and level-2 routes leaked into level 1.
- Restricting a circuit to one level: a level-1-2 system runs both levels on every circuit.
- More than one area address per system.
Configuration
IS-IS is enabled by adding an isis object to /etc/flockd/flockd.json with one entry per VRF that should run IS-IS. A VRF takes part only once it has a NET, and IS-IS runs only on the interfaces listed under it.
The minimal config -- a NET, every other field at its default, and IS-IS on one interface:
"isis": {
"vrfs": {
"default": {
"net": "49.0001.1921.6800.1001.00",
"intfs": {
"eth0": {}
}
}
}
}
A key flockd does not recognise, or a value IS-IS would refuse, is rejected with the file: flockd keeps the configuration it is running and logs which value was refused, naming its VRF, interface and level.
Per-VRF fields
Every field is optional; an omitted field keeps its default. Key names follow the IETF IS-IS YANG model (RFC 9130).
| Field | Default | Meaning |
|---|---|---|
net | none | The Network Entity Title: the area address followed by this router's six-octet system id and a zero selector, "49.0001.1921.6800.1001.00". IS-IS takes no part in the VRF until it is set. A VRF has one NET. |
is_type | "level-1-2" | The levels this router routes at: "level-1", "level-2" or "level-1-2". RFC 9130 calls both levels level-all; the value here names the levels it runs. |
lsp_lifetime | 1200 | How long, in seconds, the domain holds this router's LSPs. 1 to 1200. |
lsp_refresh_interval | 900 | How often, in seconds, this router generates its LSPs again whether or not they have changed. Not 0. Keep it inside lsp_lifetime, or the domain drops this router's LSPs between two refreshes; flockd warns when it is not. |
lsp_min_generation_interval | 30 | The least time, in seconds, between two generations of one of this router's LSPs (10589 § 7.3.6). A change waits up to this long to reach the domain. 0 generates on every change. |
lsp_mtu | 1492 | The largest LSP this router originates, in octets. 512 to 1492. It must fit every circuit: an LSP larger than one frame on the circuit -- the interface MTU, but no more than 1500 octets, less the 3-octet LLC header -- is not sent on it, and flockd warns. |
maximum_path_splits | 2 | The most equal-cost paths a route is installed over. 1 to 32. |
ignore_attached_bit | false | Install no default route towards an attached level-2 system, so that a default route advertised in the area is used instead. |
level_1, level_2 | {} | This router's settings at one level: auth, the key its LSPs and sequence number PDUs at that level are signed and checked with. See Authentication. |
intfs | {} | Map of interface name to per-interface configuration. Listing an interface runs IS-IS on it. |
Per-interface fields
| Field | Default | Meaning |
|---|---|---|
metric | 10 | The cost of the circuit. 1 to 63. |
interface_type | from the link | "broadcast" or "point-to-point". Unset, a point-to-point link runs a point-to-point circuit and anything else a broadcast one. Both ends of a link must agree. |
passive | false | Advertise the interface's subnets and addresses without running IS-IS on the link. A loopback is passive whatever this says. |
hello_interval | 10 | How often, in seconds, the circuit sends a hello. Not 0. |
hello_multiplier | 3 | How many hello intervals a neighbour holds the adjacency for without hearing a hello. 2 to 100. |
csnp_interval | 10 | How often, in seconds, a broadcast circuit sends a complete set of sequence number PDUs while it is the DIS. Not 0. |
lsp_pacing_interval | 33 | The least time, in milliseconds, between two LSPs the circuit sends. Not 0. |
lsp_retransmit_interval | 5 | How often, in seconds, a point-to-point circuit sends again an LSP its neighbour has not acknowledged, and the least time between two sends of one LSP on any circuit. Not 0. |
hello_auth | none | The key this circuit's hellos are signed and checked with, at each level whose record names none of its own. See Authentication. |
level_1, level_2 | {} | This circuit's settings at one level, below. |
Per-level fields
level_1 and level_2 hold what a circuit runs with at that level. They do not turn a level on or off -- is_type decides which levels run -- so a record for a level the router does not run is held and does nothing until is_type takes that level in.
| Field | Default | Meaning |
|---|---|---|
priority | 64 | This router's claim on being the DIS at this level, 0 to 127. The highest priority is elected, then the highest MAC address. 0 is the lowest claim, not a refusal: a router at priority 0 is still elected where it outranks the others. A router with no adjacency Up at a level elects no DIS there, itself included. A point-to-point circuit elects no DIS, and ignores it. |
hello_auth | the interface's | The key this circuit's hellos at this level are signed and checked with, in place of the interface's hello_auth. |
A config with a loopback, a point-to-point link, and a LAN on which this router is preferred as the level-2 DIS:
"isis": {
"vrfs": {
"default": {
"net": "49.0001.0700.0010.0070.00",
"is_type": "level-2",
"intfs": {
"lo": {},
"enp7s0": {
"interface_type": "point-to-point"
},
"enp9s0": {
"level_2": {
"priority": 100
}
}
}
}
}
}
Authentication
Each IS-IS PDU can carry a password in the clear (10589 § 8.2.4, § 7.3.7) or an HMAC-MD5 digest of the PDU (RFC 5304). A key is configured as an object naming its algorithm and the file it is read from; it never appears in the configuration itself:
"isis": {
"vrfs": {
"default": {
"net": "49.0001.0700.0010.0070.00",
"level_1": {
"auth": {
"auth_algo": "hmac-md5",
"auth_key_file": "/etc/flockd/isis/area.key"
}
},
"intfs": {
"enp7s0": {
"hello_auth": {
"auth_algo": "hmac-md5",
"auth_key_file": "/etc/flockd/isis/enp7s0.key"
}
}
}
}
}
}
auth_algo is "cleartext" or "hmac-md5". Which key a PDU uses:
- LSPs and sequence number PDUs use their level's
auth: 10589's area password at level 1 and domain password at level 2. Every LSP this router originates at the level carries it, as does every purge it sends. - A LAN hello uses its level's
hello_auth, else the interface's. - A point-to-point hello serves every level the circuit runs, so it uses the key of the lowest level running, found the same way.
Where a key is configured, a PDU that does not carry it is dropped and counted as auth_failed; a purge carrying anything a purge may not (RFC 6233) is dropped the same way. Where none is configured, PDUs are taken whether they carry a key or not. A key change is used at once: this router's LSPs are generated again under the new key, and a hello signed with it goes out at once, or on a LAN as soon as the one-second spacing allows.
There is one key per place, used both to sign and to check, so changing a key drops the adjacency, or stops LSPs being taken, until both ends hold the new one. Change it at both ends together.
The file's UTF-8 contents form the key, 1 to 253 octets; flockd strips trailing line endings (LF or CRLF). Permissions are the operator's responsibility -- 0600 owned by the flockd user is the expected baseline. Relative paths in flockd.json resolve against the directory of the JSON file; absolute paths are used as-is. The file is read when flockd.json is applied rather than watched, so a rotated key takes effect the next time flockd.json changes; touching it is enough. An inline "auth_key" is refused, pointing at the auth_key_file form.
The operational state reports which algorithm each level uses, never the key.
Passive circuits and loopbacks
A passive circuit sends and accepts no IS-IS PDUs: it forms no adjacency and stands in no DIS election. Its subnets and addresses are advertised in this router's LSP at every level the router runs, for as long as its link is up. Loopbacks are always passive, so a loopback is listed with no keys to advertise the router's own addresses. passive makes any other interface passive too, for a link with hosts on it but no IS-IS routers.
Hellos and holding time
Each hello asks the neighbour to hold the adjacency for hello_interval × hello_multiplier seconds, so the defaults hold an adjacency for 30 seconds. The DIS sends hellos three times as often, at a third of hello_interval but no faster than once a second, so that the LAN notices its loss sooner, and its holding time is shortened to match. A LAN hello of one level is held until a second has passed since the last (10589 § 8.4.4): a hello that changes, such as one naming a new neighbour, waits out the second and is sent then. The last hello a circuit sends as it stops, and the first after it is rebuilt, go at once. Hellos are padded to fill one frame -- the interface MTU, but no more than 1500 octets -- so an adjacency forms only where both ends pass a frame that size.
A broadcast circuit elects its first DIS two hello intervals after it comes up, so that a router joining a LAN learns the routers already there before it claims the role.
Reload semantics
Saving flockd.json is enough to apply a change; flockd auto-reloads the file.
net-- a new system id makes this a different router: it says goodbye to its neighbours and starts again under the new id. A new area address alone keeps the adjacencies whose neighbours list the new area too, and this router's LSPs carry it from their next generation. Removing the NET stops IS-IS in the VRF.is_type-- a level that is added starts at once; one that is removed stops, and its adjacencies go down. A point-to-point adjacency goes down and comes up again for the new levels.lsp_lifetime,lsp_mtu-- this router's LSPs are generated again.lsp_refresh_interval-- the refresh is re-armed at the new interval.lsp_min_generation_interval-- applies from the next generation.maximum_path_splits,ignore_attached_bit-- routes are computed again.metric-- this router's LSPs are generated again.hello_interval,hello_multiplier,priority,hello_auth-- a hello carrying the new values is sent at once, or on a LAN as soon as the one-second spacing allows. A priority change runs the DIS election again.auth-- this router's LSPs are generated again, signed with the new key.csnp_interval-- the DIS's timer is re-armed at the new interval.lsp_pacing_interval,lsp_retransmit_interval-- apply to what is sent next.interface_type,passive-- the circuit is rebuilt, so its adjacencies go down and come up again.intfs-- listing an interface runs IS-IS on it. Removing one stops it there; the circuit sends a last hello so its neighbours take the adjacency down at once rather than when it times out.- Removing a VRF stops IS-IS in it, with the same last hello on every circuit. So does stopping
flockd.
This router's LSPs are not purged when it stops: its neighbours drop the adjacency, every other router stops using the LSPs at once, and they age out of the database.
Operational State
The examples below come from a VRF named red running level 1, with a point-to-point neighbour on red0.
Check IS-IS is enabled
IS-IS appears in the enabled_protocols list in the system overview once a VRF is configured:
flock@r1:~$ flockc sys overview
{"host_info":{"hostname":"r1", ...},"enabled_protocols":["IS-IS","Static"], ...}
Show IS-IS VRFs
One row per VRF IS-IS is configured in, running or not.
flock@r1:~$ flockc isis vrfs
[{"vrf_name":"red","vrf_id":1,"net":"49.0001.0000.0000.0001.00","is_type":"level-1",
"levels":{"level-1":true,"level-2":false},"auth":{"level-1":"hmac-md5","level-2":null},
"resumes_at":null,
"last_modified":"2026-10-22T08:37:34.547Z"}]
vrf_id--nulluntil the system reports the VRF, while IS-IS holds its configuration but is not running there.net--nulluntil one is configured.levels-- the levels IS-IS holds state for. It followsis_type.auth-- how each level's LSPs and sequence number PDUs are authenticated,nullwhere they are not.resumes_at-- when IS-IS runs again where it has stopped itself because one of this router's LSPs reached the highest sequence number (10589 § 7.3.16.1).nullotherwise.
Show a VRF
The same row for one VRF, or null where IS-IS is not configured in it.
flock@r1:~$ flockc isis vrf red summary
Show IS-IS interfaces
intfs lists every circuit in the VRF, and intf shows one by name.
flock@r1:~$ flockc isis vrf red intf red0
{"vrf_name":"red","intf_name":"red0","intf_id":1,"snpa":"02:00:00:00:00:01","mtu":1500,
"interface_type":"point-to-point","passive":false,"levels":{"level-1":true,"level-2":false},
"metric":10,"hello_interval":{"secs":10,"nanos":0},"hello_multiplier":3,
"priority":{"level-1":64,"level-2":64},"hello_auth":{"level-1":null,"level-2":null},
"lsp_pacing_interval":{"secs":0,"nanos":33000000},"csnp_interval":{"secs":10,"nanos":0},
"lsp_retransmit_interval":{"secs":5,"nanos":0},"frames_rx":3,
"rx_drop":{"not_isis":0,"truncated":0,"pdu_fmt_err":0,"pdu_type_unsupported":0,
"hello_type_mismatch":0,"level_not_running":0,"no_adjacency":0,
"not_designated":0,"area_mismatch":0,"max_area_addrs_mismatch":0,
"wrong_system_type":0,"not_for_this_system":0,"no_local_net":0,
"auth_failed":0,"adj_rejected":0},
"dis":{"level-1":null,"level-2":null},"three_way":"Up",
"adjs":{"level-1":{"init":0,"up":1},"level-2":{"init":0,"up":0}},"up":true,
"last_modified":"2026-10-22T08:37:34.548Z"}
snpa-- the MAC address the circuit sends from,nullwhere the system reports none.interface_type-- what the circuit runs as, which need not be what the link is.nullon a passive circuit.levels-- the levels the circuit takes part at: the router's levels, while the link can carry a frame. A passive circuit takes part by advertising its subnets, while its link is up.priority-- the configured priority at each level, whether or not the circuit is broadcast.hello_auth-- how the circuit's hellos at each level are authenticated as they are sent,nullwhere they are not. A point-to-point circuit reports the same at both levels, its one hello serving both; a LAN reportsnullat a level it does not run, and a passive circuit, which sends no hello, at both.dis-- the MAC address of the elected DIS at each level, which is this circuit's ownsnpawhere this router holds the role.nullon a point-to-point circuit, and on a LAN before the first election.three_way-- the three-way handshake state on a point-to-point circuit (RFC 5303):Down,InitializingorUp.nullon a broadcast circuit.adjs-- how many adjacencies the circuit holds at each level, by state.up-- whether the circuit can exchange PDUs, or, on a passive circuit, whether its link is up.frames_rx-- frames read from the link, andrx_dropthe ones that went no further, by reason:not_isis-- a frame for another protocol that shares the link-layer address. Ordinary on a busy LAN.truncated-- a frame larger than one frame the link carries: the interface MTU, but no more than 1500 octets.pdu_fmt_err-- a PDU that does not decode.pdu_type_unsupported-- a PDU of a type that has nowhere to go.hello_type_mismatch-- a hello of the other kind: the two ends disagree about whether the link is point-to-point. Only the broadcast end sees it.level_not_running-- a PDU for a level the circuit does not run.no_adjacency-- an LSP or sequence number PDU from a system with no adjacency here.not_designated-- a partial sequence number PDU on a LAN where this router is not the DIS.area_mismatch-- a hello sharing no area with this router.max_area_addrs_mismatch-- a point-to-point hello whose sender allows a different number of area addresses.wrong_system_type-- a hello from a system whose level leaves nothing the adjacency could carry, such as a level-2 system reaching a level-1 router.not_for_this_system-- a point-to-point hello answering another system: the link is cross-connected.no_local_net-- a hello read while this router has no NET.auth_failed-- a PDU without the key configured for it, or a purge carrying what a purge may not.adj_rejected-- a LAN hello from a new neighbour, ignored because this router's hello has no room to list another and the newcomer's priority is no higher than the lowest held. A newcomer at a higher priority takes the place of the lowest-ranked adjacencies, by priority and then MAC address, instead. Where the room shrinks under the adjacencies held, as with a smaller MTU or an address added, the lowest-ranked go.
The counters continue across a link going down and most configuration changes, and start from zero when the circuit is rebuilt -- an interface_type or passive change -- or the interface leaves IS-IS configuration or the system. A frame being read does not move last_modified.
A passive circuit and a LAN neighbour, from a level-1-2 router:
flock@r1:~$ flockc isis vrf red intfs
[{"vrf_name":"red","intf_name":"red0","intf_id":1,"snpa":"02:00:00:00:00:01","mtu":1500,
"interface_type":null,"passive":true,"levels":{"level-1":true,"level-2":true}, ...
"frames_rx":0, ... "dis":{"level-1":null,"level-2":null},"three_way":null,
"adjs":{"level-1":{"init":0,"up":0},"level-2":{"init":0,"up":0}},"up":true, ...},
{"vrf_name":"red","intf_name":"red1","intf_id":2,"snpa":"02:00:00:00:00:02","mtu":1500,
"interface_type":"broadcast","passive":false,"levels":{"level-1":true,"level-2":true}, ...
"adjs":{"level-1":{"init":0,"up":1},"level-2":{"init":0,"up":0}},"up":true, ...}]
Show adjacencies
Every adjacency on one circuit, at every level it runs.
flock@r1:~$ flockc isis vrf red adjs red0
[{"vrf_name":"red","intf_name":"red0","level":"level-1","snpa":"02:00:00:00:01:99",
"system_id":"0000.0000.0002","state":"Up","holding_time":{"secs":30,"nanos":0},
"area_addrs":["49.0001"],"medium":{"PointToPoint":{"circuit_id":"0000.0000.0002.01"}},
"ip_intf_addrs":["10.0.1.2"],"next_hop":"10.0.1.2",
"last_modified":"2026-10-22T08:37:34.548Z"}]
On a LAN, medium carries the neighbour's priority and the LAN ID it reports, which names the DIS's pseudonode:
"medium":{"Lan":{"priority":64,"lan_id":"0000.0000.0003.04"}}
state--Inituntil the neighbour's hellos show it hears this router, thenUp. Only anUpadjacency carries routes.holding_time-- how long this router holds the adjacency without a hello, as the neighbour's hellos ask.circuit_id-- on a point-to-point circuit, the id both ends agree on as the adjacency comes up;nullbefore then.next_hop-- the address routes through the neighbour are installed with: the lowest of its addresses on one of the interface's subnets, ornullwhere it has none, and then no route is installed through it.last_modified-- a hello restating what the adjacency already holds does not move it.
Show the link-state database
The headers of the LSPs one level holds, 1 or 2, in LSP ID order. --system-id lists only the LSPs one system sources, its pseudonodes' included.
flock@r1:~$ flockc isis vrf red lsdb 1
[{"lsp_id":"0000.0000.0001.00-00","seq":2,"lifetime":1200,"checksum":44887,"is_type":"L1",
"partition":false,"att_error":false,"att_expense":false,"att_delay":false,
"att_default":false,"overload":false,"last_modified":"2026-10-22T08:37:34.548Z"},
{"lsp_id":"0000.0000.0002.00-00","seq":1,"lifetime":1200,"checksum":24159,"is_type":"L1",
"partition":false,"att_error":false,"att_expense":false,"att_delay":false,
"att_default":false,"overload":false,"last_modified":"2026-10-22T08:37:34.649Z"}]
flock@r1:~$ flockc isis vrf red lsdb 1 --system-id 0000.0000.0002
lifetime-- the remaining lifetime the LSP was stored with, in seconds. A purged LSP is held with0until it is removed.is_type-- the levels the source says it routes at, ornullwhere it claims a value 10589 leaves unused.att_default-- the source is a level-1-2 system attached to the rest of the domain, which level-1 routers send their default route towards.overload-- the source asks not to be used as a transit router.last_modified-- when this router stored this copy.
Look up a route
The route IS-IS holds for one prefix, matched exactly, or null. best is the path given to the RIB, and levels the path each level computed.
flock@r1:~$ flockc isis vrf red rib lookup 192.168.1.0/24
{"best":{"level":"level-1","route_type":"L1Internal","metric":15,"external_metric":null,
"nhs":[{"intf_name":"red0","nh_addr":"10.0.1.2"}],"connected":false},
"levels":{"level-1":{"level":"level-1","route_type":"L1Internal","metric":15,
"external_metric":null,
"nhs":[{"intf_name":"red0","nh_addr":"10.0.1.2"}],
"connected":false},
"level-2":null},
"last_modified":"2026-10-22T08:37:34.649Z"}
route_type-- in order of preference,L1Internal,L2Internal,L1InterArea(leaked into level 1 from level 2),L1External,L2ExternalorL1InterAreaExternal. A route of an earlier type wins over a later one whatever their metrics (RFC 5302 3.2).metric-- the cost of the path, and, for an external route, the cost to the router advertising it.external_metricis the external route's own metric, compared first.nhs-- the next hops, in interface name order.intf_nameisnullfor an interface the system deleted since the route was computed.connected-- a subnet of one of this router's own interfaces, with nonh_addr. IS-IS holds it so it can be advertised, and never gives it to the RIB.
Walk the routes
The routes under a prefix, in prefix order, whole or a chunk at a time. --max-entries returns at most that many, and --start-from resumes after the prefix a previous chunk ended on. finished is true when no route follows the last one returned.
flock@r1:~$ flockc isis vrf red rib walk 0.0.0.0/0
{"entries":[{"prefix":"10.0.1.0/24",
"entry":{"best":{"level":"level-1","route_type":"L1Internal","metric":10,
"external_metric":null,
"nhs":[{"intf_name":"red0","nh_addr":null}],
"connected":true}, ...}},
{"prefix":"192.168.1.0/24",
"entry":{"best":{"level":"level-1","route_type":"L1Internal","metric":15,
"external_metric":null,
"nhs":[{"intf_name":"red0","nh_addr":"10.0.1.2"}],
"connected":false}, ...}}],
"finished":true}
flock@r1:~$ flockc isis vrf red rib walk 0.0.0.0/0 --max-entries 100 --start-from 10.0.1.0/24
Stream adjacency changes
flockc subscribe isis adj streams adjacencies coming up and going down, printing one update per change until interrupted. It first prints every adjacency that is up, then each change. --vrf limits the stream to one VRF and --intf-name to interfaces of that name.
flock@r1:~$ flockc subscribe isis adj --vrf red
{"vrf_name":"red","intf_name":"red0","level":"level-1","snpa":"02:00:00:00:01:99",
"value":{"system_id":"0000.0000.0002","last_modified":"2026-10-22T08:37:34.548Z"},
"deleted":false}
An adjacency coming up carries the neighbour's system id and when it came up. One leaving Up -- falling back to Init, timing out or being torn down -- is reported with "deleted":true and no value. An adjacency that has not been Up is not reported, whether it comes or goes.
IS-IS Operation Commands Reference
Help
flockc isis --help
VRFs
flockc isis vrfs
One VRF
flockc isis vrf <vrf-name> summary
Interfaces
flockc isis vrf <vrf-name> intfs
flockc isis vrf <vrf-name> intf <intf-name>
Adjacencies
flockc isis vrf <vrf-name> adjs <intf-name>
Link-state database
flockc isis vrf <vrf-name> lsdb <1 | 2> [--system-id <system-id>]
Routes
flockc isis vrf <vrf-name> rib lookup <prefix>
flockc isis vrf <vrf-name> rib walk <root-prefix> [--max-entries <n>] [--start-from <prefix>]
Adjacency change stream
flockc subscribe isis adj [--vrf <vrf-name>] [--intf-name <intf-name>]