BSc Dissertation — Networking Systems
Building a Router Kernel
from Bare Metal
LazyDaysOS is evolving from a hobby x86 kernel into a GNS3-deployable IPv4 packet forwarding appliance — written entirely in C and Assembly, with zero external dependencies.
BSc Dissertation Title
"Design and Implementation of a Minimal IPv4 Packet Forwarding Kernel
Deployable as a GNS3 Network Appliance"
The research question: Can a purpose-built bare-metal kernel, written from scratch in C and x86 Assembly, perform correct IPv4 unicast forwarding and be integrated as a functional appliance in the GNS3 network simulation platform?
"Unlike Linux-based router images, this kernel has zero abstraction overhead between the NIC interrupt and the forwarding decision — every byte of the path is authored and understood."
1 Development Phases
✓
Protected mode switch, 5-entry GDT, 256-entry IDT with PIC remapping, identity-mapped 4 MiB page table, VGA terminal, PS/2 keyboard input.
boot.s
gdt.c
idt.c
vm_watchdog.c
tty.c
0
A bump allocator over the free physical pages above the kernel image. Required for dynamic packet buffer management — without this, variable-length Ethernet frames cannot be managed safely. This is the critical unlocker for all networking work.
kmalloc.c
page_frame_alloc.c
lazy$block integration
1
IRQ-driven receive ring buffer, DMA transmit. QEMU emulates the RTL8139 (PCI device 0x10EC:0x8139) — the simplest documented NIC available. PCI bus enumeration to discover base I/O address. Hooks into the existing isr_map[] dispatch.
pci.c
rtl8139.c
net_buf.c
IRQ 11
2
Parse incoming Ethernet frames: extract EtherType, handle ARP requests (build reply with kernel MAC/IP), parse IPv4 headers (version, TTL, checksum, src/dst). Maintain a small static ARP table (array of 16 entries).
eth.c
arp.c
ipv4.c
arp_table[16]
3
Respond to ICMP Echo Request (type 8) with Echo Reply (type 0). Recalculate checksum. This is the first live network demo milestone — a ping reply from a kernel you wrote from scratch is a compelling visual proof of concept for any examiner.
icmp.c
checksum.c
ping demo
4
Array of {dest_net, mask, gateway, iface} route entries. On receive: look up destination, decrement TTL, rewrite Ethernet header (ARP lookup for next-hop MAC), transmit on correct interface. Core dissertation deliverable.
routing.c
route_table[32]
TTL decrement
checksum update
5
Build a .qcow2 QEMU disk image from the kernel ISO. Author the lazydaysos.gns3a appliance descriptor JSON (QEMU args: -netdev user, -device rtl8139 ×2). Import into GNS3 — kernel boots and appears as a router node in any topology.
lazydaysos.gns3a
lazydaysos.qcow2
build_appliance.sh
S
Full PCI bus scan to discover a second RTL8139 at a different slot. True two-interface forwarding — packets entering eth0 forwarded out eth1. Transforms the kernel from a network host into a genuine layer-3 router.
pci_scan.c
eth0 / eth1
multi-iface routing
2 Packet Forwarding Path
How a packet travels from NIC interrupt to retransmission — every step runs in kernel ring 0, no OS calls, no drivers, no libc.
→ [RTL8139 IRQ] NIC fires IRQ 11 — packet placed in RX ring buffer
→ [isr.c] interrupt_handler() dispatches to rtl8139_rx_handler()
→ [eth.c] Parse Ethernet frame: EtherType 0x0800 = IPv4, 0x0806 = ARP
→ [arp.c] ARP request? Build reply. Update local ARP table arp_table[16]
→ [ipv4.c] Parse IPv4 header. Verify checksum. Extract dst_ip
→ [routing.c] Longest-prefix match in route_table[32] → select next_hop + iface
→ [ipv4.c] Decrement TTL. Recompute IP checksum. Drop if TTL = 0 (no ICMP Time Exceeded yet)
→ [arp.c] Resolve next_hop MAC from ARP table. Send ARP request if unknown
→ [rtl8139.c] Write Ethernet frame to TX descriptor. Issue outb(TxAddr, buf). Done. ~1–2 µs
3 Technology Stack
⚙️
i686-elf GCC
Freestanding cross-compiler, no libc, no CRT
🔗
GNU LD
Custom linker script, ELF output at 1 MiB
🥾
GRUB 2
Multiboot2 loader, ISO 9660 image
🖥️
QEMU i386
Emulates RTL8139 NIC, PCI bus, x87 FPU
🌐
GNS3
Network simulation, QEMU appliance import
🔌
RTL8139
Simplest documented NIC, 10/100 Mbps, DMA TX
4 Milestone Timeline
Completed
M0 — Kernel Foundation
Boot, protected mode, GDT, IDT, paging, VGA terminal, keyboard input. All subsystems self-tested at powerup via util$self_test().
Phase 0 — Immediate
M1 — Heap Allocator
Implement kmalloc/kfree bump allocator. Validate with existing lazy$block test framework. Unlocks all dynamic data structures.
Phase 1–2
M2 — Kernel replies to ping
RTL8139 driver receives frames. ARP reply working. ICMP Echo Reply sent. Demonstrate: ping 10.0.1.1 from a QEMU-connected host gets a reply from the kernel.
Phase 4–5
M3 — GNS3 Appliance Demo
LazyDaysOS imported into GNS3 as a QEMU appliance. Two VPCS nodes connected through it. ping from VPCS-A reaches VPCS-B via the kernel's routing table. Core dissertation deliverable.
Stretch Goal
M4 — Dual NIC True Routing
Full PCI enumeration discovers second RTL8139. Packets forwarded between eth0 and eth1. Dynamic ARP resolution per interface. Future dissertation extension or MSc follow-on.