-
Notifications
You must be signed in to change notification settings - Fork 1
Module TiNet
This page describes the TiNET module for dot2net.
TiNET (Tiny Network) is a lightweight container-based network emulation tool. It uses Docker containers connected via Linux network namespaces and veth pairs to create virtual network topologies.
The TiNET module generates spec.yaml, the specification file for TiNET:
nodes:
- name: r1
image: quay.io/frrouting/frr:8.5.4
interfaces: [{name: eth0, type: direct, args: r2#eth0}]
mounts: [$PWD/r1/etc/frr/frr.conf:/etc/frr/frr.conf, $PWD/r1/etc/frr/daemons:/etc/frr/daemons]
node_configs:
- name: r1
cmds:
- cmd: vtysh -b| Section | Source | Description |
|---|---|---|
nodes |
DOT nodes | Node definitions with image, interfaces, mounts |
switches |
deploy: platform nodes |
Shared media TiNET realizes as bridges. The section is left out entirely when a topology has none |
node_configs |
startup block |
Commands to run on each node |
- interfaces: Automatically generated from DOT edge definitions
-
mounts: Generated from FileDefinitions that have
pathset. They start with$PWD/: TiNET passes the string todocker run -v, which refuses a relative source, and the output oftinet upis meant to be piped to a shell that expands it — against the directory the lab is brought up from, which is where the spec file sits -
cmds: Generated from user-defined
startupconfig block
When a topology declares worker groups, the spec file becomes group-scoped:
each machine gets its own, holding its nodes and the links it can wire itself. A
link that leaves a machine appears in neither, since no spec file can make it —
see Placing nodes on machines.
Mount paths become relative to the machine's directory.
module_config:
tinet:
generate_scripts: truewrites tinet.sh, which carries the parts that are easy to get wrong: TiNET
brings a lab up in two steps (up creates the nodes, conf applies
node_configs), its output is a shell script meant to be piped, and it prints
one line that is not a command when an interface attaches to a switch — which
the pipe has to drop or the shell stops there.
See Command Reference.
Each node TiNET deploys must have this parameter defined (a node with
deploy: none has none to run, and a deploy: platform node is a bridge):
| Parameter | Description | Example |
|---|---|---|
image |
Container image | quay.io/frrouting/frr:8.5.4 |
Define this in your NodeClass:
nodeclass:
- name: router
interface_policy: [p2p] # addresses for this node's interfaces
params: [lo] # and ip_loopback for the node itself
values:
image: quay.io/frrouting/frr:8.5.4The startup config block defines commands to run inside the container. This is used to generate the cmds section in node_configs.
nodeclass:
- name: router
config:
- name: startup
template:
- "vtysh -b"
- "ip addr add {{ .ip_loopback }}/32 dev lo"Behavior: every node gets a node_configs entry. A node with no startup
commands gets one with an empty cmds:, which TiNET accepts. (containerlab
differs here: its exec: section is left out when there is nothing to run.)
Files with path defined in FileDefinition are automatically mounted into containers:
file:
- name: frr.conf
path: /etc/frr/frr.conf # This triggers mount generation
- name: daemons
path: /etc/frr/daemonsGenerated mounts:
mounts: [$PWD/r1/etc/frr/frr.conf:/etc/frr/frr.conf, $PWD/r1/etc/frr/daemons:/etc/frr/daemons]name: ospf_lab
module:
- tinet
- frr
file:
- name: frr.conf
path: /etc/frr/frr.conf
- name: daemons
path: /etc/frr/daemons
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] # addresses for this node's interfaces
params: [lo] # and ip_loopback for the node itself
values:
image: quay.io/frrouting/frr:8.5.4
config:
- file: frr.conf
template:
- "hostname {{ .name }}"
- "!"
- "router ospf"
- " router-id {{ .ip_loopback }}"
- file: daemons
sourcefile: ./daemons
- name: startup
template:
- "vtysh -b"graph {
r1 [class="router"]
r2 [class="router"]
r1 -- r2
}nodes:
- name: r1
image: quay.io/frrouting/frr:8.5.4
interfaces: [{name: eth0, type: direct, args: r2#eth0}]
mounts: [$PWD/r1/etc/frr/frr.conf:/etc/frr/frr.conf, $PWD/r1/etc/frr/daemons:/etc/frr/daemons]
- name: r2
image: quay.io/frrouting/frr:8.5.4
interfaces: [{name: eth0, type: direct, args: r1#eth0}]
mounts: [$PWD/r2/etc/frr/frr.conf:/etc/frr/frr.conf, $PWD/r2/etc/frr/daemons:/etc/frr/daemons]
node_configs:
- name: r1
cmds:
- cmd: vtysh -b
- name: r2
cmds:
- cmd: vtysh -bdot2net build -c input.yaml input.dot
tinet up -c spec.yaml | grep -v '<->' | sudo sh
tinet conf -c spec.yaml | grep -v '<->' | sudo sh
tinet down -c spec.yaml | grep -v '<->' | sudo shThe grep is not optional: TiNET prints one line that is not a command when an
interface attaches to a switch, and the shell stops there without it.
module_config.tinet.generate_scripts: true (off by default) writes tinet.sh,
which carries the two-step deploy and that pipe for you:
sudo ./tinet.sh deploy # up and conf
sudo ./tinet.sh exec r1 ip addr
sudo ./tinet.sh destroy # teardown, collect, then downA topology that collects files or has teardown commands needs the script for them to happen. See Command Reference.
| Feature | TiNET | Containerlab |
|---|---|---|
| Complexity | Simpler, lightweight | More features |
| Node types | Docker containers | Multiple kinds (SR Linux, cEOS, etc.) |
| Execution | Shell script output | Direct deployment |
| Interface naming | dot2net's own, eth0 by default |
the same. Kathara is the one that fixes it |
- Module System - How modules work
- File Output - File generation and bind mounts
- Module: Containerlab - Alternative container-based platform
- Module: FRR - FRR configuration helpers