featured image

PWOSPF Router: Bridging Classical Networking and Modern SDN with Interactive Virtualization

Building a production-grade network router that implements the Routing Information Protocol (RIP) using low-level C, integrated it with Software-Defined Networking (SDN) through OpenFlow, and packaged everything into an interactive, browser-based simulation environment.

Published

Sun Mar 22 2026

Technologies Used

C Docker Mininet OpenFlow Flask Python
View on GitHub

Live Demo

Loading demo...

Making Network Protocols Visible

Network engineering education has a persistent problem: testing routing behaviors is expensive, time-consuming, and risky. Physical routers cost thousands of dollars. Lab setups require dedicated space. Configuration errors can disrupt production networks. Students learn routing concepts through static diagrams and theoretical explanations without ever seeing how these protocols behave in a living, evolving system.

This project is a complete virtualized network environment that behaves like real hardware but runs entirely in software. A three-router topology spins up in seconds. Link failures are injected with a single click. Routing tables converge in real time, visible in a browser-based dashboard. I built it to make learning and experimentation accessible — not “accessible with an hour of setup,” but accessible from a browser tab.

What the System Does

The router core is a from-scratch C implementation of RIP routing with full support for ARP resolution, ICMP messaging, IPv4 forwarding with TTL management, and dynamic routing table updates. It handles real packet processing — validating checksums, performing longest-prefix matching, managing ARP caches with timeout mechanisms, and generating proper ICMP error messages when destinations are unreachable or TTL expires.

A POX-based OpenFlow controller manages virtual switches and coordinates packet flow between routers and hosts. This separates the control plane (routing decisions) from the data plane (packet forwarding) — a clean demonstration of how modern SDN architectures work alongside traditional routing protocols.

The Flask-powered web interface provides real-time visibility into network behavior through an SVG topology visualization that updates link states live. Users can generate traffic (ping, traceroute, HTTP requests) between any nodes, inject link failures to test convergence, and interact directly with the Mininet environment through an integrated terminal. Fifteen comprehensive test cases validate everything from basic connectivity to complex failure scenarios involving multiple simultaneous link failures and convergence timing requirements.

Why C, Why the Python Split, Why Privileged Docker

C for the router core. Router performance depends on tight control over memory layout. Network packet headers are precisely defined byte structures — Ethernet frames, IP headers, UDP/TCP segments — and C’s struct packing and pointer arithmetic provide exact control without runtime overhead. Production routers use C or C++ for their data planes; this implementation provides realistic exposure to actual networking codebases. When debugging packet-level issues, tools like Wireshark and tcpdump integrate naturally with C programs through standard packet capture libraries.

The Python 2.7 / Python 3.x split. Mininet and POX both depend on Python 2.7, which reached end-of-life in 2020 but remains essential for many network simulation tools due to their deep dependency chains. Rather than attempting a risky migration or forking upstream projects, I isolated the legacy components (control plane) from the modern ones (web dashboard). The Flask web server runs in Python 3.x with Socket.IO and eventlet for real-time updates, while the POX controller operates in its native Python 2.7 environment. This demonstrates a practical systems integration skill: knowing when to bridge incompatible components rather than force unnecessary rewrites.

Docker with privileged mode. Network virtualization with Mininet requires low-level kernel operations: creating network namespaces, manipulating virtual interfaces, managing Open vSwitch kernel modules. These operations require Linux capabilities that standard Docker containers don’t provide. Running in privileged mode grants the container necessary permissions. For a development and education tool where reproducibility and ease of deployment matter more than multi-tenant isolation, this is the right trade-off. One docker run command gives users a complete, working network lab that would otherwise require hours of manual configuration.

Coordinating Three Asynchronous Subsystems

The most architecturally complex part of the system is timing coordination between three asynchronous subsystems: the C routers exchanging RIP updates, the OpenFlow controller managing switch state, and the web dashboard displaying real-time updates.

Distance-vector routing protocols like RIP are inherently asynchronous and timing-dependent. When a link fails, routers don’t discover this instantly — they rely on periodic updates (every 30 seconds in standard RIP) and timeout mechanisms. During convergence, routing tables may temporarily contain inconsistent information as updates propagate hop-by-hop. If the web dashboard queries routing state too early, it shows incomplete data. If test cases don’t wait long enough after injecting failures, they produce false negatives.

I addressed this through a three-tier timing coordination strategy. At the lowest level, the C router uses a timeout thread that wakes every second to check for expired ARP cache entries and trigger RIP request/response cycles. The POX controller maintains OpenFlow connection state machines, responding immediately to switch events but coordinating with router startup through a ten-second warmup period that ensures all OpenFlow handshakes complete before routers attempt packet forwarding. At the application level, the automated test framework explicitly sleeps for 30 seconds after topology initialization and after each link state change, allowing sufficient time for RIP convergence before validation begins.

The web dashboard embraces the reality of eventual consistency by showing real-time state regardless of convergence status, letting users observe the convergence process itself rather than hiding it behind synchronization barriers. That’s actually more educational — watching routing tables settle is the whole point.

The ARP-IP interaction added another layer of subtlety. When the router needs to forward a packet but doesn’t have the destination’s MAC address cached, it must queue the IP packet, send an ARP request, wait for the reply, then forward the original packet. This requires careful state management: tracking which packets are waiting on which ARP resolutions, implementing timeouts for unanswered ARP requests, and generating appropriate ICMP “destination unreachable” messages when resolution fails. The implementation uses a linked-list queue structure attached to each ARP cache entry.

What Building This Taught Me

Polyglot systems live or die at their interfaces. The hard part wasn’t writing code in multiple languages — it was designing clean interfaces between them. The VNS protocol serves as a binary message boundary between C and Python, using explicit length-prefixed packets with defined message types. The Flask Socket.IO layer provides a JSON-based boundary between Python and JavaScript, using event names as method contracts. Each boundary point is a potential failure mode, so I invested heavily in logging and error handling at crossing points.

Reproducibility is a feature. Before Docker, running this project required installing specific versions of Mininet, compiling Open vSwitch with correct flags, managing Python 2 and 3 simultaneously, and hoping your kernel supported the necessary network namespaces. Every environment was slightly different, producing subtle bugs that appeared on some machines but not others. Containerization eliminated that entire class of problem. The Dockerfile isn’t just deployment automation — it’s executable documentation of the exact environment the software expects.

UX matters even for technical tools. Early versions required five terminal windows, a specific startup order, and manual IP configuration. The web dashboard changed everything. The integrated terminal eliminated the need to SSH into containers. The visual topology made abstract routing concepts concrete. One-click fault injection made testing convergence trivial instead of tedious.

What’s Next

Real-time performance observability. The dashboard shows topology state but lacks quantitative metrics. Adding real-time graphs for packet rate, routing table size, convergence time, and bandwidth utilization would turn this from a binary “working/not working” tool into a platform for performance analysis.

Modern protocol support. The current implementation uses OpenFlow 1.0 (circa 2009) because of POX’s limitations. Migrating to OpenFlow 1.3+ would enable multi-table pipelines, more flexible matching, and meter-based QoS — features that reflect how modern SDN deployments actually work.

Cross-protocol comparison. Adding OSPF and potentially BGP would create a compelling comparative learning environment. Students could watch the same link failure propagate through RIP’s slow hop-by-hop convergence versus OSPF’s near-instant LSA flooding — building intuition about protocol trade-offs that textbooks can only describe abstractly.

RESTful testing API. Exposing network operations (create topology, inject failure, verify path) through a REST API would enable integration with CI/CD pipelines, property-based testing frameworks, and classroom autograders. Students could submit routing implementations that get automatically tested against a failure scenario suite.

Try It Out

Check out the live demo or explore the source code on GitHub.

We respect your privacy.

← View All Projects

Related Tutorials

    Ask me anything!