Skip to content

Commit 9ba90cd

Browse files
committed
Add IPv6 Feature and Netperf test
1 parent 1165309 commit 9ba90cd

File tree

9 files changed

+138
-11
lines changed

9 files changed

+138
-11
lines changed

lisa/features/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from .gpu import Gpu, GpuEnabled, GpuSettings
2020
from .hibernation import Hibernation, HibernationEnabled, HibernationSettings
2121
from .infiniband import Infiniband
22+
from .ipv6 import IPv6
2223
from .isolated_resource import IsolatedResource
2324
from .nested_virtualization import NestedVirtualization
2425
from .network_interface import NetworkInterface, Sriov, Synthetic
@@ -54,6 +55,7 @@
5455
"HibernationEnabled",
5556
"HibernationSettings",
5657
"Infiniband",
58+
"IPv6",
5759
"IsolatedResource",
5860
"NestedVirtualization",
5961
"Nfs",

lisa/features/ipv6.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT license.
3+
4+
from typing import Any, Type
5+
6+
from lisa import schema
7+
from lisa.feature import Feature
8+
9+
10+
class IPv6(Feature):
11+
@classmethod
12+
def settings_type(cls) -> Type[schema.FeatureSettings]:
13+
return schema.FeatureSettings
14+
15+
@classmethod
16+
def can_disable(cls) -> bool:
17+
return True
18+
19+
def enabled(self) -> bool:
20+
raise NotImplementedError
21+
22+
def _initialize(self, *args: Any, **kwargs: Any) -> None:
23+
pass

lisa/sut_orchestrator/azure/features.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3115,6 +3115,28 @@ def delete_share(self) -> None:
31153115
)
31163116

31173117

3118+
class IPv6(AzureFeatureMixin, features.IPv6):
3119+
@classmethod
3120+
def create_setting(
3121+
cls, *args: Any, **kwargs: Any
3122+
) -> Optional[schema.FeatureSettings]:
3123+
return schema.FeatureSettings.create(cls.name())
3124+
3125+
@classmethod
3126+
def on_before_deployment(cls, *args: Any, **kwargs: Any) -> None:
3127+
arm_parameters = cast(AzureArmParameter, kwargs.get("arm_parameters"))
3128+
# Enable IPv6 support in ARM template when IPv6 feature is required
3129+
# This ensures IPv6 is enabled during initial deployment and
3130+
# the setting persists for environment reuse scenarios
3131+
arm_parameters.use_ipv6 = True
3132+
3133+
def enabled(self) -> bool:
3134+
return True
3135+
3136+
def _initialize(self, *args: Any, **kwargs: Any) -> None:
3137+
super()._initialize(*args, **kwargs)
3138+
3139+
31183140
class AzureExtension(AzureFeatureMixin, Feature):
31193141
RESOURCE_NOT_FOUND = re.compile(r"ResourceNotFound", re.M)
31203142

lisa/sut_orchestrator/azure/platform_.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ def supported_features(cls) -> List[Type[feature.Feature]]:
500500
features.Nfs,
501501
features.Availability,
502502
features.Infiniband,
503+
features.IPv6,
503504
features.Hibernation,
504505
]
505506

lisa/tools/ip.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from lisa.tools import Cat
1313
from lisa.tools.start_configuration import StartConfiguration
1414
from lisa.tools.whoami import Whoami
15-
from lisa.util import LisaException, find_patterns_in_lines
15+
from lisa.util import LisaException, find_patterns_in_lines, get_matched_str
1616

1717

1818
class IpInfo:
@@ -346,6 +346,20 @@ def get_ip_address(self, nic_name: str) -> str:
346346
assert "ip_addr" in matched, f"not find ip address for nic {nic_name}"
347347
return matched["ip_addr"]
348348

349+
def get_ipv6_address(self, nic_name: str) -> str:
350+
"""Get the global IPv6 address for a network interface."""
351+
result = self.run(f"-6 addr show {nic_name}", force_run=True, sudo=True)
352+
353+
# Regex to match IPv6 addresses with global scope
354+
# Example: inet6 2001:db8::5/128 scope global dynamic noprefixroute
355+
ipv6_pattern = re.compile(r"inet6\s+([0-9a-fA-F:]+)\/\d+\s+scope\s+global")
356+
357+
ipv6_address = get_matched_str(result.stdout, ipv6_pattern)
358+
if ipv6_address:
359+
return ipv6_address
360+
361+
raise LisaException(f"No global IPv6 address found on interface {nic_name}")
362+
349363
def get_default_route_info(self) -> tuple[str, str]:
350364
result = self.run("route", force_run=True, sudo=True)
351365
result.assert_exit_code()

lisa/tools/lagscope.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,14 +131,17 @@ def restore_busy_poll(self) -> None:
131131
for key in self._busy_pool_keys:
132132
sysctl.write(key, self._original_settings[key])
133133

134-
def run_as_server_async(self, ip: str = "") -> Process:
134+
def run_as_server_async(self, ip: str = "", use_ipv6: bool = False) -> Process:
135135
# -r: run as a receiver
136136
# -rip: run as server mode with specified ip address
137137
cmd = ""
138+
if use_ipv6:
139+
cmd += " -6"
138140
if ip:
139141
cmd += f" -r{ip}"
140142
else:
141143
cmd += " -r"
144+
142145
process = self.run_async(cmd, sudo=True, shell=True, force_run=True)
143146
if not process.is_running():
144147
raise LisaException("lagscope server failed to start")
@@ -159,6 +162,7 @@ def run_as_client_async(
159162
count_of_histogram_intervals: int = 30,
160163
dump_csv: bool = True,
161164
daemon: bool = False,
165+
use_ipv6: bool = False,
162166
) -> Process:
163167
# -s: run as a sender
164168
# -i: test interval
@@ -172,6 +176,8 @@ def run_as_client_async(
172176
# -R: dumps raw latencies into csv file
173177
# -D: run as daemon
174178
cmd = f"{self.command} -s{server_ip} "
179+
if use_ipv6:
180+
cmd += " -6 "
175181
if run_time_seconds:
176182
cmd += f" -t{run_time_seconds} "
177183
if count_of_histogram_intervals:
@@ -391,7 +397,7 @@ def restore_busy_poll(self) -> None:
391397
# This is not supported on FreeBSD.
392398
return
393399

394-
def run_as_server_async(self, ip: str = "") -> Process:
400+
def run_as_server_async(self, ip: str = "", use_ipv6: bool = False) -> Process:
395401
return self.node.tools[Sockperf].start_server_async("tcp")
396402

397403
def run_as_client_async(
@@ -407,6 +413,7 @@ def run_as_client_async(
407413
count_of_histogram_intervals: int = 30,
408414
dump_csv: bool = True,
409415
daemon: bool = False,
416+
use_ipv6: bool = False,
410417
) -> Process:
411418
return self.node.tools[Sockperf].run_client_async("tcp", server_ip)
412419

lisa/tools/ntttcp.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,11 @@ def run_as_server_async(
213213
dev_differentiator: str = "Hypervisor callback interrupts",
214214
run_as_daemon: bool = False,
215215
udp_mode: bool = False,
216+
use_ipv6: bool = False,
216217
) -> Process:
217218
cmd = ""
219+
if use_ipv6:
220+
cmd += " -6 "
218221
if server_ip:
219222
cmd += f" -r{server_ip} "
220223
cmd += (
@@ -308,6 +311,7 @@ def run_as_client(
308311
dev_differentiator: str = "Hypervisor callback interrupts",
309312
run_as_daemon: bool = False,
310313
udp_mode: bool = False,
314+
use_ipv6: bool = False,
311315
) -> ExecutableResult:
312316
# -sserver_ip: run as a sender with server ip address
313317
# -P: Number of ports listening on receiver side [default: 16] [max: 512]
@@ -326,11 +330,15 @@ def run_as_client(
326330
# the devices specified by the differentiator
327331
# Examples for differentiator: Hyper-V PCIe MSI, mlx4, Hypervisor callback
328332
# interrupts
329-
cmd = (
333+
cmd = ""
334+
if use_ipv6:
335+
cmd += " -6 "
336+
cmd += (
330337
f" -s{server_ip} -P {ports_count} -n {threads_count} -t {run_time_seconds} "
331338
f"-W {warm_up_time_seconds} -C {cool_down_time_seconds} -b {buffer_size}k "
332339
f"--show-nic-packets {nic_name} "
333340
)
341+
334342
if udp_mode:
335343
cmd += " -u "
336344
if dev_differentiator:

microsoft/testsuites/performance/common.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
Fdisk,
3333
Fio,
3434
FIOResult,
35+
Ip,
3536
Iperf3,
3637
Kill,
3738
Lagscope,
@@ -258,6 +259,7 @@ def perf_ntttcp( # noqa: C901
258259
lagscope_server_ip: Optional[str] = None,
259260
server_nic_name: Optional[str] = None,
260261
client_nic_name: Optional[str] = None,
262+
use_ipv6: bool = False,
261263
) -> List[Union[NetworkTCPPerformanceMessage, NetworkUDPPerformanceMessage]]:
262264
# Either server and client are set explicitly or we use the first two nodes
263265
# from the environment. We never combine the two options. We need to specify
@@ -339,10 +341,23 @@ def perf_ntttcp( # noqa: C901
339341
client_nic_name if client_nic_name else client.nics.default_nic
340342
)
341343
dev_differentiator = "Hypervisor callback interrupts"
344+
345+
if use_ipv6:
346+
# Retrieve IPv6 address of server, which is the address
347+
# of the default nic.
348+
server_ip_address = server.tools[Ip].get_ipv6_address(
349+
server.nics.default_nic
350+
)
351+
else:
352+
server_ip_address = server.internal_address
353+
342354
server_lagscope.run_as_server_async(
343-
ip=lagscope_server_ip
344-
if lagscope_server_ip is not None
345-
else server.internal_address
355+
ip=(
356+
lagscope_server_ip
357+
if lagscope_server_ip is not None
358+
else server_ip_address
359+
),
360+
use_ipv6=use_ipv6,
346361
)
347362
max_server_threads = 64
348363
perf_ntttcp_message_list: List[
@@ -364,14 +379,15 @@ def perf_ntttcp( # noqa: C901
364379

365380
server_result = server_ntttcp.run_as_server_async(
366381
server_nic_name,
367-
server_ip=server.internal_address if isinstance(server.os, BSD) else "",
382+
server_ip=server_ip_address if isinstance(server.os, BSD) else "",
368383
ports_count=num_threads_p,
369384
buffer_size=buffer_size,
370385
dev_differentiator=dev_differentiator,
371386
udp_mode=udp_mode,
387+
use_ipv6=use_ipv6,
372388
)
373389
client_lagscope_process = client_lagscope.run_as_client_async(
374-
server_ip=server.internal_address,
390+
server_ip=server_ip_address,
375391
ping_count=0,
376392
run_time_seconds=10,
377393
print_histogram=False,
@@ -380,15 +396,17 @@ def perf_ntttcp( # noqa: C901
380396
length_of_histogram_intervals=0,
381397
count_of_histogram_intervals=0,
382398
dump_csv=False,
399+
use_ipv6=use_ipv6,
383400
)
384401
client_ntttcp_result = client_ntttcp.run_as_client(
385402
client_nic_name,
386-
server.internal_address,
403+
server_ip_address,
387404
buffer_size=buffer_size,
388405
threads_count=num_threads_n,
389406
ports_count=num_threads_p,
390407
dev_differentiator=dev_differentiator,
391408
udp_mode=udp_mode,
409+
use_ipv6=use_ipv6,
392410
)
393411
server.tools[Kill].by_name(server_ntttcp.command)
394412
server_ntttcp_result = server_result.wait_result()

microsoft/testsuites/performance/networkperf.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
simple_requirement,
1515
)
1616
from lisa.environment import Environment, Node
17-
from lisa.features import Sriov, Synthetic
17+
from lisa.features import IPv6, Sriov, Synthetic
1818
from lisa.operating_system import BSD, Windows
1919
from lisa.testsuite import TestResult
2020
from lisa.tools import Sysctl
@@ -286,6 +286,38 @@ def perf_udp_iperf_sriov(self, result: TestResult) -> None:
286286
udp_mode=True,
287287
)
288288

289+
@TestCaseMetadata(
290+
description="""
291+
This test case uses ntttcp to test IPv6 SR-IOV network throughput.
292+
""",
293+
priority=3,
294+
timeout=TIMEOUT,
295+
requirement=simple_requirement(
296+
min_count=2,
297+
network_interface=Sriov(),
298+
supported_features=[IPv6],
299+
unsupported_os=[BSD, Windows],
300+
),
301+
)
302+
def perf_tcp_ipv6_ntttcp_sriov(self, result: TestResult) -> None:
303+
perf_ntttcp(result, use_ipv6=True)
304+
305+
@TestCaseMetadata(
306+
description="""
307+
This test case uses ntttcp to test IPv6 synthetic network throughput.
308+
""",
309+
priority=3,
310+
timeout=TIMEOUT,
311+
requirement=simple_requirement(
312+
min_count=2,
313+
network_interface=Synthetic(),
314+
supported_features=[IPv6],
315+
unsupported_os=[BSD, Windows],
316+
),
317+
)
318+
def perf_tcp_ipv6_ntttcp_synthetic(self, result: TestResult) -> None:
319+
perf_ntttcp(result, use_ipv6=True)
320+
289321
# Marked all following tests to skip on BSD since
290322
# sockperf compilation is not natively supported at this time
291323
# This is due to the default compiler on freebsd being c++17

0 commit comments

Comments
 (0)