Skip to content

Module FRR

sat edited this page Aug 13, 2026 · 9 revisions

Module: FRR

This page describes the FRR module for dot2net.

What is FRR?

FRRouting (FRR) is a free and open source Internet routing protocol suite for Linux and Unix platforms. It implements BGP, OSPF, RIP, IS-IS, PIM, LDP, BFD, Babel, PBR, OpenFabric and VRRP.

What the FRR Module Provides

The FRR module generates no output file of its own. It provides a FormatStyle for writing configuration as vtysh commands, and a class that gives a node file logging.

Provided FormatStyles

FormatStyle Name Purpose Output Format
FRRVtyshCLI vtysh command format Shell commands for vtysh

FRRVtyshCLI FormatStyle

The FRRVtyshCLI FormatStyle formats configuration lines as vtysh commands suitable for shell execution:

vtysh -c "conf t" -c "router ospf" -c "router-id 10.255.0.1"

This is useful for the startup config block when you want to configure FRR via command line rather than configuration files.

frrLogFile: writing FRR's log to a file

nodeclass:
  - name: router
    use: [frrLogFile]

That is the whole of it. The class makes the log file, gives it to the frr user, names it to a running FRR, and collects it when the lab is destroyed.

It exists because FRR cannot make that file itself: its daemons run as the frr user and /var/log belongs to root, so a log file named in a configuration read at boot is one FRR reports it cannot open. Mounting an empty file in was the older answer, and it does not survive Kathara, which mounts directories and would have to replace /var/log wholesale.

The commands run from startup, so what is lost is whatever FRR logged before they run — a handful of lines about reading its configuration. From then on the log is complete.

Value Default Meaning
frr_log_path /var/log/frr.log Where the log is written inside the container
frr_log_level informational How much is written. FRR's own default is debugging, which floods a lab's log
nodeclass:
  - name: router
    use: [frrLogFile]
    values:
      frr_log_level: debugging

Where the log ends up

While the lab runs, the log is inside the container and nowhere else:

sudo ./containerlab.sh exec r1 tail -f /var/log/frr.log

It is not on the host. Mounting it out would mean giving the container a writable path into the generated files, and on Kathara it cannot be done at all — a mount there is a whole directory, so it would replace /var/log.

When the lab is destroyed, the entry script copies it out first:

sudo ./containerlab.sh destroy
collected/
├── r1/var/log/frr.log
├── r2/var/log/frr.log
└── ...

collected/<node>/ mirrors the path inside the container, so where a file came from is readable from where it landed. The files belong to whoever ran the script, not to root. sudo ./containerlab.sh collect [<dir>] does the same without destroying the lab, and DOT2NET_COLLECT_DIR moves the destination — which is what lets one topology be run many times, each run keeping its own logs.

This needs an entry script (module_config.<module>.generate_scripts: true); dot2net says so if one is missing. See Command Reference and File Output.

Usage Example

Using FRRVtyshCLI in startup

The format turns a block of configuration lines into one vtysh invocation, so it goes on the block, not on startup itself: startup gathers the blocks and each of them becomes a command.

module:
  - containerlab
  - frr

nodeclass:
  - name: router
    interface_policy: [p2p]
    params: [lo]
    values:
      image: quay.io/frrouting/frr:8.5.4
      kind: linux
    config:
      - name: startup           # unformatted: it collects the blocks below
        depends: [rtr_cmd]
        blocks:
          after: ["self_rtr_cmd", "interfaces_ospf_cmd"]
      - name: rtr_cmd           # what the node itself has to say
        format: FRRVtyshCLI
        template:
          - "router ospf"
          - "router-id {{ .ip_loopback }}"

interfaceclass:
  - name: default
    config:
      - name: ospf_cmd          # and what each of its interfaces has to say
        format: FRRVtyshCLI
        template:
          - "int {{ .name }}"
          - "ip addr {{ .ip_addr }}/{{ .ip_plen }}"
          - "router ospf"
          - "network {{ .ip_net }} area 0"

Note where the parameters come from: ip_loopback belongs to the node (hence params: [lo]), while ip_addr and ip_net belong to an interface — a node template cannot reach them, which is why the interface has a block of its own.

Generated Output

In topo.yaml exec section:

exec:
- vtysh -c "conf t" -c "router ospf" -c "router-id 10.255.0.1"
- vtysh -c "conf t" -c "int eth0" -c "ip addr 10.0.0.1/30" -c "router ospf" -c "network 10.0.0.0/30 area 0"

Alternative: Configuration File Approach

For more complex configurations, you may prefer using FRR configuration files instead of vtysh commands:

module:
  - containerlab

file:
  - name: frr.conf
    path: /etc/frr/frr.conf
  - name: daemons
    path: /etc/frr/daemons
  - name: vtysh.conf
    path: /etc/frr/vtysh.conf

nodeclass:
  - name: router
    values:
      image: quay.io/frrouting/frr:8.5.4
      kind: linux
    config:
      - file: frr.conf
        template:
          - "hostname {{ .name }}"
          - "!"
          - "router ospf"
          - " router-id {{ .ip_loopback }}"
          - "{{ .interfaces_ospf_network }}"
          - "!"
      - file: daemons
        sourcefile: ./daemons
      - file: vtysh.conf
        sourcefile: ./vtysh.conf
      - name: startup
        template:
          - "vtysh -b"  # Load configuration from frr.conf

interfaceclass:
  - name: default
    config:
      # the block frr.conf gathers above, one line per interface
      - name: ospf_network
        template:
          - " network {{ .ip_net }} area 0"

Comparison: Commands vs Config Files

Approach Pros Cons
FRRVtyshCLI (commands) Simple, no extra files Hard to debug, limited complexity
Config files Full FRR syntax, easier debugging Requires file setup (daemons, vtysh.conf)

Recommendation: Use config files for production topologies; use FRRVtyshCLI for simple tests or quick prototypes.

Required FRR Files

When using FRR with configuration files, you typically need:

File Purpose Example Content
frr.conf Main configuration Generated by dot2net
daemons Enable routing daemons ospfd=yes
vtysh.conf vtysh settings service integrated-vtysh-config

Example daemons file

zebra=yes
bgpd=no
ospfd=yes
ospf6d=no
ripd=no
ripngd=no
isisd=no
pimd=no
ldpd=no
nhrpd=no
eigrpd=no
babeld=no
sharpd=no
staticd=no
pbrd=no
bfdd=no
fabricd=no

Example vtysh.conf file

service integrated-vtysh-config

Complete Example with FRRVtyshCLI

This one builds as it stands.

input.yaml

name: ospf_simple
module:
  - containerlab
  - frr

class_policy:
  interface:
    default: [default]

layer:
  - name: ip
    default_connect: true
    policy:
      - name: p2p
        range: 10.0.0.0/16
        prefix: 30
      - name: lo
        type: loopback
        range: 10.255.0.0/24

nodeclass:
  - name: router
    interface_policy: [p2p]
    params: [lo]
    values:
      image: quay.io/frrouting/frr:8.5.4
      kind: linux
    config:
      # startup itself is unformatted: it gathers the blocks below, each of
      # which turns into one vtysh invocation
      - name: startup
        depends: [rtr_cmd]
        blocks:
          after: ["self_rtr_cmd", "interfaces_ospf_cmd"]
      - name: rtr_cmd
        format: FRRVtyshCLI
        template:
          - "router ospf"
          - "router-id {{ .ip_loopback }}"

interfaceclass:
  - name: default
    config:
      - name: ospf_cmd
        format: FRRVtyshCLI
        template:
          - "int {{ .name }}"
          - "ip addr {{ .ip_addr }}/{{ .ip_plen }}"
          - "router ospf"
          - "network {{ .ip_net }} area 0"

input.dot

graph {
  r1 [class="router"]
  r2 [class="router"]
  r1 -- r2
}

Generated topo.yaml

name: ospf_simple
topology:
  nodes:
    r1:
      kind: linux
      image: quay.io/frrouting/frr:8.5.4
      network-mode: none
      exec:
      - vtysh -c "conf t" -c "router ospf" -c "router-id 10.255.0.1"
      - vtysh -c "conf t" -c "int eth0" -c "ip addr 10.0.0.1/30" -c "router ospf" -c "network 10.0.0.0/30 area 0"
    r2:
      kind: linux
      image: quay.io/frrouting/frr:8.5.4
      network-mode: none
      exec:
      - vtysh -c "conf t" -c "router ospf" -c "router-id 10.255.0.2"
      - vtysh -c "conf t" -c "int eth0" -c "ip addr 10.0.0.2/30" -c "router ospf" -c "network 10.0.0.0/30 area 0"

  links:
  - endpoints: [r1:eth0, r2:eth0]

See Also

Clone this wiki locally