-
Notifications
You must be signed in to change notification settings - Fork 64
SRIOV tests and unit tests (New) #1761
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
1f298f8
SRIOV tests and unit tests
mreed8855 7880cf8
Updates made to sriov.py and unit tests to increase the coverage
mreed8855 dde0667
Updated for black format c heck
mreed8855 90b30a8
Merge branch 'main' into sriov_update4
mreed8855 9e51d1a
Updates made to address the PR comments
mreed8855 30ba2f4
Updated unit tests
mreed8855 77193d2
Moved job file to networking
mreed8855 86f718e
Merge branch 'main' into sriov_update4
mreed8855 1eab4d8
Fixed black formatting
mreed8855 27bb0c9
Fix black formatting
mreed8855 a58dbb6
Fixed additional fomatting issues
mreed8855 5b1fde7
Removed this file as it was mistakely placed here
mreed8855 b86419a
Fixed black formatting again!
mreed8855 7867db7
Updated for PR changes
mreed8855 919288b
removed try except block
mreed8855 e5d517e
Fix flake8 issue
mreed8855 c4e5417
Black formatting issue
mreed8855 f84921d
flake8 issue
mreed8855 6d96e65
flake 8 issue
mreed8855 6fbe40f
Remove try except block from check_interface_vendor
mreed8855 bcbebff
Updates to unit tests
mreed8855 42a75ec
black formating fix
mreed8855 939856a
Removed line for python 3.5
mreed8855 aeadb95
Changes made to comply with Python 3.5
mreed8855 702787f
pythong 3.5 issue
mreed8855 eb1b4be
python 3.5 issue
mreed8855 a14098c
Removed sys.exit from main
mreed8855 c7e9030
Adding a cleanup sriov script to remove virtual adapters after
mreed8855 68c2995
Fix black and flake8 formating
mreed8855 5558910
Fix black formatting
mreed8855 f6ff3b4
- Add has_sriov manifest entry to enable SR-IOV testing
mreed8855 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,283 @@ | ||
#!/usr/bin/env python3 | ||
""" | ||
Scripts used to test sriov network functions | ||
Copyright (C) 2025 Canonical Ltd. | ||
|
||
Author | ||
Michael Reed <[email protected]. | ||
|
||
This program is free software: you can redistribute it and/or modify | ||
it under the terms of the GNU General Public License version 3, | ||
as published by the Free Software Foundation. | ||
|
||
This program is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
GNU General Public License for more details. | ||
|
||
You should have received a copy of the GNU General Public License | ||
along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
""" | ||
|
||
import argparse | ||
import logging | ||
import os | ||
import sys | ||
from checkbox_support.lxd_support import LXD, LXDVM | ||
|
||
# Map vendor IDs to vendor names | ||
VENDOR_INFO = { | ||
"0x8086": ("Intel"), | ||
"0x15b3": ("Mellanox"), | ||
"0x14e4": ("Broadcom"), | ||
} | ||
|
||
# Number of virutal interfaces created for SRIOV Enabled Interfaces | ||
NUM_OF_VIRTUAL_IFACES = 1 | ||
|
||
|
||
def get_release_to_test(): | ||
try: | ||
import distro | ||
|
||
if distro.id() == "ubuntu-core": | ||
return "{}.04".format(distro.version()) | ||
return distro.version() | ||
except ImportError: | ||
import lsb_release | ||
|
||
return lsb_release.get_distro_information()["RELEASE"] | ||
|
||
|
||
def check_ubuntu_version(): | ||
logging.info("Check for 24.04 or greater") | ||
version = get_release_to_test() | ||
|
||
if float(version) < 24.04: | ||
raise ValueError( | ||
"Ubuntu 24.04 or greater is required, but found {}.".format( | ||
version | ||
) | ||
) | ||
logging.info("The system is 24.04 or greater, proceed") | ||
|
||
|
||
def check_interface_vendor(interface): | ||
""" | ||
Find the vendor of the network interface | ||
""" | ||
vendor_id_path = "/sys/class/net/{}/device/vendor".format(interface) | ||
|
||
if not os.path.exists(vendor_id_path): | ||
raise FileNotFoundError( | ||
"Vendor ID path {} not found".format(vendor_id_path) | ||
) | ||
|
||
with open(vendor_id_path, "r", encoding="utf-8") as file: | ||
vendor_id = file.read().strip() | ||
|
||
if vendor_id not in VENDOR_INFO: | ||
raise ValueError( | ||
"{} has an unknown vendor ID {}".format(interface, vendor_id) | ||
) | ||
|
||
vendor_name = VENDOR_INFO[vendor_id] | ||
if vendor_name == "Broadcom": | ||
raise NotImplementedError( | ||
"Broadcom SRIOV testing is not supported at this time" | ||
) | ||
|
||
logging.info("The interface %s is a(n) %s NIC", interface, vendor_name) | ||
|
||
|
||
def is_sriov_capable(interface): | ||
""" | ||
Check if the specified network interface is SR-IOV capable and | ||
configured to support at least one Virtual Function. | ||
""" | ||
sriov_path = "/sys/class/net/{}/device/sriov_numvfs".format(interface) | ||
num_vfs = NUM_OF_VIRTUAL_IFACES | ||
|
||
try: | ||
# Check if the interface supports SR-IOV | ||
logging.info("checking if sriov_numvfs exists") | ||
if not os.path.exists(sriov_path): | ||
raise FileNotFoundError( | ||
"SR-IOV not supported or interface {} does not exist.".format( | ||
interface | ||
) | ||
) | ||
|
||
logging.info( | ||
"SR-IOV before change {} VFs on interface {}.".format( | ||
num_vfs, interface | ||
) | ||
) | ||
# First, disable VFs before changing the number to avoid issues | ||
logging.info("Setting numvfs to zero") | ||
with open(sriov_path, "w", encoding="utf-8") as f: | ||
f.write("0") | ||
|
||
# Set the desired number of VFs | ||
logging.info("Setting numvfs to %d", num_vfs) | ||
with open(sriov_path, "w", encoding="utf-8") as f: | ||
f.write(str(num_vfs)) | ||
|
||
logging.info( | ||
"SR-IOV enabled with {} VFs on interface {}.".format( | ||
num_vfs, interface | ||
) | ||
) | ||
|
||
except (IOError, FileNotFoundError) as e: | ||
logging.info("Failed to enable SR-IOV on {}: {}".format(interface, e)) | ||
sys.exit(1) | ||
|
||
except Exception as e: | ||
logging.info("An error occurred: {}".format(e)) | ||
sys.exit(1) | ||
pedro-avalos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
def cleanup_sriov(interface): | ||
sriov_path = "/sys/class/net/{}/device/sriov_numvfs".format(interface) | ||
try: | ||
# Check if the interface SR-IOV exists | ||
logging.info("checking if sriov_numvfs exists") | ||
if not os.path.exists(sriov_path): | ||
raise FileNotFoundError( | ||
"SR-IOV interface {} does not exist.".format(interface) | ||
) | ||
|
||
# First, disable VFs after testing | ||
logging.info("Setting numvfs to zero") | ||
with open(sriov_path, "w", encoding="utf-8") as f: | ||
f.write("0") | ||
|
||
except FileNotFoundError as e: | ||
logging.info("Failed to disable SR-IOV on {}: {}".format(interface, e)) | ||
sys.exit(1) | ||
|
||
except Exception as e: | ||
logging.info("An error occurred: {}".format(e)) | ||
sys.exit(1) | ||
|
||
|
||
def test_lxd_sriov(args): | ||
logging.info("Starting lxd SRIOV Test") | ||
verify_cmds = 'bash -c "lspci | grep Virtual"' | ||
options = ["--network", "lab_sriov"] | ||
network_cmd = "lxc network create lab_sriov --type=sriov parent={}".format( | ||
args.interface | ||
) | ||
|
||
check_ubuntu_version() | ||
check_interface_vendor(args.interface) | ||
is_sriov_capable(args.interface) | ||
|
||
with LXD(args.template, args.rootfs) as instance: | ||
logging.info("Create sriov network for lxc") | ||
instance.run("lxc network delete lab_sriov", ignore_errors=True) | ||
instance.run(network_cmd) | ||
|
||
logging.info("Launching container: %s", instance.name) | ||
instance.launch(options) | ||
|
||
logging.info("Waiting for %s to be up", instance.name) | ||
instance.wait_until_running() | ||
|
||
instance.run(verify_cmds, on_guest=True) | ||
|
||
instance.run("lxc network delete lab_sriov") | ||
cleanup_sriov(args.interface) | ||
|
||
|
||
def test_lxd_vm_sriov(args): | ||
logging.info("Starting lxd vm SRIOV") | ||
verify_cmds = 'bash -c "lspci | grep Virtual"' | ||
options = ["-c", "security.secureboot=false", "--network", "lab_sriov"] | ||
network_cmd = "lxc network create lab_sriov --type=sriov parent={}".format( | ||
args.interface | ||
) | ||
|
||
check_ubuntu_version() | ||
check_interface_vendor(args.interface) | ||
is_sriov_capable(args.interface) | ||
|
||
with LXDVM(args.template, args.image) as instance: | ||
logging.info("Create sriov network for lxc vm") | ||
instance.run("lxc network delete lab_sriov", ignore_errors=True) | ||
instance.run(network_cmd) | ||
|
||
logging.info("Launching virtual machine: %s", instance.name) | ||
instance.launch(options) | ||
|
||
logging.info("Waiting for %s to be up", instance.name) | ||
instance.wait_until_running() | ||
|
||
logging.info("running a simple command") | ||
instance.run(verify_cmds, on_guest=True) | ||
|
||
instance.run("lxc network delete lab_sriov") | ||
cleanup_sriov(args.interface) | ||
|
||
|
||
def main(): | ||
|
||
parser = argparse.ArgumentParser(description="SRIOV Test") | ||
subparsers = parser.add_subparsers() | ||
|
||
# Main cli options | ||
lxd_sriov_parser = subparsers.add_parser( | ||
"lxd", help=("Run the SRIOV test on LXD validation test") | ||
) | ||
lxd_vm_sriov_parser = subparsers.add_parser( | ||
"lxdvm", help=("Run the SRIOV test on VM validation test") | ||
) | ||
|
||
parser.add_argument( | ||
"--debug", | ||
dest="log_level", | ||
action="store_const", | ||
const=logging.DEBUG, | ||
default=logging.INFO, | ||
) | ||
|
||
parser.add_argument( | ||
"--interface", type=str, default=None, help="SRIOV Interface" | ||
) | ||
|
||
# Sub test options | ||
lxd_sriov_parser.add_argument( | ||
"--template", type=str, default=os.getenv("LXD_TEMPLATE") | ||
) | ||
|
||
lxd_sriov_parser.add_argument( | ||
"--rootfs", type=str, default=os.getenv("LXD_ROOTFS") | ||
) | ||
|
||
lxd_sriov_parser.set_defaults(func=test_lxd_sriov) | ||
|
||
# Sub test options | ||
lxd_vm_sriov_parser.add_argument( | ||
"--template", type=str, default=os.getenv("LXD_TEMPLATE") | ||
) | ||
|
||
lxd_vm_sriov_parser.add_argument( | ||
"--image", type=str, default=os.getenv("KVM_IMAGE") | ||
) | ||
|
||
lxd_vm_sriov_parser.set_defaults(func=test_lxd_vm_sriov) | ||
|
||
args = parser.parse_args() | ||
|
||
logging.basicConfig(level=args.log_level) | ||
|
||
# silence normal output from requests module | ||
logging.getLogger("requests").setLevel(logging.WARNING) | ||
logging.getLogger("urllib3").setLevel(logging.WARNING) | ||
|
||
args.func(args) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.