mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-10-27 02:32:23 +02:00
fix(qemu): open the adapter TAP without a vnet header
The TAP netdev kept QEMU's default vnet_hdr, so virtio-net, e1000e, igb and vmxnet3 guests offload TCP/UDP checksums (and TSO) to the TAP: their frames carry only the pseudo-header sum in the checksum field. A kernel bridge link finishes them, but the uBridge relay (cloud, NAT, hub, ...) reads the TAP with libpcap and forwards the frames as they are, so DNS and TCP through a cloud fail while ICMP and DHCP work. With vnet_hdr=off QEMU stops offering the offloads and the guest (or the emulated NIC) sends finished frames, as with the 2.x socket netdev. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
2c10782635
commit
156b77000c
@ -2715,8 +2715,14 @@ class QemuVM(KernelDatapathMixin, BaseNode):
|
||||
tap = self._kernel_host_ifc(adapter_number) or self._tap_name(adapter_number)
|
||||
network_options.extend(["-device", f"{device_string},netdev=gns3-{adapter_number}"])
|
||||
if self._tap_datapath or isinstance(nio, NIOTAP):
|
||||
# vnet_hdr=off: with QEMU's default virtio-net header the
|
||||
# guest NIC offloads TCP/UDP checksums and TSO to the TAP.
|
||||
# A kernel bridge finishes such frames, but the uBridge relay
|
||||
# (cloud, NAT, ...) copies them off the TAP as they are, so
|
||||
# receivers drop them. Without the header QEMU and the guest
|
||||
# send finished frames, as with the 2.x socket netdev.
|
||||
network_options.extend(
|
||||
["-netdev", f"tap,id=gns3-{adapter_number},ifname={tap},script=no,downscript=no"]
|
||||
["-netdev", f"tap,id=gns3-{adapter_number},ifname={tap},script=no,downscript=no,vnet_hdr=off"]
|
||||
)
|
||||
else:
|
||||
# Legacy datapath (uBridge without the tap module): QEMU talks
|
||||
|
||||
@ -29,6 +29,7 @@ from unittest.mock import MagicMock, patch
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
|
||||
from gns3server.compute.nios.nio_tap import NIOTAP
|
||||
from gns3server.compute.qemu import Qemu
|
||||
from gns3server.compute.qemu.qemu_error import QemuError
|
||||
from gns3server.compute.qemu.qemu_vm import QemuVM
|
||||
@ -143,11 +144,35 @@ async def test_network_options_use_the_tap_anchor(vm):
|
||||
|
||||
options = await vm._network_options()
|
||||
|
||||
assert f"tap,id=gns3-0,ifname={TAP0},script=no,downscript=no" in options
|
||||
assert f"tap,id=gns3-0,ifname={TAP0},script=no,downscript=no,vnet_hdr=off" in options
|
||||
assert not any(option.startswith("socket,") for option in options)
|
||||
assert not vm._local_udp_tunnels
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_network_options_turn_off_the_tap_vnet_header(vm):
|
||||
"""
|
||||
Every TAP netdev turns the virtio-net header off, the legacy NIOTAP one
|
||||
included. With QEMU's default header the guest NIC hands its TCP/UDP
|
||||
checksums (and TSO) to the TAP, and the uBridge relay copies those
|
||||
frames off the TAP unfinished: receivers behind a cloud drop them.
|
||||
"""
|
||||
|
||||
vm._tap_datapath = True
|
||||
vm.adapters = 2
|
||||
vm.adapter_type = "virtio-net-pci"
|
||||
vm._kernel_taps[(0, 0)] = TAP0
|
||||
vm._ethernet_adapters[1].add_nio(0, NIOTAP("tap-legacy"))
|
||||
|
||||
options = await vm._network_options()
|
||||
|
||||
netdevs = [options[i + 1] for i, option in enumerate(options) if option == "-netdev"]
|
||||
assert netdevs == [
|
||||
f"tap,id=gns3-0,ifname={TAP0},script=no,downscript=no,vnet_hdr=off",
|
||||
"tap,id=gns3-1,ifname=tap-legacy,script=no,downscript=no,vnet_hdr=off",
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_network_options_keep_the_legacy_socket_netdev(vm):
|
||||
"""
|
||||
|
||||
@ -11,7 +11,7 @@ binary, the real IOS CLI behind the server's telnet console), driven through
|
||||
the controller REST API. QEMU is the node type whose guest leg *is* the
|
||||
anchor: uBridge creates one persistent TAP per adapter before launch and
|
||||
hands it to this user, and QEMU opens it by ifname as its netdev
|
||||
(``-netdev tap,ifname=...,script=no,downscript=no``) — no userspace hop, no
|
||||
(``-netdev tap,ifname=...,script=no,downscript=no,vnet_hdr=off``) — no userspace hop, no
|
||||
port bridge, the anchor is the NIC's host side.
|
||||
|
||||
* two QEMU nodes on one compute report ``kernel_datapath`` when the
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user