What you can learn

A topology costs a few lines of text and a few seconds. Nothing on your machine is touched. When you have broken it beyond repair you type del all and build it again.

Nothing here is a simulation

A lan is an Open vSwitch bridge. A kvm guest has its own kernel. A cnt guest is a real container with a real network stack. The routing daemons are the ones a carrier runs, and they do not know they are in a demo. When OSPF reconverges after you cut a cable, that is OSPF reconverging.

The daemons, the kernels and the frames are those of real machines: a configuration works or fails in cloonix for the reason it does on them, the timing of the hardware aside (What cloonix is not, below).

The loop

Every demo leaves the network running when it ends, so the topology it built is there to be changed, broken and captured after the last line of the script.

1. Run it cloonix cli nemo demo 2. Look dump drawing 3. Break it unplug, cnf A2B 4. Capture cnf sniff=, sniff 5. Explain two wires, one packet change one line of the script and run it again

The demos are chosen for failure modes where the symptom names a different layer than the cause. Stop OSPF in the dns demo and name resolution stops: the symptom is DNS, the cause is routing. Leave out the discard route in frrmix and every BGP session comes up, reports itself established, and carries nothing.

The one habit: catch the packet

A counter inside a guest reports what that guest believes; a capture reports what crossed the wire. Cloonix puts a sniffer on any capturable interface and hands back only what matches a filter — and the filter is applied on the server, so what does not match never crosses the wire to you.

an interface eth=1, green cloonix-ovs-snf one copy, many readers the filter applied here webshark, in the browser wireshark dissectors, no Qt cloonix cli <net> sniff ... --dump  --bytes  --line cloonix cli nemo cnf gwA eth1 sniff=on    then    cloonix cli nemo sniff gwA eth1 --dump udp port 51820

Two subscriptions with the same filter, one on each side of a tunnel or a translation, is the standard way here of showing that something was encrypted, dropped or rewritten. The grammar is a subset of tcpdump's, and its limits are part of what it shows: below IP it knows arp alone, so a demo about EAPOL or batman OGMs says so and captures unfiltered rather than inventing a filter that cannot exist.

The catalogue

Subject areas, then one python file per demo: demos/<area>/<demo>.py. The docstring at the top of each one says what the software is and what the demo does with it, then the topology as ascii art, then the packet to catch. Its first line is what the Demo panel of the canvas shows beside the name.

cloonix/cnt.pytwo containers on one lan and a ping: the nine lines of the first run, played by a program
cloonix/kvm.pythe same with two virtual machines
cloonix/a2b.pythe cable that can be told to be bad: delay, loss and rate, measured on both wires
cloonix/c2c.pythree servers, two c2c cables, one router between two subnets, and a ping that crosses them
cloonix/nat.pypasst: the dhcp answer, the way out, and the loopback of the host reached from inside
cloonix/nginx.pya published port: a web page served from a container with no address on the host
cloonix/snf.pyone noisy lan, four filters, four counts
cloonix/mount.pya host directory inside two containers with vmount=, one image in two roles with startup_env=, and what a delete leaves behind
cloonix/limit.pycnf cpu= ram=: a cpu and ram cap put on a running container and measured from inside its cgroup
cloonix/systemd.pyone container with an init beside two without, and the inotify margin of the host
cloonix/cntwifi.pymac80211_hwsim, hostapd, wpa_supplicant — and no wire at all
cloonix/cntkvmwifi.pya container radio and a kvm radio on one air, suid-power the medium of both
cloonix/kvmwifi.pymac80211_hwsim of the guest kernels, the cloonix agent carrying the frames to suid-power, the medium of every air
cloonix/phy.pya real interface taken into a net, absorbed on one kvm, macvlanned on the other, each running its own cloonix; the kvm without its eth0 still carries a container's pings
cloonix/realnet.pya cloonix inside a kvm: a guest of the inner net becomes a station of the outer lan through a tap and a bridge
switching/vlan.pyone trunk, two networks, and a tag that hides every filter above the link layer
switching/stp.pya loop, the storm it makes, and the protocol that blocks one port
routing/frrspider.py frrspider_bgp.py frrmix.pysixty OSPF routers, the same sixty in BGP, then four AS with OSPF inside and BGP between
address/dhcp.pykea, two lans, one server, and giaddr deciding the subnet
address/ipv6.pyzebra: a router advertisement, and hosts that make their own address
address/dns.pybind9 and frr: a name that only resolves if OSPF is up
availability/vrrp.pykeepalived: two routers, one address, and a gratuitous ARP
security/nftables.pya stateful filter, masquerade, dnat, and the counter that says which rule matched
security/tls.pyopenssl: one page over http and over https, and the bytes of both on the lan
security/wg.pywireguard: the same taps as every other demo, and a wire that goes blank
services/proxy.pyhaproxy: one request, two connections, and a health check
services/smtp.pypostfix: an MX lookup, then a conversation in plain text
services/mqtt.pymosquitto: one message in, several out
services/asterisk.pya PBX, two SIP phones, and calls that carry audio
address/knot.pyan authoritative server and the zone transfer that feeds a second
address/ntp.pya client disciplining its clock to a server with chrony
address/unbound.pya resolver that answers, caches, and can be caught doing it
availability/cluster.pytwo nodes, one service, and a failover when one dies
routing/isis.pythe link-state protocol of the carriers, in frames with no IP header
routing/babel.pydistance-vector routing that reroutes when a link comes and goes
routing/batman.pya mesh that routes at layer 2, below IP entirely
routing/bird.pythe other routing daemon: OSPF the same, in a different program
security/arp.pydsniff: arp poisoning, a machine put in the middle, and the static entry that stops it
security/ebpf.pya program loaded into the kernel to drop packets at the wire
security/ipsec.pyan encrypted tunnel between two different implementations
security/openvpn.pya point-to-point tunnel with one shared key
security/radius.pya server that says yes to the right password and no to the wrong
security/suricata.pyan intrusion sensor that alerts on traffic it is told to watch
security/tinc.pya small mesh vpn where each node knows the others
services/squid.pya caching proxy that speeds up hits and enforces a policy
switching/vxlan.pyiproute2: a layer 2 network carried over a routed core in udp 4789
switching/ovn.pyone logical switch spread across two hosts by an overlay
watching/perf.pyiperf3 and mtr over a cable that is degraded step by step
wifi/cnt_*.py kvm_*.py cntkvm_*.pyhostapd and wpa_supplicant: open, WPA2, WPA3, a bridge, roaming, a mesh, a home box, WPA2-Enterprise, a listener in monitor mode
windows.pya windows server guest, its firewall, and the ping it answers only when told to
freebsd.pya freebsd guest with the agent on a disc of its own
cisco.pythree ios-xe routers driven over their serial console

The cloonix area is the platform under itself rather than a third party: the two first networks, an impairment cable, a server-to-server link, the way out of an isolated network, a cloonix inside a kvm, the capture path, and the emulated radios.

A course through it

Twelve packages, each a few demos on one subject, ordered so that a package uses only what the ones before it showed. On every step: run the demo, read the canvas and its History popup, catch the packet, break one thing and repair it. The chapter Learning with cloonix of the user book gives each package its steps, its packet and its break.

0 first net 1 cloonix items 2 one wire 3 addresses 4 routing 5 tunnels 6 the edge 7 services 8 failover 9 overlays 10 wifi 11 other guests on every step 1 run the demo 2 read the canvas and the History popup 3 catch the packet with sniff 4 break one thing, watch, repair
packagedemoswhat it shows
0The first networkcloonix/cnt.py cloonix/kvm.pyadd, plug, ssh, sniff, del all
1The cloonix itemscloonix/a2b.py snf.py nat.py c2c.py nginx.py mount.py limit.py systemd.py cntwifi.py kvmwifi.py cntkvmwifi.pya shaped wire, the capture, the way out, three nets joined, the way in, mounts and caps, an init, the radios
2One wireswitching/vlan.py stp.py802.1Q tags, a loop and spanning tree
3Addresses, names, timeaddress/dhcp.py ipv6.py dns.py unbound.py knot.py ntp.pya relay, an address made from an advertisement, udp 53 and tcp 53, udp 123
4Routingrouting/frrspider.py frrspider_bgp.py frrmix.py bird.py isis.py babel.py batman.pyOSPF, BGP, redistribution, a second daemon, IS-IS, rerouting, a layer 2 mesh in the kernel
5Encryption and tunnelssecurity/tls.py wg.py openvpn.py tinc.py ipsec.pyhttps beside http, then what the middle wire shows before and after a tunnel
6The edgesecurity/nftables.py suricata.py ebpf.py radius.py arp.pyfilter, inspect, drop in the kernel, authenticate, and arp poisoning
7Servicesservices/proxy.py squid.py smtp.py mqtt.py asterisk.pyproxies, mail, publish and subscribe, a phone call
8Staying upavailability/vrrp.py cluster.pyan address that moves, a service that fails over
9Overlays and the real networkswitching/vxlan.py ovn.py cloonix/phy.py realnet.py watching/perf.pya layer 2 net over a routed core, Geneve, a real interface taken in, a cloonix inside a kvm, where the throughput goes
10Wifiwifi/cnt_*.py kvm_*.py cntkvm_*.pyan open air, WPA2, WPA3, a bridge, roaming, a mesh, a home box, a login per user, a listener
11Other guestsfreebsd.py windows.py cisco.pya BSD with the agent, a windows desktop, a router on its console

What cloonix is not

It emulates a network, not hardware. Forwarding at line rate, ASIC behaviour, optics, anything where the timing of the silicon is the subject — those are outside it. An a2b shapes a cable enough to show what TCP does about a bad line; it is not a channel model. The wifi radios are mac80211_hwsim: the 802.11 state machine is real, association and EAPOL are real, the propagation is not.

Get started Read the documentation