|
| 1 | +<!-- |
| 2 | + Copyright 2025, UNSW |
| 3 | + SPDX-License-Identifier: CC-BY-SA-4.0 |
| 4 | +--> |
| 5 | + |
| 6 | +# Ethernet Driver VM Example |
| 7 | + |
| 8 | +This example demonstrates an Ethernet driver VM running with sDDF's echo server on the Odroid C4. It is |
| 9 | +a shallow copy that only contains files that needs to be modified to accomodate the Ethernet driver |
| 10 | +VM. |
| 11 | + |
| 12 | +The only files that we copied from the echo server is `echo.mk` and `meta.py` to accomodate the VM. |
| 13 | + |
| 14 | +The idea is we have a userspace program in Linux that converts sDDF's network TX/RX into |
| 15 | +corresponding syscalls in a Linux raw socket. |
| 16 | +- The sDDF network control, data regions and notification from virtualisers are mapped into Linux |
| 17 | + userspace via UIO. |
| 18 | +- A promiscuous socket is opened to sniff all incoming frames. When a frame comes through from the |
| 19 | + socket, we enqueue the data into the appropriate sDDF queues and fault on a pre-determined address |
| 20 | + so the VMM can notify the RX virtualiser. |
| 21 | +- When a client wants to transmit data, we will get TX virt notifications via UIO, then we simply |
| 22 | + write the data out into the socket. |
| 23 | + |
| 24 | +Even though we already have a native Ethernet driver for Odroid C4, this example is still useful as |
| 25 | +it could be used to provide Ethernet driver VM on new boards or further developed into a |
| 26 | +WiFi/Cellular/Bluetooth driver VM. |
| 27 | + |
| 28 | +The example currently works on the following platforms: |
| 29 | +* HardKernel Odroid-C4 |
| 30 | + |
| 31 | +Things to note when using the network UIO driver: |
| 32 | +- You need to map in the control queues as uncached in the guest and native virtualisers. This is |
| 33 | + because Linux treats UIO regions as device memory thus map them uncached to userspace. |
| 34 | + |
| 35 | +## Compilation |
| 36 | +To compile this example, run: |
| 37 | +``` |
| 38 | +make MICROKIT_SDK=<absolute path to SDK> MICROKIT_BOARD=odroidc4 MICROKIT_CONFIG=release |
| 39 | +``` |
| 40 | + |
| 41 | +### Boot |
| 42 | +On a successful boot, your console will look like this: |
| 43 | +``` |
| 44 | +1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 |
| 45 | + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 |
| 46 | +2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq qlen 1000 |
| 47 | + link/ether 00:1e:06:4a:35:e4 brd ff:ff:ff:ff:ff:ff |
| 48 | +[ 3.716293] meson8b-dwmac ff3f0000.ethernet eth0: Link is Up - 1Gbps/Full - flow control off |
| 49 | +[ 5.753497] random: crng init done |
| 50 | +UIO(NET): *** Starting up |
| 51 | +UIO(NET): *** Network interface: eth0 |
| 52 | +UIO(NET): *** Setting up raw promiscuous socket |
| 53 | +[ 10.669821] meson8b-dwmac ff3f0000.ethernet eth0: entered promiscuous mode |
| 54 | +UIO(NET): *** Creating epoll |
| 55 | +UIO(NET): *** Binding socket to epoll |
| 56 | +UIO(NET): *** Setting up data passing page via UIO |
| 57 | +UIO(NET): -> mapped device 'uio0' with size 0x1000 @ 0xffff8454d000 |
| 58 | +UIO(NET): -> rx data paddr = 0x5feff000 |
| 59 | +UIO(NET): -> tx client #0 data paddr = 0x5fdff000 |
| 60 | +UIO(NET): -> tx client #1 data paddr = 0x5fcff000 |
| 61 | +UIO(NET): *** Setting up in sDDF net control queues |
| 62 | +UIO(NET): -> mapped device 'uio1' with size 0x3000 @ 0xffff8454a000 |
| 63 | +UIO(NET): -> mapped device 'uio3' with size 0x3000 @ 0xffff84547000 |
| 64 | +UIO(NET): -> mapped device 'uio2' with size 0x5000 @ 0xffff84542000 |
| 65 | +UIO(NET): -> mapped device 'uio4' with size 0x5000 @ 0xffff8453d000 |
| 66 | +UIO(NET): *** Setting up TX/RX fault mechanism for guest -> VMM notifications |
| 67 | +UIO(NET): -> mapped device 'uio5' with size 0x1000 @ 0xffff8453c000 |
| 68 | +UIO(NET): -> mapped device 'uio6' with size 0x1000 @ 0xffff8453b000 |
| 69 | +UIO(NET): *** Setting up TX/RX UIO IRQs for VMM -> guest notifications |
| 70 | +UIO(NET): *** Binding UIO TX and RX incoming interrupts to epoll |
| 71 | +UIO(NET): *** Setting up in sDDF net data queues |
| 72 | +UIO(NET): -> mapped device 'uio9' with size 0x100000 @ 0xffff8443b000 |
| 73 | +UIO(NET): -> mapped device 'uio10' with size 0x200000 @ 0xffff8423b000 |
| 74 | +UIO(NET): *** All initialisation successful, now sending all pending TX active before we block on events |
| 75 | +UIO(NET): *** All pending TX active have been sent thru the raw sock, entering event loop now. |
| 76 | +UIO(NET): *** You won't see any output from UIO Net anymore. Unless there is a warning or error. |
| 77 | +DHCP request finished, IP address for netif client0 is: 172.16.1.91 |
| 78 | +DHCP request finished, IP address for netif client1 is: 172.16.1.90 |
| 79 | +``` |
| 80 | + |
| 81 | +Though the MAC, IP and memory addreses would be different of course. There will be delay in the tens |
| 82 | +of seconds between the Linux userspace network driver initialisation and lwIP DHCP completion. This |
| 83 | +is due to all the components being able to initialise first before the guest can get to userspace. |
| 84 | +So lwIP will send many DHCP requests without success, with increasing timeout for each request. |
| 85 | + |
| 86 | +## Future work |
| 87 | +- Support more platforms. |
| 88 | +- Fix the avalance of: |
| 89 | +`<<seL4(CPU 0) [handleInterruptEntry/56 T0x8003849400 "net_driver_vm" @20c0fc]: Spurious interrupt!>>` |
| 90 | +on debug config. |
| 91 | +- Further minimise the Linux kernel. I've reduced the kernel size to only 12.5MiB by disabling most |
| 92 | + drivers. Though there are room to push it further by disabling more features that we don't need. |
| 93 | +- Move the UIO driver into a kernel module or use iouring to reduce the context switch cost every |
| 94 | + time we send or receive a frame. |
| 95 | +- (Tying into previous) Move away from UIO, which allow us to use SIMD instructions for faster |
| 96 | + memory operations in the driver. I mentioned this as the network queue entry size isn't a power of |
| 97 | + 2, so clang always generate vector loads and stores to speed things up. Which has to be disabled |
| 98 | + to make UIO happy. |
| 99 | +- Investigate mapping the queue and data regions as cached. |
| 100 | +- Properly implement WFI/WFE in libvmm so we correctly measure CPU utilisation. |
0 commit comments