Skip to content

Commit 7c20b32

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 bc0ba43 commit 7c20b32

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

tests/host_tools/udp_offload.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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 to stderr"""
17+
print(*args, file=sys.stderr, **kwargs)
18+
19+
20+
# Define SOL_UDP and UDP_SEGMENT if not defined in the system headers
21+
try:
22+
from socket import SOL_UDP, UDP_SEGMENT
23+
except ImportError:
24+
SOL_UDP = 17 # Protocol number for UDP
25+
UDP_SEGMENT = 103 # Option code for UDP segmentation (non-standard)
26+
27+
# Get the IP and port from command-line arguments
28+
if len(sys.argv) != 3:
29+
eprint("Usage: python3 udp_offload.py <ip_address> <port>")
30+
sys.exit(1)
31+
32+
ip_address = sys.argv[1]
33+
port = int(sys.argv[2])
34+
35+
# Create a UDP socket
36+
sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
37+
38+
# Set the UDP segmentation option (UDP_SEGMENT) to 1400 bytes
39+
OPTVAL = 1400
40+
try:
41+
sockfd.setsockopt(SOL_UDP, UDP_SEGMENT, OPTVAL)
42+
except (AttributeError, PermissionError):
43+
eprint("Unable to set UDP_SEGMENT option")
44+
sys.exit(1)
45+
46+
# Set the destination address and port
47+
servaddr = (ip_address, port)
48+
49+
# Send the message to the destination address
50+
MESSAGE = b"x"
51+
try:
52+
sockfd.sendto(MESSAGE, servaddr)
53+
print("Message sent successfully")
54+
except socket.error as e:
55+
eprint(f"Error sending message: {e}")
56+
sys.exit(1)
57+
58+
sockfd.close()

tests/integration_tests/functional/test_net.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,65 @@ 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+
out_filename = "/tmp/out.txt"
93+
message = "x"
94+
95+
# Start a UDP server in the guest
96+
# vm.ssh.check_output(f"nohup socat UDP-LISTEN:{port} - > {out_filename} &")
97+
vm.ssh.check_output(
98+
f"nohup socat UDP-LISTEN:{port} OPEN:{out_filename},creat > /dev/null 2>&1 &"
99+
)
100+
101+
# Try to send a UDP message from host with UDP offload enabled
102+
cmd = f"ip netns exec {vm.ssh_iface().netns} python3 ./host_tools/udp_offload.py {vm.ssh_iface().host} {port}"
103+
ret = utils.run_cmd(cmd)
104+
105+
# Check that the transmission was successful
106+
assert ret.returncode == 0, f"{ret.stdout=} {ret.stderr=}"
107+
108+
# Check that the server received the message
109+
ret = vm.ssh.run(f"cat {out_filename}")
110+
assert ret.stdout == message, f"{ret.stdout=} {ret.stderr=}"
111+
112+
113+
def test_tap_offload_booted(uvm_plain_any):
114+
"""
115+
Verify that tap offload features are configured for a booted VM.
116+
"""
117+
vm = uvm_plain_any
118+
vm.spawn()
119+
vm.basic_config()
120+
vm.add_net_iface()
121+
vm.start()
122+
123+
run_udp_offload_test(vm)
124+
125+
126+
def test_tap_offload_restored(microvm_factory, guest_kernel, rootfs_ubuntu_22):
127+
"""
128+
Verify that tap offload features are configured for a restored VM.
129+
"""
130+
src = microvm_factory.build(guest_kernel, rootfs_ubuntu_22, monitor_memory=False)
131+
src.spawn()
132+
src.basic_config()
133+
src.add_net_iface()
134+
src.start()
135+
snapshot = src.snapshot_full()
136+
src.kill()
137+
138+
dst = microvm_factory.build()
139+
dst.spawn()
140+
dst.restore_from_snapshot(snapshot, resume=True)
141+
142+
run_udp_offload_test(dst)

0 commit comments

Comments
 (0)