2. lwIP — Lightweight IP
lwIP is a small, independent implementation of the TCP/IP protocol suite, designed for embedded systems with limited resources.
2.1. Integration of lwIP in SO3
The port of lwIP to SO3 was originally done by Julien Quartier as a Diploma work.
The stack lives under net/lwip/ and provides TCP, UDP, IPv4/IPv6 and a DNS
resolver.
SO3 exposes a BSD-style socket API to user space: the net/ glue maps VFS
file descriptors onto lwIP sockets so that socket(), bind(),
connect(), send() and recv() work from applications. The network
interface driver lives in devices/net/ — currently an smc911x
(smsc,smc911x) MAC. See the networking section of the kernel
chapter.
Note
Networking is opt-in: CONFIG_NET plus CONFIG_SMC911X. Both are on
in the four QEMU virt defconfigs (virt32/virt64, plain and _fb),
and off everywhere else — rpi4 and verdin have no driver for their own MAC
yet.
2.2. The NIC on QEMU virt
QEMU’s stock virt machine offers only virtio-net, which SO3 has no driver
for. The so3 QEMU patch therefore adds an SMSC LAN9118 to the machine model,
next to the PL111/PL050 devices it already adds:
MMIO base
0x08804000(VIRT_ETHin thehw/arm/virt.cmemmap,ethernet@08804000indts/virt{32,64}.dts);interrupt SPI 15 (
irqmap[VIRT_ETH], andinterrupts = <0 15 4>in the same DT nodes).
Two details are worth knowing. The MAC is not at the 0x1a000000 the SO3
device trees inherited from vexpress-a15: that address is inside the PCIe MMIO
window, whose gpex alias covers the whole range and shadows anything mapped
underneath, so the guest read back nothing and never detected the chip. And it
is only instantiated when the command line fills the legacy on-board NIC slot
(-nic/-net); without it the machine is exactly as it was and
smc911x_detect_chip() simply fails.
2.3. Trying it out
ping exercises the stack end to end:
/ % ping -c 6 10.0.2.2
64 bytes from 10.0.2.2: icmp_seq=1 ttl=255 time=6.497070 ms
64 bytes from 10.0.2.2: icmp_seq=2 ttl=255 time=0.601074 ms
...
6 packets transmitted, 6 received, 0.000000% packet loss
st.sh attaches two NICs on user-mode (slirp) networking — QEMU itself
plays DHCP, DNS and NAT, so nothing has to be set up on the host and no sudo
is needed. The LAN9118 (-nic user,model=lan9118) is the one SO3 drives; the
virtio-net device is there for the Linux agency of the AVZ boot chain, and
carries the host port 2222 → guest port 22 forward. Each guest ignores
the NIC it cannot drive. The trade-off of slirp is that the guest is NAT’d and
not reachable from the LAN. (scripts/qemu-ifup.sh / qemu-ifdown.sh are
leftovers from the earlier tap-and-bridge setup and are no longer used.)
The interface comes up by DHCP during netif_add(), so the address is
announced on the console shortly after boot:
Network Interface Controller (NIC) found LAN9118
smc911x: detected LAN9118 controller
IP Network up and running with address 10.0.2.15
Pinging past the slirp gateway (10.0.2.2) needs the host to let QEMU
open ICMP sockets, otherwise slirp emulates the echo over UDP and relays back
the port-unreachable it gets:
From 192.168.1.1 icmp_seq=1 Destination Port Unreachable
The kernel decides that with net.ipv4.ping_group_range, whose default on
several distributions is the empty range 1 0. Widening it (sysctl -w
net.ipv4.ping_group_range="0 2147483647") lets slirp forward the echo for
real. Nothing in SO3 is involved either way.
Note
The RX Status Level the driver programs into FIFO_INT must be 0: the
controller raises the RSFL interrupt when the RX status FIFO holds more
entries than that level, so a level of 1 only interrupts once a second frame
has arrived, and every reception stays one frame behind.