mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-10-27 02:32:23 +02:00
Merge pull request #3029 from tikD1337/fix/qemu-tap-partial-csum
fix(qemu): open the adapter TAP with vnet_hdr=off so relay links carry finished checksums
This commit is contained in:
commit
dd19d96fbf
@ -2715,8 +2715,14 @@ class QemuVM(KernelDatapathMixin, BaseNode):
|
|||||||
tap = self._kernel_host_ifc(adapter_number) or self._tap_name(adapter_number)
|
tap = self._kernel_host_ifc(adapter_number) or self._tap_name(adapter_number)
|
||||||
network_options.extend(["-device", f"{device_string},netdev=gns3-{adapter_number}"])
|
network_options.extend(["-device", f"{device_string},netdev=gns3-{adapter_number}"])
|
||||||
if self._tap_datapath or isinstance(nio, NIOTAP):
|
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(
|
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:
|
else:
|
||||||
# Legacy datapath (uBridge without the tap module): QEMU talks
|
# Legacy datapath (uBridge without the tap module): QEMU talks
|
||||||
|
|||||||
@ -29,6 +29,7 @@ from unittest.mock import MagicMock, patch
|
|||||||
import pytest
|
import pytest
|
||||||
import pytest_asyncio
|
import pytest_asyncio
|
||||||
|
|
||||||
|
from gns3server.compute.nios.nio_tap import NIOTAP
|
||||||
from gns3server.compute.qemu import Qemu
|
from gns3server.compute.qemu import Qemu
|
||||||
from gns3server.compute.qemu.qemu_error import QemuError
|
from gns3server.compute.qemu.qemu_error import QemuError
|
||||||
from gns3server.compute.qemu.qemu_vm import QemuVM
|
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()
|
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 any(option.startswith("socket,") for option in options)
|
||||||
assert not vm._local_udp_tunnels
|
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
|
@pytest.mark.asyncio
|
||||||
async def test_network_options_keep_the_legacy_socket_netdev(vm):
|
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
|
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
|
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
|
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.
|
port bridge, the anchor is the NIC's host side.
|
||||||
|
|
||||||
* two QEMU nodes on one compute report ``kernel_datapath`` when the
|
* two QEMU nodes on one compute report ``kernel_datapath`` when the
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user