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.

~2K
Lines of C/ASM
5
Dev Phases
0
External Libs
RTL8139
Target NIC

Target GNS3 Topology

🖥️
PC-A
10.0.1.2/24
⚙️
LazyDaysOS
eth0 10.0.1.1
🖥️
PC-B
10.0.2.2/24
Packet from PC-A → LazyDaysOS forwards → PC-B  |  GNS3 via QEMU appliance (.gns3a)
GNS3 Appliance Node View
💻
VPCS-A 10.0.1.2/24
gw 10.0.1.1
🔧
LazyDaysOS QEMU i386
RTL8139 ×2
Runs as QEMU appliance — import lazydaysos.gns3a into GNS3
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

Foundation — Boot, GDT, IDT, Paging COMPLETE

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
Heap Allocator — kmalloc / kfree PREREQUISITE

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
RTL8139 NIC Driver NEXT

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
Ethernet + ARP + IPv4 Parser NEXT

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
ICMP Echo — Make the Kernel Pingable NEXT

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
Static Routing Table + Packet Forwarding NEXT

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
GNS3 Appliance Packaging NEXT

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
Stretch — Dual NIC + PCI Enumeration STRETCH GOAL

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.