Network & Block

SLIRP networking, HTTP block device, and HTTP 9P filesystem

Data Flow

graph TD A[Guest Net Driver] --> B[VirtIO Net] B --> C[EthernetDevice] C --> D{Backend} D -->|user| E[SLIRP] D -->|tap| F[TUN/TAP] E --> G[Host UDP/TCP/ICMP] H[Guest Block Driver] --> I[VirtIO Block] I --> J[BlockDevice] J --> K{Backend} K -->|local| L[block_device_init] K -->|http| M[block_device_init_http] M --> N[HTTP Range Requests] O[Guest 9P Driver] --> P[VirtIO 9P] P --> Q[FSDevice] Q --> R{Backend} R -->|local| S[fs_disk_init] R -->|http| T[fs_net_init] T --> U[HTTP GET + Cache]

SLIRP User Networking

When the config specifies driver: "user", TinyEMU uses the bundled SLIRP library. SLIRP performs NAT-like translation: the guest sees a virtual network, and outbound traffic is translated to the host's IP stack. No root privileges or tap interface are required.

EthernetDevice *slirp_open(void)
{
    /* initialize SLIRP state */
    ...
    eth->write_packet = slirp_write_packet;
    eth->select_fill = slirp_select_fill1;
    eth->select_poll = slirp_select_poll1;
    return eth;
}

TUN/TAP Backend

For bridged networking, TinyEMU supports a TUN/TAP backend. The netinit.sh script sets up the tap interface and NAT rules. The emulator opens /dev/net/tun and forwards raw Ethernet frames.

EthernetDevice *tun_open(const char *ifname)
{
    int fd = open("/dev/net/tun", O_RDWR);
    struct ifreq ifr;
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
    ioctl(fd, TUNSETIFF, &ifr);
    /* wrap fd in EthernetDevice */
}

HTTP Block Device

block_device_init_http() creates a block device backed by remote HTTP resources. The disk image is split into small files (via splitimg). The driver caches blocks locally and prefetches adjacent blocks to improve performance.

BlockDevice *block_device_init_http(const char *url,
                                    int max_cache_size_kb,
                                    void (*start_cb)(void *opaque),
                                    void *start_opaque)
{
    BlockDeviceHTTP *s = mallocz(sizeof(*s));
    s->max_cache_size_kb = max_cache_size_kb;
    strncpy(s->url, url, sizeof(s->url));
    s->bs->get_sector_count = bf_http_get_sector_count;
    s->bs->read_async = bf_http_read_async;
    s->bs->write_async = bf_http_write_async;
    return s->bs;
}

HTTP 9P Filesystem

fs_net.c implements a 9P filesystem over HTTP. It downloads files on demand, caches inodes, and supports preloading via a .preload file list. This allows running a full Linux rootfs without downloading the entire image upfront.

FSDevice *fs_net_init(const char *url,
                      void (*start_cb)(void *opaque),
                      void *opaque)
{
    FSNetState *s = mallocz(sizeof(*s));
    s->base_url = strdup(url);
    s->fs_dev.fs_walk = fs_net_walk;
    s->fs_dev.fs_read = fs_net_read;
    s->fs_dev.fs_write = fs_net_write;
    /* ... */
    return &s->fs_dev;
}