Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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).

FieldDefaultMeaning
netnoneThe 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_lifetime1200How long, in seconds, the domain holds this router's LSPs. 1 to 1200.
lsp_refresh_interval900How 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_interval30The 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_mtu1492The 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_splits2The most equal-cost paths a route is installed over. 1 to 32.
ignore_attached_bitfalseInstall 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

FieldDefaultMeaning
metric10The cost of the circuit. 1 to 63.
interface_typefrom 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.
passivefalseAdvertise the interface's subnets and addresses without running IS-IS on the link. A loopback is passive whatever this says.
hello_interval10How often, in seconds, the circuit sends a hello. Not 0.
hello_multiplier3How many hello intervals a neighbour holds the adjacency for without hearing a hello. 2 to 100.
csnp_interval10How often, in seconds, a broadcast circuit sends a complete set of sequence number PDUs while it is the DIS. Not 0.
lsp_pacing_interval33The least time, in milliseconds, between two LSPs the circuit sends. Not 0.
lsp_retransmit_interval5How 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_authnoneThe 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.

FieldDefaultMeaning
priority64This 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_auththe interface'sThe 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 -- null until the system reports the VRF, while IS-IS holds its configuration but is not running there.
  • net -- null until one is configured.
  • levels -- the levels IS-IS holds state for. It follows is_type.
  • auth -- how each level's LSPs and sequence number PDUs are authenticated, null where 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). null otherwise.

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, null where the system reports none.
  • interface_type -- what the circuit runs as, which need not be what the link is. null on 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, null where they are not. A point-to-point circuit reports the same at both levels, its one hello serving both; a LAN reports null at 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 own snpa where this router holds the role. null on 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, Initializing or Up. null on 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, and rx_drop the 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 -- Init until the neighbour's hellos show it hears this router, then Up. Only an Up adjacency 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; null before then.
  • next_hop -- the address routes through the neighbour are installed with: the lowest of its addresses on one of the interface's subnets, or null where 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.

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 with 0 until it is removed.
  • is_type -- the levels the source says it routes at, or null where 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, L2External or L1InterAreaExternal. 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_metric is the external route's own metric, compared first.
  • nhs -- the next hops, in interface name order. intf_name is null for an interface the system deleted since the route was computed.
  • connected -- a subnet of one of this router's own interfaces, with no nh_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>]