QEMU Network Internals
======================
This document provides detailed technical information about the UART-based IP tunnel implementation for ESP32 QEMU emulation.
.. note::
This is advanced technical documentation. For usage instructions, see :doc:`qemu-emulator`.
Architecture Overview
---------------------
.. code-block:: text
┌─────────────────────────────────────────────────────────────────┐
│ HOST (Linux) │
│ │
│ ┌──────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ ping │─────▶│ tun0 │◀────▶│ TUN Bridge │ │
│ │ curl │ │ 192.168. │ │ (Python) │ │
│ └──────────┘ │ 100.1/24 │ └─────────────────┘ │
│ └─────────────┘ │ │
│ │ TCP:5556 │
└──────────────────────────────────────────────────┼──────────────┘
│
│ QEMU chardev
┌──────────────────────────────────────────────────┼──────────────┐
│ ESP32 QEMU │ │
│ ▼ │
│ ┌────────────┐ ┌──────────────┐ ┌─────────────┐ │
│ │ Web │ │ lwIP │ │ UART1 │ │
│ │ Server │◀───▶│ Stack │◀───▶│ Driver │ │
│ │ HTTP │ │ 192.168. │ │ │ │
│ │ │ │ 100.2/24 │ └─────────────┘ │
│ └────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Frame Format
------------
Ethernet Frame Encapsulation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: text
┌───────────────┬────────────────────────────────────────────┐
│ Frame Length │ Ethernet Frame │
│ (2 bytes) │ (14-byte header + IP) │
│ Big Endian │ │
├───────────────┼────────────────────────────────────────────┤
│ [HI] [LO] │ [DST_MAC:6][SRC_MAC:6][TYPE:2][IP PACKET] │
└───────────────┴────────────────────────────────────────────┘
Example ICMP Echo Request (98 bytes total):
.. code-block:: text
Length: 0x00 0x62 (98 bytes)
Ethernet:
Dst MAC: 02:00:00:00:00:02 (ESP32)
Src MAC: 02:00:00:00:00:01 (Host)
Type: 0x08 0x00 (IPv4)
IP:
Version/IHL: 0x45 (IPv4, 20 byte header)
Protocol: 0x01 (ICMP)
Src IP: 192.168.100.1 (0xC0 0xA8 0x64 0x01)
Dst IP: 192.168.100.2 (0xC0 0xA8 0x64 0x02)
ICMP:
Type: 0x08 (Echo Request)
Code: 0x00
Initialization Sequence
-----------------------
System Startup
~~~~~~~~~~~~~~
1. **Initialize Network Stack** (``wifi_manager_sim.c``)
- ``esp_netif_init()``
- ``esp_event_loop_create_default()``
2. **Initialize UART Tunnel Driver** (``netif_uart_tunnel_sim.c``)
a) **Hardware Setup:**
- Configure UART1: 115200 baud, GPIO 17/16
- ``uart_driver_install()`` with 2KB RX/TX buffers
b) **Create esp_netif:**
- ``ESP_NETIF_INHERENT_DEFAULT_ETH()`` config
- ``esp_netif_new()``
c) **Configure Static IP:**
- IP: 192.168.100.2
- Gateway: 192.168.100.1
- Netmask: 255.255.255.0
d) **Direct lwIP Integration:**
- Get lwIP netif handle
- Set MAC: 02:00:00:00:00:02
- Set flags: ETHARP | ETHERNET | BROADCAST
- Register linkoutput callback
- Set as default netif
- Add static ARP entry for gateway
3. **Start RX Task**
- FreeRTOS task polls UART for incoming frames
- Priority 5 (high priority for network responsiveness)
Packet Flow
-----------
Outgoing (TX): ESP32 → Host
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. **Application Layer**
- Application calls lwIP functions (e.g., ``send()``, ``httpd_resp_send()``)
2. **lwIP TCP/IP Stack**
- TCP/UDP processing
- IP header generation
- Routing decision (uses UART netif)
3. **Ethernet Layer**
- lwIP calls ``linkoutput`` callback
- Function: ``netif_output()`` in ``netif_uart_tunnel_sim.c``
4. **Frame Preparation**
- Extract Ethernet header from pbuf (14 bytes)
- Get payload length
- Prepare 2-byte length prefix (big-endian)
5. **UART Transmission**
- Write length prefix to UART1
- Write Ethernet frame to UART1
- QEMU chardev forwards to TCP socket
6. **TUN Bridge** (Python)
- Receives frame from TCP socket
- Writes frame to TUN device
- Linux kernel processes as Ethernet frame
7. **Host Network Stack**
- Routes to appropriate application (curl, browser, etc.)
Incoming (RX): Host → ESP32
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. **Host Application**
- Application sends packet (e.g., HTTP request)
2. **Linux Network Stack**
- Routes to TUN device (192.168.100.2)
3. **TUN Bridge** (Python)
- Reads Ethernet frame from TUN device
- Writes length-prefixed frame to TCP socket
4. **QEMU Chardev**
- Forwards data to emulated UART1
5. **ESP32 UART Driver**
- RX interrupt triggers
- Data copied to FreeRTOS queue
6. **RX Task** (``uart_rx_task``)
- Reads 2-byte length prefix
- Reads Ethernet frame (up to 1518 bytes)
- Validates frame length and format
7. **lwIP Input**
- Allocates pbuf
- Copies frame data to pbuf
- Calls ``netif->input()`` → ``tcpip_input()``
8. **lwIP TCP/IP Stack**
- Ethernet processing
- IP routing
- TCP/UDP handling
9. **Application Layer**
- Application receives data via socket
Critical Implementation Details
-------------------------------
Buffer Management
~~~~~~~~~~~~~~~~~
.. code-block:: c
// RX buffer allocation
#define UART_RX_BUF_SIZE 2048
#define MAX_ETH_FRAME_SIZE 1518
uint8_t frame_buffer[MAX_ETH_FRAME_SIZE];
**Strategy:**
- Fixed-size buffer on stack for frame assembly
- pbuf allocation only after complete frame received
- Minimizes heap fragmentation
UART Configuration
~~~~~~~~~~~~~~~~~~
.. code-block:: c
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
};
**Performance:**
- 115200 baud ≈ 14.4 KB/s theoretical max
- Practical throughput: ~10 KB/s (overhead + framing)
- Adequate for HTTP, slow for large transfers
Error Handling
~~~~~~~~~~~~~~
.. code-block:: c
// Length validation
if (frame_len < 14 || frame_len > MAX_ETH_FRAME_SIZE) {
ESP_LOGW(TAG, "Invalid frame length: %d", frame_len);
continue; // Skip malformed frame
}
**Robustness:**
- Frame length validation prevents buffer overflows
- Timeout on incomplete frames (1 second)
- Automatic recovery from malformed packets
MAC Address Assignment
~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: c
static const uint8_t esp32_mac[6] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x02};
static const uint8_t host_mac[6] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x01};
**Design:**
- Locally administered MAC addresses (bit 1 set)
- Static assignment for predictable ARP behavior
- No MAC learning required
Static ARP Entry
~~~~~~~~~~~~~~~~
.. code-block:: c
// Add gateway ARP entry
ip4_addr_t gw_addr;
IP4_ADDR(&gw_addr, 192, 168, 100, 1);
etharp_add_static_entry(&gw_addr, (struct eth_addr*)host_mac);
**Why Static ARP:**
- Prevents ARP requests over UART (reduces overhead)
- Immediate connectivity without ARP handshake
- Simplifies bridge implementation
Performance Characteristics
---------------------------
Throughput
~~~~~~~~~~
- **HTTP GET small file**: ~5-8 KB/s
- **HTTP GET 1MB file**: ~10 KB/s sustained
- **Ping latency**: 3-8 ms typical
Bottlenecks
~~~~~~~~~~~
1. **UART Bandwidth**: 115200 baud limit
2. **Frame Overhead**: 2-byte length + 14-byte Ethernet header per packet
3. **QEMU Emulation**: CPU overhead vs. real hardware
Optimization Opportunities
~~~~~~~~~~~~~~~~~~~~~~~~~~
**Increase Baud Rate**: 230400 or 460800 (requires TUN bridge update)
**Jumbo Frames**: Support 9KB frames (requires lwIP MTU change)
**DMA**: Use UART DMA for reduced CPU overhead
**Zero-Copy**: Direct pbuf allocation in UART callback
Debugging Network Issues
------------------------
Enable Verbose Logging
~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: c
// In netif_uart_tunnel_sim.c
#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
Capture UART Traffic
~~~~~~~~~~~~~~~~~~~~~
.. code-block:: bash
# Monitor UART1 in separate terminal
./tools/view_uart1.sh
Analyze with tcpdump
~~~~~~~~~~~~~~~~~~~~
.. code-block:: bash
# Capture TUN device traffic
sudo tcpdump -i tun0 -w capture.pcap
# Analyze with Wireshark
wireshark capture.pcap
Check Frame Alignment
~~~~~~~~~~~~~~~~~~~~~
.. code-block:: bash
# Look for length/frame mismatches in logs
grep "RX:" /tmp/qemu_uart*.log | head -20
Known Issues and Limitations
-----------------------------
Current Limitations
~~~~~~~~~~~~~~~~~~~
- **UART Speed**: 115200 baud limits throughput to ~10 KB/s
- **No WiFi Emulation**: Direct IP connectivity, no AP/STA simulation
- **Single Interface**: Cannot emulate multiple network interfaces
- **No Packet Loss**: Reliable UART, no wireless error simulation
Future Improvements
~~~~~~~~~~~~~~~~~~~
- **Higher Baud Rate**: 460800+ for better throughput
- **WiFi Event Simulation**: Emulate connection/disconnection events
- **Packet Loss Simulation**: Inject errors for robustness testing
- **Multiple Interfaces**: Support AP + STA simultaneously
Source Code Reference
---------------------
Key Files
~~~~~~~~~
- ``main/components/netif_uart_tunnel/netif_uart_tunnel_sim.c`` - ESP32 driver
- ``main/components/web_server/wifi_manager_sim.c`` - Network initialization
- ``tools/serial_tun_bridge.py`` - Host-side TUN bridge
- ``tools/run-qemu-network.sh`` - Launch script
Further Reading
---------------
- `lwIP Documentation `_
- `ESP-IDF esp_netif Guide `_
- `Linux TUN/TAP `_
- `QEMU Chardev `_