Mininet SDN Lab Environment with Custom Python Topologies
I built reproducible SDN test environments with the Mininet Python API, defining custom multi-switch topologies that spin up on demand against a remote controller. Codifying topologies made OpenFlow and controller experiments repeatable and disposable.
Objective & Context
Mininet emulates real networks with lightweight namespaces and Open vSwitch, so an entire fabric runs on one host. This lab uses the Python API to script topologies, providing the reproducible substrate for the SDN concepts, OpenFlow, and controller labs.
Learning Objectives
- Describe a network topology with the Mininet Python API (hosts, switches, links).
- Launch the topology against a remote SDN controller with root privileges.
- Validate full reachability between hosts with pingall.
- Explain how Mininet uses namespaces and Open vSwitch to emulate a fabric.
- Reuse the topology as the substrate for OpenFlow and controller experiments.
Environment & Prerequisites
Prerequisites
- Mininet with Open vSwitch; Python 3.
- A remote controller (Ryu/ONOS) for non-trivial topologies.
- Root privileges (Mininet manipulates namespaces).
- Mininet installed with Open vSwitch (sudo apt install -y mininet openvswitch-switch).
- Python 3 for the topology script.
- A remote controller (Ryu or ONOS) listening on 127.0.0.1 for non-trivial topologies.
- Root privileges: Mininet creates network namespaces and veth pairs.
- Basic Python and switching concepts.
Step-by-Step Execution
1. Define a topology with the Python API
Expected output:
from mininet.topo import Topo
class TwoSwitch(Topo):
def build(self):
s1, s2 = self.addSwitch('s1'), self.addSwitch('s2')
self.addLink(s1, s2)
self.addLink(self.addHost('h1'), s1)
self.addLink(self.addHost('h2'), s2)
topos = {'two': (lambda: TwoSwitch())}
What this teaches: the Python API turns a topology into version-controlled code instead of a pile of manual commands.
2. Launch against a remote controller [PRIVILEGED]
sudo mn --custom topo.py --topo two --controller remote,ip=127.0.0.1Expected output:
*** Creating network
*** Adding controller
*** Adding hosts:
h1 h2
*** Adding switches:
s1 s2
*** Adding links:
(h1, s1) (h2, s2) (s1, s2)
*** Configuring hosts
h1 h2
*** Starting controller
*** Starting 2 switches
s1 s2 ...
*** Starting CLI:
mininet>
What this teaches: Mininet needs root because namespaces, veth pairs, and OVS bridges are privileged kernel operations.
topo.py must be in the current directory (or give --custom the full path). The remote controller target 127.0.0.1:6653 assumes your controller listens locally; start it first, then verify the switch connected with: sudo ovs-vsctl get-controller s1.
3. Validate full reachability
mininet> pingallExpected output:
*** Results: 0% dropped (2/2 received)
What this teaches: pingall is the fastest smoke test that every host can reach every other host through the emulated fabric.
How It Works
Mininet builds each virtual host as a Linux network namespace: a separate network stack with its own interfaces, addresses, and routing table, but sharing the host kernel. Switches are Open vSwitch bridges in the root namespace, and hosts attach to them through veth pairs, which behave like a virtual Ethernet cable with one end in each namespace.
Because everything runs in the real kernel, the emulated network behaves like real hardware for most purposes: packets traverse real OVS datapaths, real iptables rules apply, and real applications run unmodified on the virtual hosts. The main limitation is performance: all virtual hosts share the host CPU, so Mininet is for functional testing, not throughput benchmarking.
The remote controller option is what makes Mininet an SDN lab. Instead of learning MAC addresses on their own, the OVS switches connect to an external controller over OpenFlow, so forwarding behavior is decided by controller software. This is the substrate the SDN concepts, OpenFlow, and controller labs all build on.
Validation & Testing
Run pingall and iperf within the emulated topology to confirm connectivity and link behaviour. Pass criteria: 0% drop with the controller present and a clean teardown via mn -c.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| mn fails with permission errors | Mininet was run without root | Run with sudo; namespace and OVS operations require privileges |
| Switches never connect to the controller | Controller not listening or wrong IP/port | Confirm the controller is up and the topology points at the right address (default 127.0.0.1:6653) |
| pingall shows packet loss | Host CPU oversubscribed by too many virtual nodes | Reduce the topology size or raise link delays; Mininet shares one kernel scheduler |
| Cleanup errors after a crash (RTNETLINK exists) | A previous run left namespaces and OVS bridges behind | Run sudo mn -c to wipe stale state before relaunching |
| Custom topology import fails | Python path or class name mismatch in the -custom argument | Check that the file defines the class named in -topo and is importable from the working directory |
Advanced: Troubleshooting
- Stale state errors: always
mn -cbetween runs to clear namespaces and OVS bridges. - No connectivity: a remote controller must be running or hosts have no flows.
- Link params ignored: use TCLink to apply bandwidth/delay.
Key Results
- Scripted reproducible multi-switch topologies that deploy in seconds.
- Provided the disposable substrate for 3 dependent SDN labs.
- Achieved 0% packet drop in controller-managed reachability tests.
- Standardized clean teardown to prevent cross-run contamination.
Key Takeaways
- Script topologies in Python so experiments are reproducible and reviewable.
- Always sudo mn -c after a crash to clear stale namespaces.
- Mininet is for functional correctness, not performance measurement.
- One topology file can serve every SDN lab in this series.
Practice Challenges
Challenge 1: Build a 3-tier topology
Goal: Write a Python topology with core, aggregation, and access layers plus redundant links, then validate with pingall.
Hint: Subclass Topo, add switches in a loop, and link each layer to the one above it twice.
Challenge 2: Rate-limit a link
Goal: Apply a 10 Mbit/s cap with 10 ms delay to one link using TCLink and show the effect with iperf.
Hint: Pass cls=TCLink and bw=10, delay='10ms' in addLink, then run iperf between the hosts.