Netlab Tutorial: Build a Campus Network Lab with VLANs, VRRP, and OSPF
Learn how to build a campus-style network lab using Netlab and Containerlab with VLANs, VRRP, and OSPF. Step-by-step guide for network engineers.
As a veteran network engineer, I have always relied on free tools for my labbing journey. I started with Packet Tracer from Cisco, then moved to GNS3 for network automation labs, which served me well for a long time. But integrating with other systems, like connecting external VMs, was not easy. EVE-NG made that part simpler, and I enjoyed using it, but it demanded heavy resources.
These days I use Containerlab. It is lightweight, flexible, and works smoothly with Docker, so building and managing labs is much faster and less resource hungry. For automation and modern testing, it has become my main choice. Still, the real challenge in all these tools comes after the devices boot up — device provisioning. Spinning them up is easy, but preparing configs and making the devices usable always takes the most effort, to test network automation tools.
Solving the Pain with netlab
netlab is an open-source tool that solves these issues by letting you define your topology at a high level in a simple YAML file. Instead of placing devices in a GUI or repeating base configs, netlab automates device provisioning by generating the Containerlab topology and configurations, including IPs, routing, and custom settings. It works with Containerlab or Vagrant, allowing you to spin up realistic labs in minutes and reproduce them anywhere with ease.
Getting Started with netlab
In this blog, we will leverage Containerlab with the netlab tool, and the requirements are:
To install netlab on an existing system that already has the low-level tools installed, use:
1
python3 -m pip install networklab
For reference, I am running this on an Ubuntu 24.04 desktop with 16 GB of RAM and 4 vCPUs.
If you face any issue with installation, see Manual Virtual Machine Provisioning.
Defining a Topology
Let me share a basic topology and walk you through what will be created.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# topology.yml
---
provider: clab
defaults:
devices:
iol.clab.image: vrnetlab/cisco_iol:17.12.01
nodes:
R1:
device: iol
R2:
device: iol
R3:
device: iol
links:
- R1-R2-R3
This topology will do the following:
- Use Containerlab to deploy the nodes
- Define prefix information for different connections (netlab can do automatically)
- Specify the number of nodes
- Define how the nodes are connected
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
❯ netlab up
┌──────────────────────────────────────────────────────────────────────────────────┐
│ CREATING configuration files │
└──────────────────────────────────────────────────────────────────────────────────┘
[CREATED] provider configuration file: clab.yml
[CREATED] transformed topology dump in YAML format in netlab.snapshot.yml
[GROUPS] group_vars for all
[GROUPS] group_vars for iol
[HOSTS] host_vars for R1
[HOSTS] host_vars for R2
[HOSTS] host_vars for R3
[CREATED] minimized Ansible inventory hosts.yml
[CREATED] Ansible configuration file: ansible.cfg
┌──────────────────────────────────────────────────────────────────────────────────┐
│ CHECKING virtualization provider installation │
└──────────────────────────────────────────────────────────────────────────────────┘
[SUCCESS] clab installed and working correctly
┌──────────────────────────────────────────────────────────────────────────────────┐
│ STARTING clab nodes │
└──────────────────────────────────────────────────────────────────────────────────┘
provider clab: executing sudo -E containerlab deploy --reconfigure -t clab.yml
16:18:14 INFO Containerlab started version=0.69.3
16:18:14 INFO Parsing & checking topology file=clab.yml
16:18:14 INFO Removing directory path=/home/zulu/Documents/demo-lab/clab-demolab
16:18:14 INFO Creating docker network name=netlab_mgmt IPv4 subnet=192.168.121.0/24 IPv6 subnet="" MTU=0
16:18:17 INFO Creating lab directory path=/home/zulu/Documents/demo-lab/clab-demolab
16:18:18 INFO Creating container name=R1
16:18:18 INFO Creating container name=R3
16:18:18 INFO Creating container name=R2
16:18:21 INFO Running postdeploy actions for Cisco IOL 'R1' node
16:18:21 INFO Running postdeploy actions for Cisco IOL 'R3' node
16:18:21 INFO Created link: R1:eth1 (Ethernet0/1) ▪┄┄▪ demolab_1:R1_Ethernet0/1
16:18:21 INFO Running postdeploy actions for Cisco IOL 'R2' node
16:18:22 INFO Created link: R2:eth1 (Ethernet0/1) ▪┄┄▪ demolab_1:R2_Ethernet0/1
16:18:22 INFO Created link: R3:eth1 (Ethernet0/1) ▪┄┄▪ demolab_1:R3_Ethernet0/1
16:18:22 INFO Adding host entries path=/etc/hosts
16:18:22 INFO Adding SSH config for nodes path=/etc/ssh/ssh_config.d/clab-demolab.conf
You are on the latest version (0.69.3)
╭─────────────────┬────────────────────────────┬─────────┬─────────────────╮
│ Name │ Kind/Image │ State │ IPv4/6 Address │
├─────────────────┼────────────────────────────┼─────────┼─────────────────┤
│ clab-demolab-R1 │ cisco_iol │ running │ 192.168.121.101 │
│ │ vrnetlab/cisco_iol:17.12.01 │ │ N/A │
├─────────────────┼────────────────────────────┼─────────┼─────────────────┤
│ clab-demolab-R2 │ cisco_iol │ running │ 192.168.121.102 │
│ │ vrnetlab/cisco_iol:17.12.01 │ │ N/A │
├─────────────────┼────────────────────────────┼─────────┼─────────────────┤
│ clab-demolab-R3 │ cisco_iol │ running │ 192.168.121.103 │
│ │ vrnetlab/cisco_iol:17.12.01 │ │ N/A │
╰─────────────────┴────────────────────────────┴─────────┴─────────────────╯
┌──────────────────────────────────────────────────────────────────────────────────┐
│ DEPLOYING initial device configurations │
└──────────────────────────────────────────────────────────────────────────────────┘
[WARNING]: Could not match supplied host pattern, ignoring: unprovisioned
PLAY [Deploy initial device configuration] ********************************************************************************************************
[WARNING]: Found variable using reserved name: hosts
TASK [Set variables that cannot be set with VARS] *************************************************************************************************
ok: [R3]
ok: [R2]
ok: [R1]
PLAY RECAP ****************************************************************************************************************************************
R1 : ok=17 changed=1 unreachable=0 failed=0 skipped=5 rescued=0 ignored=0
R2 : ok=16 changed=1 unreachable=0 failed=0 skipped=5 rescued=0 ignored=0
R3 : ok=16 changed=1 unreachable=0 failed=0 skipped=5 rescued=0 ignored=0
[SUCCESS] Lab devices configured
SSH into device is simple as below:
1
2
3
4
5
6
7
8
9
10
11
❯ netlab connect R1
Connecting to clab-demolab-R1 using SSH port 22
R1#sh ip int bri
Interface IP-Address OK? Method Status Protocol
Ethernet0/0 192.168.121.101 YES TFTP up up
Ethernet0/1 172.16.0.1 YES manual up up
Ethernet0/2 unassigned YES unset administratively down down
Ethernet0/3 unassigned YES unset administratively down down
Loopback0 10.0.0.1 YES manual up up
R1#
You also don’t need to worry about interface names — the logic in netlab will automatically assign the next available interface.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
❯ netlab down --cleanup
┌──────────────────────────────────────────────────────────────────────────────────┐
│ CHECKING virtualization provider installation │
└──────────────────────────────────────────────────────────────────────────────────┘
[SUCCESS] clab installed and working correctly
┌──────────────────────────────────────────────────────────────────────────────────┐
│ STOPPING clab nodes │
└──────────────────────────────────────────────────────────────────────────────────┘
16:26:28 INFO Parsing & checking topology file=clab.yml
16:26:28 INFO Parsing & checking topology file=clab.yml
16:26:28 INFO Destroying lab name=demolab
16:26:30 INFO Removed container name=clab-demolab-R3
16:26:31 INFO Removed container name=clab-demolab-R1
16:26:31 INFO Removed container name=clab-demolab-R2
16:26:31 INFO Removing host entries path=/etc/hosts
16:26:31 INFO Removing SSH config path=/etc/ssh/ssh_config.d/clab-demolab.conf
┌──────────────────────────────────────────────────────────────────────────────────┐
│ CLEANUP configuration files │
└──────────────────────────────────────────────────────────────────────────────────┘
... removing clab.yml
... removing ansible.cfg
... removing hosts.yml
... removing directory tree group_vars
... removing directory tree host_vars
... removing netlab.snapshot.yml
If you don’t want to remove everything, avoid using the –cleanup flag, as it will also destroy all the files. The netlab tutorials page has dozens of guides describing different features — pick one to get started.
Some command outputs have been omitted for brevity.
Building a Campus Demo Lab
Now that we have Netlab and Containerlab ready, let’s move beyond simple topologies and create something closer to a real-world enterprise network.
To demonstrate, I built a multi-layer redundant campus lab using Netlab. It includes:
- Core Layer: A router for upstream connectivity.
- Distribution Layer: Two distribution switches with VRRP for gateway redundancy and OSPF for routing.
- Access Layer: Two access switches trunked up to the distribution.
- Hosts: Four Linux hosts spread across VLAN 10 and VLAN 20.
This gives us a design that resembles many real production networks, but completely containerized and automated with Netlab.
Topology File
Here’s the topology definition I used (topology.yml
). Netlab will take care of building configs, assigning IP addresses, and wiring everything up:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
provider: clab
defaults:
devices:
iol:
clab:
image: vrnetlab/cisco_iol:17.12.01
ioll2:
clab:
image: vrnetlab/cisco_iol:l2-17.12.01
linux:
clab:
image: alpine:latest
module: [gateway]
vlans:
vlan_10:
id: 10
gateway:
ipv4: 172.16.0.254/24
vlan_20:
id: 20
gateway:
ipv4: 172.16.1.254/24
nodes:
R1:
D1:
config: [configs/D1.j2]
D2:
config: [configs/D2.j2]
S1:
S2:
H1:
H2:
H3:
H4:
groups:
CORE:
members: [R1]
device: iol
role: router
module: [ospf]
DISTRIBUTION:
members: [D1, D2]
device: ioll2
module: [vlan, ospf]
vlan:
mode: irb
ACCESS:
members: [S1, S2]
device: ioll2
module: [vlan]
vlan:
mode: bridge
hosts:
members: [H1, H2, H3, H4]
device: linux
role: host
links:
- R1-D1
- R1-D2
- group: vlan_10
vlan.access: vlan_10
members: [H1-S1, H4-S2]
- group: vlan_20
vlan.access: vlan_20
members: [H2-S2, H3-S1]
- group: access_trunk
vlan.trunk: [vlan_10, vlan_20]
members: [D1-S1, D1-S2, D2-S1, D2-S2]
Deploying the Demo
Once the file is ready, just bring up the lab with:
1
netlab up
Netlab will automatically generate configuration, and merged configs for the distribution switches (using D1.j2
and D2.j2
templates from configs/
) and set up hosts with the right IP addresses.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# D1.j2 Configuration
interface Vlan10
vrrp 10 ip 172.16.0.254
vrrp 10 priority 110
vrrp 10 preempt
interface Vlan20
vrrp 20 ip 172.16.1.254
vrrp 20 priority 100
vrrp 20 preempt
# D2j2 Configuration
interface Vlan10
vrrp 10 ip 172.16.0.254
vrrp 10 priority 100
vrrp 10 preempt
interface Vlan20
vrrp 20 ip 172.16.1.254
vrrp 20 priority 110
vrrp 20 preempt
You can jump (SSH
) into devices with:
1
2
netlab connect D1
netlab connect R1
Verifying the Lab
- VRRP → D1 should be Master for VLAN 10, D2 for VLAN 20.
- Host Connectivity → H1 ↔ H4 (VLAN 10) and H2 ↔ H3 (VLAN 20) should ping.
- Routing → H1 should be able to ping H2 across VLANs.
- OSPF → R1, D1, D2 should form OSPF adjacencies.
That’s where Netlab comes in. Instead of manually dragging devices or repeating configs, you can define your entire lab in a simple YAML file. Netlab automatically provisions devices, assigns IPs, builds topologies, and pushes configs, saving huge amounts of time.
To demonstrate this, I walked through a campus-style demo lab with a core router, redundant distribution switches running OSPF and VRRP, access switches carrying VLANs, and Linux hosts. With a single netlab up command, the full environment spins up—ready for testing inter-VLAN routing, gateway redundancy, and routing adjacencies.
Whether you’re a student, a professional, or just curious about automation-driven labs, Netlab makes it easy to build and share realistic topologies in minutes.