Skip to content

Commit

Permalink
test(net): add test for tap offload features
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
kalyazin committed Oct 7, 2024
1 parent bc0ba43 commit 7c20b32
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 0 deletions.
58 changes: 58 additions & 0 deletions tests/host_tools/udp_offload.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""
A utility for sending a UDP message with UDP oflload enabled.
Inspired by the "TUN_F_CSUM is a must" chapter
in https://blog.cloudflare.com/fr-fr/virtual-networking-101-understanding-tap/
by Cloudflare.
"""

import socket
import sys


def eprint(*args, **kwargs):
"""Print to stderr"""
print(*args, file=sys.stderr, **kwargs)


# Define SOL_UDP and UDP_SEGMENT if not defined in the system headers
try:
from socket import SOL_UDP, UDP_SEGMENT
except ImportError:
SOL_UDP = 17 # Protocol number for UDP
UDP_SEGMENT = 103 # Option code for UDP segmentation (non-standard)

# Get the IP and port from command-line arguments
if len(sys.argv) != 3:
eprint("Usage: python3 udp_offload.py <ip_address> <port>")
sys.exit(1)

ip_address = sys.argv[1]
port = int(sys.argv[2])

# Create a UDP socket
sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# Set the UDP segmentation option (UDP_SEGMENT) to 1400 bytes
OPTVAL = 1400
try:
sockfd.setsockopt(SOL_UDP, UDP_SEGMENT, OPTVAL)
except (AttributeError, PermissionError):
eprint("Unable to set UDP_SEGMENT option")
sys.exit(1)

# Set the destination address and port
servaddr = (ip_address, port)

# Send the message to the destination address
MESSAGE = b"x"
try:
sockfd.sendto(MESSAGE, servaddr)
print("Message sent successfully")
except socket.error as e:
eprint(f"Error sending message: {e}")
sys.exit(1)

sockfd.close()
62 changes: 62 additions & 0 deletions tests/integration_tests/functional/test_net.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,65 @@ def test_multi_queue_unsupported(uvm_plain):
host_dev_name=tapname,
guest_mac="AA:FC:00:00:00:01",
)


def run_udp_offload_test(vm):
"""
- Start a socat UDP server in the guest.
- Try to send a UDP message with UDP offload enabled.
If tap offload features are not configured, an attempt to send a message will fail with EIO "Input/output error".
More info (search for "TUN_F_CSUM is a must"): https://blog.cloudflare.com/fr-fr/virtual-networking-101-understanding-tap/
"""
port = "81"
out_filename = "/tmp/out.txt"
message = "x"

# Start a UDP server in the guest
# vm.ssh.check_output(f"nohup socat UDP-LISTEN:{port} - > {out_filename} &")
vm.ssh.check_output(
f"nohup socat UDP-LISTEN:{port} OPEN:{out_filename},creat > /dev/null 2>&1 &"
)

# Try to send a UDP message from host with UDP offload enabled
cmd = f"ip netns exec {vm.ssh_iface().netns} python3 ./host_tools/udp_offload.py {vm.ssh_iface().host} {port}"
ret = utils.run_cmd(cmd)

# Check that the transmission was successful
assert ret.returncode == 0, f"{ret.stdout=} {ret.stderr=}"

# Check that the server received the message
ret = vm.ssh.run(f"cat {out_filename}")
assert ret.stdout == message, f"{ret.stdout=} {ret.stderr=}"


def test_tap_offload_booted(uvm_plain_any):
"""
Verify that tap offload features are configured for a booted VM.
"""
vm = uvm_plain_any
vm.spawn()
vm.basic_config()
vm.add_net_iface()
vm.start()

run_udp_offload_test(vm)


def test_tap_offload_restored(microvm_factory, guest_kernel, rootfs_ubuntu_22):
"""
Verify that tap offload features are configured for a restored VM.
"""
src = microvm_factory.build(guest_kernel, rootfs_ubuntu_22, monitor_memory=False)
src.spawn()
src.basic_config()
src.add_net_iface()
src.start()
snapshot = src.snapshot_full()
src.kill()

dst = microvm_factory.build()
dst.spawn()
dst.restore_from_snapshot(snapshot, resume=True)

run_udp_offload_test(dst)

0 comments on commit 7c20b32

Please sign in to comment.