c9s
Core Concepts

Nodes and Links

The primary Clabernetes API for describing network nodes and point-to-point wires.

Node and Link resources form the primary c9s API. A Node contains one containerlab node definition, while a Link contains one connection between two node interfaces.

Both resources are namespace-scoped. A namespace is therefore the boundary of a directly authored lab, and both endpoints of a Link must refer to Nodes in that namespace.

Node

The Node name is the containerlab node name. Its specification uses containerlab vocabulary for fields such as kind, image, type, startup-config, and exec.

apiVersion: c9s.run/v1alpha1
kind: Node
metadata:
  name: srl1
spec:
  profileRef:
    name: lab-policy
  kind: nokia_srlinux
  image: ghcr.io/nokia/srlinux:26.3

A Node can reference one same-namespace NodeProfile. If the reference is omitted, global Config defaults apply. An explicit reference that does not exist prevents the Node from being realized.

Node fields

The Node spec accepts the portable containerlab node vocabulary. Unknown fields are rejected when the manifest is applied, and known fields without a Pod mapping fail planning with a diagnostic naming the field.

  • Realized as declared: kind, type, image, image-pull-policy, entrypoint, cmd, env, user, sysctls, devices, cap-add, privileged, security-opts, tmpfs, shm-size, cpu, memory, dns, healthcheck, startup-delay, restart-policy (always or unless-stopped), exec, mgmt-ipv4, mgmt-ipv6, ports, aliases, group, extras, components, and certificate.
  • Files: startup-config (inline text or a path), license, and binds take their content from payloads attached to the Node, see Containerlab file fields.
  • Grouping: network-mode: container:<primary> places the Node in the primary Node's Pod. Other network modes are rejected.
  • Link changes: link-apply-mode (live, restart, or recreate) overrides the kind's default action when Links of the Node change. live applies changes in the existing Pod. Both restart and recreate directly replace the Pod; c9s does not first attempt an application restart or wait for a restart timeout. Normal Kubernetes termination grace periods still apply. Pod replacement restarts all Nodes sharing that Pod; configuration survival follows the persistent storage policy.
  • Rejected at planning: config (config-engine variables), env-files, runtime, stages, and credentials, see Differences from containerlab.

Inside a device, node names, aliases, and chassis component names resolve to management addresses, see Management network.

A Link declares exactly two endpoints: one wire, nothing else.

apiVersion: c9s.run/v1alpha1
kind: Link
metadata:
  name: srl1-e1-1-multitool-eth1
spec:
  endpointA:
    nodeName: srl1
    interfaceName: e1-1
  endpointB:
    nodeName: multitool
    interfaceName: eth1

Wiring belongs only to Link objects; interfaces are not embedded into Node specifications. The link controller validates endpoints and records a namespace-unique wire id in status, while each device Pod's connectivity sidecar watches only the Links terminating on its own Nodes and realizes each cross-Pod wire on the sidecar-to-sidecar fabric wire, addressed by the Link's allocated wire id.

Why direct resources?

Each Node grows only with its own configuration and each Link remains one wire. This removes the single aggregate-object size limit of a source Topology and lets each resource reconcile independently.

Direct resources do not promise unlimited scale: Kubernetes API capacity, controller throughput, and the total object count still matter.

Complete example

The individual-resource SR Linux and multitool example contains a NodeProfile, two Nodes, and one Link.

See the Node reference and Link reference for all fields, and Operating a lab for reading Node and Link status.

On this page