Skip to content

Commit 3033356

Browse files
committed
Dpdk: 32bit test
Allow building rdma-core and dpdk as 32bit applications before test. Add the 32bit test. This is a beefy commit because we must extend the Installer class to support 32bit builds. This means adding invalid arch checks, adding arch checks to the DependencyInstaller, adding changes to PKG_CONFIG_PATH and allowing updating environment variables everywhere. The result is that we can install DPDK and RDMA core and run their 32bit versions to test basic send/receive stuff.
1 parent 9362f54 commit 3033356

File tree

6 files changed

+354
-79
lines changed

6 files changed

+354
-79
lines changed

lisa/tools/meson.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Licensed under the MIT license.
33

44
from pathlib import PurePath
5-
from typing import cast
5+
from typing import Dict, Optional, cast
66

77
from semver import VersionInfo
88

@@ -50,15 +50,22 @@ def _install(self) -> bool:
5050
)
5151
return self._check_exists()
5252

53-
def setup(self, args: str, cwd: PurePath, build_dir: str = "build") -> PurePath:
53+
def setup(
54+
self,
55+
args: str,
56+
cwd: PurePath,
57+
build_dir: str = "build",
58+
update_envs: Optional[Dict[str, str]] = None,
59+
) -> PurePath:
5460
self.run(
55-
f"{args} {build_dir}",
61+
parameters=f"{args} {build_dir}",
5662
force_run=True,
5763
shell=True,
5864
cwd=cwd,
5965
expected_exit_code=0,
6066
expected_exit_code_failure_message=(
6167
f"Could not configure {str(cwd)} with meson using args {args}"
6268
),
69+
update_envs=update_envs,
6370
)
6471
return cwd.joinpath(build_dir)

microsoft/testsuites/dpdk/common.py

Lines changed: 92 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,22 @@
1111
from lisa import Node
1212
from lisa.executable import Tool
1313
from lisa.operating_system import Debian, Fedora, Oracle, Posix, Redhat, Suse, Ubuntu
14-
from lisa.tools import Git, Tar, Wget
15-
from lisa.util import UnsupportedDistroException
14+
from lisa.tools import Git, Lscpu, Tar, Wget
15+
from lisa.tools.lscpu import CpuArchitecture
16+
from lisa.util import UnsupportedCpuArchitectureException, UnsupportedDistroException
1617

1718
DPDK_STABLE_GIT_REPO = "https://dpdk.org/git/dpdk-stable"
1819

1920
# azure routing table magic subnet prefix
2021
# signals 'route all traffic on this subnet'
2122
AZ_ROUTE_ALL_TRAFFIC = "0.0.0.0/0"
2223

24+
ARCH_COMPATIBILITY_MATRIX = {
25+
CpuArchitecture.X64: [CpuArchitecture.X64],
26+
CpuArchitecture.I386: [CpuArchitecture.I386, CpuArchitecture.X64],
27+
CpuArchitecture.ARM64: [CpuArchitecture.ARM64],
28+
}
29+
2330

2431
# Attempt to clean up the DPDK package dependency mess
2532
# Make a Installer class that implements the common steps
@@ -34,7 +41,7 @@ class OsPackageDependencies:
3441
# the packages to install on that OS.
3542
def __init__(
3643
self,
37-
matcher: Callable[[Posix], bool],
44+
matcher: Callable[[Posix, Optional[CpuArchitecture]], bool],
3845
packages: Optional[Sequence[Union[str, Tool, Type[Tool]]]] = None,
3946
stop_on_match: bool = False,
4047
) -> None:
@@ -45,14 +52,21 @@ def __init__(
4552

4653
class DependencyInstaller:
4754
# provide a list of OsPackageDependencies for a project
48-
def __init__(self, requirements: List[OsPackageDependencies]) -> None:
55+
def __init__(
56+
self,
57+
requirements: List[OsPackageDependencies],
58+
arch: Optional[CpuArchitecture] = None,
59+
) -> None:
4960
self.requirements = requirements
61+
self._arch = arch
5062

5163
# evaluate the list of package dependencies,
5264
def install_required_packages(
53-
self, node: Node, extra_args: Union[List[str], None]
65+
self,
66+
os: Posix,
67+
extra_args: Union[List[str], None],
68+
arch: Optional[CpuArchitecture] = None,
5469
) -> None:
55-
os = node.os
5670
assert isinstance(os, Posix), (
5771
"DependencyInstaller is not compatible with this OS: "
5872
f"{os.information.vendor} {os.information.release}"
@@ -61,13 +75,16 @@ def install_required_packages(
6175
# stop on list end or if exclusive_match parameter is true.
6276
packages: List[Union[str, Tool, Type[Tool]]] = []
6377
for requirement in self.requirements:
64-
if requirement.matcher(os) and requirement.packages:
65-
packages += requirement.packages
78+
if requirement.matcher(os, arch):
79+
if requirement.packages is not None and len(requirement.packages) > 0:
80+
packages += requirement.packages
6681
if requirement.stop_on_match:
6782
break
83+
6884
os.install_packages(packages=packages, extra_args=extra_args)
6985

7086
# NOTE: It is up to the caller to raise an exception on an invalid OS
87+
# see unsupported_os_thrower as a catch-all 'list end' function
7188

7289

7390
class Downloader:
@@ -200,23 +217,43 @@ def _uninstall(self) -> None:
200217
def _install_dependencies(self) -> None:
201218
if self._os_dependencies is not None:
202219
self._os_dependencies.install_required_packages(
203-
self._node, extra_args=self._package_manager_extra_args
220+
self._os, extra_args=self._package_manager_extra_args, arch=self._arch
204221
)
205222

206223
# define how to check the installed version
207224
def get_installed_version(self) -> VersionInfo:
208225
raise NotImplementedError(f"get_installed_version {self._err_msg}")
209226

210-
def _should_install(self, required_version: Optional[VersionInfo] = None) -> bool:
211-
return (not self._check_if_installed()) or (
212-
required_version is not None
213-
and required_version > self.get_installed_version()
227+
def _should_install(
228+
self,
229+
required_version: Optional[VersionInfo] = None,
230+
required_arch: Optional[CpuArchitecture] = None,
231+
) -> bool:
232+
return (
233+
(not self._check_if_installed())
234+
# NOTE: Taking advantage of longer-than-expected lifetimes here.
235+
# If the tool still exists we ~should~ be able to check the old version
236+
# from a previous test environment.
237+
# At the moment, we use create() to force re-initialization.
238+
# If we ever fix things so that we use .get,
239+
# we will need this check. So add it now.q
240+
or (required_arch != self._arch)
241+
or (
242+
required_version is not None
243+
and required_version > self.get_installed_version()
244+
)
214245
)
215246

216247
# run the defined setup and installation steps.
217-
def do_installation(self, required_version: Optional[VersionInfo] = None) -> None:
248+
def do_installation(
249+
self,
250+
required_version: Optional[VersionInfo] = None,
251+
required_arch: Optional[CpuArchitecture] = None,
252+
) -> None:
218253
self._setup_node()
219-
if self._should_install():
254+
if self._should_install(
255+
required_version=required_version, required_arch=required_arch
256+
):
220257
self._uninstall()
221258
self._install_dependencies()
222259
self._install()
@@ -226,6 +263,7 @@ def __init__(
226263
node: Node,
227264
os_dependencies: Optional[DependencyInstaller] = None,
228265
downloader: Optional[Downloader] = None,
266+
arch: Optional[CpuArchitecture] = None,
229267
) -> None:
230268
self._node = node
231269
if not isinstance(self._node.os, Posix):
@@ -236,20 +274,34 @@ def __init__(
236274
self._package_manager_extra_args: List[str] = []
237275
self._os_dependencies = os_dependencies
238276
self._downloader = downloader
277+
self._arch = arch
278+
if self._arch:
279+
# avoid building/running arm64 on i386, etc
280+
system_arch = self._node.tools[Lscpu].get_architecture()
281+
if system_arch not in ARCH_COMPATIBILITY_MATRIX[self._arch]:
282+
raise UnsupportedCpuArchitectureException(system_arch)
239283

240284

241285
# Base class for package manager installation
242286
class PackageManagerInstall(Installer):
243-
def __init__(self, node: Node, os_dependencies: DependencyInstaller) -> None:
287+
def __init__(
288+
self,
289+
node: Node,
290+
os_dependencies: DependencyInstaller,
291+
arch: Optional[CpuArchitecture],
292+
) -> None:
244293
super().__init__(node, os_dependencies)
245294

246295
# uninstall from the package manager
247296
def _uninstall(self) -> None:
248297
if not (isinstance(self._os, Posix) and self._check_if_installed()):
249298
return
250299
if self._os_dependencies is not None:
251-
for os_package_check in self._os_dependencies.requirements:
252-
if os_package_check.matcher(self._os) and os_package_check.packages:
300+
for os_package_check in self._os_dependencies:
301+
if (
302+
os_package_check.matcher(self._os, self._arch)
303+
and os_package_check.packages
304+
):
253305
self._os.uninstall_packages(os_package_check.packages)
254306
if os_package_check.stop_on_match:
255307
break
@@ -261,7 +313,7 @@ def _check_if_installed(self) -> bool:
261313
# For dpdk, pkg-manager install is only for 'dpdk' and 'dpdk-dev'
262314
# This will take too long if it's more than a few packages.
263315
if self._os_dependencies is not None:
264-
for os_package_check in self._os_dependencies.requirements:
316+
for os_package_check in self._os_dependencies:
265317
if os_package_check.matcher(self._os) and os_package_check.packages:
266318
for pkg in os_package_check.packages:
267319
if not self._os.package_exists(pkg):
@@ -271,9 +323,13 @@ def _check_if_installed(self) -> bool:
271323
return True
272324

273325

274-
def force_dpdk_default_source(variables: Dict[str, Any]) -> None:
326+
def force_dpdk_default_source(
327+
variables: Dict[str, Any], build_arch: Optional[CpuArchitecture] = None
328+
) -> None:
275329
if not variables.get("dpdk_source", None):
276330
variables["dpdk_source"] = DPDK_STABLE_GIT_REPO
331+
if build_arch:
332+
variables["build_arch"] = build_arch
277333

278334

279335
_UBUNTU_LTS_VERSIONS = ["24.4.0", "22.4.0", "20.4.0", "18.4.0"]
@@ -368,13 +424,27 @@ def is_url_for_git_repo(url: str) -> bool:
368424
return scheme == "git" or check_for_git_https
369425

370426

371-
def unsupported_os_thrower(os: Posix) -> bool:
427+
# utility matcher to throw an OS error type for a match.
428+
def unsupported_os_thrower(os: Posix, arch: Optional[CpuArchitecture]) -> bool:
429+
if arch:
430+
message_suffix = f"OS and Architecture ({arch})"
431+
else:
432+
message_suffix = "OS"
372433
raise UnsupportedDistroException(
373434
os,
374-
message=("Installer did not define dependencies for this os."),
435+
message=f"Installer did not define dependencies for this {message_suffix}",
375436
)
376437

377438

439+
# utility matcher to throw an OS error when i386 is not supported
440+
def i386_not_implemented_thrower(os: Posix, arch: Optional[CpuArchitecture]) -> bool:
441+
if arch and arch == CpuArchitecture.I386:
442+
raise NotImplementedError(
443+
"i386 is not implemented for this (installer,OS) combo."
444+
)
445+
return False
446+
447+
378448
def get_debian_backport_repo_args(os: Debian) -> List[str]:
379449
# ex: 'bionic-backports' or 'buster-backports'
380450
# these backport repos are available for the older OS's

microsoft/testsuites/dpdk/dpdksuite.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from lisa.testsuite import simple_requirement
2626
from lisa.tools import Echo, Git, Hugepages, Ip, Kill, Lsmod, Make, Modprobe
2727
from lisa.tools.hugepages import HugePageSize
28+
from lisa.tools.lscpu import CpuArchitecture
2829
from lisa.util.constants import SIGINT
2930
from microsoft.testsuites.dpdk.common import (
3031
DPDK_STABLE_GIT_REPO,
@@ -95,6 +96,29 @@ def verify_dpdk_build_netvsc(
9596
) -> None:
9697
verify_dpdk_build(node, log, variables, "netvsc", HugePageSize.HUGE_2MB)
9798

99+
@TestCaseMetadata(
100+
description="""
101+
netvsc pmd version.
102+
This test case checks DPDK can be built and installed correctly.
103+
Prerequisites, accelerated networking must be enabled.
104+
The VM should have at least two network interfaces,
105+
with one interface for management.
106+
More details refer https://docs.microsoft.com/en-us/azure/virtual-network/setup-dpdk#prerequisites # noqa: E501
107+
""",
108+
priority=2,
109+
requirement=simple_requirement(
110+
min_core_count=8,
111+
min_nic_count=2,
112+
network_interface=Sriov(),
113+
unsupported_features=[Gpu, Infiniband],
114+
),
115+
)
116+
def verify_dpdk_build_netvsc_32bit(
117+
self, node: Node, log: Logger, variables: Dict[str, Any]
118+
) -> None:
119+
force_dpdk_default_source(variables, build_arch=CpuArchitecture.I386)
120+
verify_dpdk_build(node, log, variables, "netvsc", HugePageSize.HUGE_2MB)
121+
98122
@TestCaseMetadata(
99123
description="""
100124
netvsc pmd version with 1GiB hugepages

0 commit comments

Comments
 (0)