Skip to content

Commit 736aa9f

Browse files
committed
test(net): add test for tap offload features
This is a regression test for the following fix: commit a9e5f13 Author: Nikita Kalyazin <[email protected]> Date: Mon Sep 30 13:05:28 2024 +0000 fix(net): set tap offload features on restore The test verifies that tap offload features are configured for both booted and restored VMs. Signed-off-by: Nikita Kalyazin <[email protected]>
1 parent 8c7f1dd commit 736aa9f

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

tests/host_tools/udp_offload.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""
4+
A utility for sending a UDP message with UDP oflload enabled.
5+
6+
Inspired by the "TUN_F_CSUM is a must" chapter
7+
in https://blog.cloudflare.com/fr-fr/virtual-networking-101-understanding-tap/
8+
by Cloudflare.
9+
"""
10+
11+
import socket
12+
import sys
13+
14+
15+
def eprint(*args, **kwargs):
16+
print(*args, file=sys.stderr, **kwargs)
17+
18+
19+
# Define SOL_UDP and UDP_SEGMENT if not defined in the system headers
20+
try:
21+
from socket import SOL_UDP, UDP_SEGMENT
22+
except ImportError:
23+
SOL_UDP = 17 # Protocol number for UDP
24+
UDP_SEGMENT = 103 # Option code for UDP segmentation (non-standard)
25+
26+
# Get the IP and port from command-line arguments
27+
if len(sys.argv) != 3:
28+
eprint("Usage: python3 udp_offload.py <ip_address> <port>")
29+
sys.exit(1)
30+
31+
ip_address = sys.argv[1]
32+
port = int(sys.argv[2])
33+
34+
# Create a UDP socket
35+
sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
36+
37+
# Set the UDP segmentation option (UDP_SEGMENT) to 1400 bytes
38+
optval = 1400
39+
try:
40+
sockfd.setsockopt(SOL_UDP, UDP_SEGMENT, optval)
41+
except (AttributeError, PermissionError):
42+
eprint("Unable to set UDP_SEGMENT option")
43+
sys.exit(1)
44+
45+
# Set the destination address and port
46+
servaddr = (ip_address, port)
47+
48+
# Send the message to the destination address
49+
message = b"x"
50+
try:
51+
sockfd.sendto(message, servaddr)
52+
print("Message sent successfully")
53+
except socket.error as e:
54+
eprint(f"Error sending message: {e}")
55+
exit(1)
56+
57+
sockfd.close()

tests/integration_tests/functional/test_net.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,56 @@ def test_multi_queue_unsupported(uvm_plain):
7878
host_dev_name=tapname,
7979
guest_mac="AA:FC:00:00:00:01",
8080
)
81+
82+
83+
def run_udp_offload_test(vm):
84+
"""
85+
- Start a socat UDP server in the guest.
86+
- Try to send a UDP message with UDP offload enabled.
87+
88+
If tap offload features are not configured, an attempt to send a message will fail with EIO "Input/output error".
89+
More info (search for "TUN_F_CSUM is a must"): https://blog.cloudflare.com/fr-fr/virtual-networking-101-understanding-tap/
90+
"""
91+
port = 81
92+
93+
# Start a UDP server in the guest
94+
vm.ssh.check_output(f"nohup socat UDP-LISTEN:{port} - > /dev/null 2>&1 &")
95+
96+
# Try to send a UDP message from host with UDP offload enabled
97+
cmd = f"ip netns exec {vm.ssh_iface().netns} python3 ./host_tools/udp_offload.py {vm.ssh_iface().host} {port}"
98+
ret = utils.run_cmd(cmd)
99+
100+
# Check that the transmission was successful
101+
assert ret.returncode == 0, f"{ret.stdout=} {ret.stderr=}"
102+
103+
104+
def test_tap_offload_booted(uvm_plain_any):
105+
"""
106+
Verify that tap offload features are configured for a booted VM.
107+
"""
108+
vm = uvm_plain_any
109+
vm.spawn()
110+
vm.basic_config()
111+
vm.add_net_iface()
112+
vm.start()
113+
114+
run_udp_offload_test(vm)
115+
116+
117+
def test_tap_offload_restored(microvm_factory, guest_kernel, rootfs_ubuntu_22):
118+
"""
119+
Verify that tap offload features are configured for a restored VM.
120+
"""
121+
src = microvm_factory.build(guest_kernel, rootfs_ubuntu_22, monitor_memory=False)
122+
src.spawn()
123+
src.basic_config()
124+
src.add_net_iface()
125+
src.start()
126+
snapshot = src.snapshot_full()
127+
src.kill()
128+
129+
dst = microvm_factory.build()
130+
dst.spawn()
131+
dst.restore_from_snapshot(snapshot, resume=True)
132+
133+
run_udp_offload_test(dst)

0 commit comments

Comments
 (0)