Skip to content
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

Support for vf testing in enrt #375

Merged
merged 7 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lnst/Recipes/ENRT/BaremetalEnrtRecipe.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from lnst.Recipes.ENRT.BaseEnrtRecipe import BaseEnrtRecipe
from lnst.Recipes.ENRT.UseVfsMixin import UseVfsMixin
from lnst.Recipes.ENRT.PerfTestMixins import CommonPerfTestTweakMixin
from lnst.Recipes.ENRT.ConfigMixins.DisableTurboboostMixin import (
DisableTurboboostMixin,
Expand Down Expand Up @@ -55,6 +56,7 @@ def disable_turboboost_host_list(self):


class BaremetalEnrtRecipe(
UseVfsMixin,
BaremetalEnrtCommonMixins,
BaremetalEnrtMeasurementGenerators,
BaseEnrtRecipe,
Expand Down
58 changes: 1 addition & 57 deletions lnst/Recipes/ENRT/BaseSRIOVNetnsTcRecipe.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
from collections.abc import Collection
from dataclasses import dataclass
from itertools import zip_longest
from typing import Optional

from lnst.Common.Parameters import (
Param,
Expand All @@ -11,11 +8,11 @@
from lnst.Common.IpAddress import interface_addresses
from lnst.Controller import HostReq, DeviceReq, RecipeParam
from lnst.Controller.NetNamespace import NetNamespace
from lnst.Devices import RemoteDevice
from lnst.RecipeCommon.endpoints import EndpointPair, IPEndpoint
from lnst.RecipeCommon.Perf.Recipe import RecipeConf
from lnst.Recipes.ENRT.helpers import ip_endpoint_pairs
from lnst.Recipes.ENRT.BaremetalEnrtRecipe import BaremetalEnrtRecipe
from lnst.Recipes.ENRT.SRIOVDevices import SRIOVDevices
from lnst.RecipeCommon.Ping.PingEndpoints import PingEndpoints
from lnst.Recipes.ENRT.BaseEnrtRecipe import EnrtConfiguration
from lnst.Recipes.ENRT.ConfigMixins.OffloadSubConfigMixin import (
Expand All @@ -26,59 +23,6 @@
)


@dataclass
class SRIOVDevices():
"""
The class takes care of
1. creating the vfs
2. accessing the vfs by index or using next()
3. accessing the vf representors by index or using next()
3. accessing vf/vf representor pairs by index or using next()

For example:
```
host.eth0.eswitch_mode = "switchdev"
sriov_devices = SRIOVDevices(host.eth0, 2)

vfs = sriov_devices.vfs # all vf devices
vf_representors = sriov_devices.vf_reps # all vf representors

vf0, vf_rep0 = sriov_devices[0] # vf/vf_rep of first virtual function
vf1, vf_rep1 = sriov_devices[1] # vf/vf_rep of second virtual function

for vf, vf_rep in sriov_devices: # iteration over vf/vf_representor pairs
vf.up()
vf_rep.up()
```
"""
phys_dev: RemoteDevice
vfs: list[RemoteDevice]
vf_reps: Optional[list[RemoteDevice]] = None

def __init__(self, phys_dev: RemoteDevice, number_of_vfs: int = 1):
self.phys_dev = phys_dev
phys_dev.up_and_wait()
self.vfs, self.vf_reps = phys_dev.create_vfs(number_of_vfs)

for vf_index, vf in enumerate(self.vfs):
phys_dev.host.map_device(f"{phys_dev._id}_vf{vf_index}", {"ifname": vf.name})

for vf_rep_index, vf_rep in enumerate(self.vf_reps):
phys_dev.host.map_device(f"{phys_dev._id}_vf_rep{vf_index}", {"ifname": vf_rep.name})

def __iter__(self):
if self.vf_reps:
return zip(self.vfs, self.vf_reps, strict=True)

return zip_longest(self.vfs, [None])

def __getitem__(self, key):
if self.vf_reps:
return self.vfs[key], self.vf_reps[key]

return self.vfs[key], None


class BaseSRIOVNetnsTcRecipe(
CommonHWSubConfigMixin, OffloadSubConfigMixin, BaremetalEnrtRecipe
):
Expand Down
3 changes: 2 additions & 1 deletion lnst/Recipes/ENRT/BondRecipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,10 @@ def test_wide_configuration(self):
"""

host1, host2 = self.matched.host1, self.matched.host2
config = super().test_wide_configuration()

host1.bond0 = BondDevice(mode=self.params.bonding_mode,
miimon=self.params.miimon_value)
config = super().test_wide_configuration()

for dev in [host1.eth0, host1.eth1]:
dev.down()
Expand Down
59 changes: 59 additions & 0 deletions lnst/Recipes/ENRT/SRIOVDevices.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from dataclasses import dataclass
from itertools import zip_longest
from typing import Optional

from lnst.Devices import RemoteDevice


@dataclass
class SRIOVDevices():
"""
The class takes care of
1. creating the vfs
2. accessing the vfs by index or using next()
3. accessing the vf representors by index or using next()
3. accessing vf/vf representor pairs by index or using next()

For example:
```
host.eth0.eswitch_mode = "switchdev"
sriov_devices = SRIOVDevices(host.eth0, 2)

vfs = sriov_devices.vfs # all vf devices
vf_representors = sriov_devices.vf_reps # all vf representors

vf0, vf_rep0 = sriov_devices[0] # vf/vf_rep of first virtual function
vf1, vf_rep1 = sriov_devices[1] # vf/vf_rep of second virtual function

for vf, vf_rep in sriov_devices: # iteration over vf/vf_representor pairs
vf.up()
vf_rep.up()
```
"""
phys_dev: RemoteDevice
vfs: list[RemoteDevice]
vf_reps: Optional[list[RemoteDevice]] = None

def __init__(self, phys_dev: RemoteDevice, number_of_vfs: int = 1):
self.phys_dev = phys_dev
phys_dev.up_and_wait()
self.vfs, self.vf_reps = phys_dev.create_vfs(number_of_vfs)

for vf_index, vf in enumerate(self.vfs):
phys_dev.host.map_device(f"{phys_dev._id}_vf{vf_index}", {"ifname": vf.name})

if self.vf_reps is not None:
for vf_rep_index, vf_rep in enumerate(self.vf_reps):
phys_dev.host.map_device(f"{phys_dev._id}_vf_rep{vf_rep_index}", {"ifname": vf_rep.name})

def __iter__(self):
if self.vf_reps:
return zip(self.vfs, self.vf_reps, strict=True)

return zip_longest(self.vfs, [None])

def __getitem__(self, key):
if self.vf_reps:
return self.vfs[key], self.vf_reps[key]

return self.vfs[key], None
3 changes: 1 addition & 2 deletions lnst/Recipes/ENRT/TeamRecipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,11 @@ def test_wide_configuration(self):
| host2.eth0 = 192.168.10.2/24 and fc00:0:0:1::2/64
"""
host1, host2 = self.matched.host1, self.matched.host2
config = super().test_wide_configuration()

teamd_config = {'runner': {'name': self.params.runner_name}}
host1.team0 = TeamDevice(config=teamd_config)

config = super().test_wide_configuration()

for dev in [host1.eth0, host1.eth1]:
dev.down()
host1.team0.slave_add(dev)
Expand Down
3 changes: 1 addition & 2 deletions lnst/Recipes/ENRT/TeamVsBondRecipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,12 @@ class TeamVsBondRecipe(PerfReversibleFlowMixin, CommonHWSubConfigMixin,

def test_wide_configuration(self):
host1, host2 = self.matched.host1, self.matched.host2
config = super().test_wide_configuration()

host1.team0 = TeamDevice(config={'runner': {'name': self.params.runner_name}})

host2.bond0 = BondDevice(mode=self.params.bonding_mode,
miimon=self.params.miimon_value)

config = super().test_wide_configuration()
ipv4_addr = interface_addresses(self.params.net_ipv4)
ipv6_addr = interface_addresses(self.params.net_ipv6)

Expand Down
65 changes: 65 additions & 0 deletions lnst/Recipes/ENRT/UseVfsMixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from lnst.Common.Parameters import BoolParam
from lnst.Controller.Requirements import DeviceReq
from lnst.Recipes.ENRT.SRIOVDevices import SRIOVDevices


class UseVfsMixin:
"""
Mixin allows any ENRT recipe to use virtual function (VF) interfaces
instead of physical interfaces defined by DeviceReq requirements.

VF interfaces are created automatically and DeviceReq handles are replaced
with VF Device instances. This allows user to interact with the network
interfaces without additional changes to the code of recipe.

There are some limitations, for example pause frames cannot be configured
since the VF do not support these.
"""

use_vfs = BoolParam(default=False)

def test_wide_configuration(self):
config = super().test_wide_configuration()

if not self.params.use_vfs:
return config

config.vf_config = {}
for host_key, host_req in self.req:
dev_names = [key for key, value in host_req if isinstance(value, DeviceReq)]
host = getattr(self.matched, host_key)

# remap_pfs_to_vfs
for dev_name in dev_names:
dev = getattr(host, dev_name)
sriov_devices = SRIOVDevices(dev, 1)
vf_dev = sriov_devices.vfs[0]
host.map_device(dev_name, {"ifname": vf_dev.name})

host_config = config.vf_config.setdefault(host, [])
host_config.append(sriov_devices)

return config

def test_wide_deconfiguration(self, config):
if self.params.use_vfs:
for host, sriov_devices_list in config.vf_config.items():
for sriov_devices in sriov_devices_list:
vf_dev = sriov_devices.vfs[0]
host.map_device(vf_dev._id, {"ifname": sriov_devices.phys_dev.name})
sriov_devices.phys_dev.delete_vfs()

super().test_wide_deconfiguration(config)

def generate_test_wide_description(self, config):
description = super().generate_test_wide_description(config)

if self.params.use_vfs:
description += [
f"Using vf device {vf_dev.name} of pf {sriov_devices.phys_dev.name} for DeviceReq {host.hostid}.{vf_dev._id}"
for host, sriov_devices_list in config.vf_config.items()
for sriov_devices in sriov_devices_list
for vf_dev in sriov_devices.vfs
]

return description
2 changes: 1 addition & 1 deletion lnst/Recipes/ENRT/VlansOverBondRecipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ def test_wide_configuration(self):
| host2.vlan2 = 192.168.30.2/24 and fc00:0:0:3::2/64
"""
host1, host2 = self.matched.host1, self.matched.host2
config = super().test_wide_configuration()

host1.bond0 = BondDevice(mode=self.params.bonding_mode,
miimon=self.params.miimon_value)
Expand All @@ -129,7 +130,6 @@ def test_wide_configuration(self):
host2.vlan1 = VlanDevice(realdev=host2.eth0, vlan_id=self.params.vlan1_id)
host2.vlan2 = VlanDevice(realdev=host2.eth0, vlan_id=self.params.vlan2_id)

config = super().test_wide_configuration()
config.track_device(host1.bond0)

vlan0_ipv4_addr = interface_addresses(self.params.vlan0_ipv4)
Expand Down
2 changes: 1 addition & 1 deletion lnst/Recipes/ENRT/VlansOverTeamRecipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class VlansOverTeamRecipe(PerfReversibleFlowMixin, VlanPingEvaluatorMixin,

def test_wide_configuration(self):
host1, host2 = self.matched.host1, self.matched.host2
config = super().test_wide_configuration()

host1.team0 = TeamDevice(config={'runner': {'name': self.params.runner_name}})
for dev in [host1.eth0, host1.eth1]:
Expand All @@ -71,7 +72,6 @@ def test_wide_configuration(self):
host2.vlan1 = VlanDevice(realdev=host2.eth0, vlan_id=self.params.vlan1_id)
host2.vlan2 = VlanDevice(realdev=host2.eth0, vlan_id=self.params.vlan2_id)

config = super().test_wide_configuration()
config.track_device(host1.team0)

vlan0_ipv4_addr = interface_addresses(self.params.vlan0_ipv4)
Expand Down
3 changes: 1 addition & 2 deletions lnst/Recipes/ENRT/VlansRecipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def test_wide_configuration(self):

"""
host1, host2 = self.matched.host1, self.matched.host2
config = super().test_wide_configuration()

host1.eth0.down()
host2.eth0.down()
Expand All @@ -96,8 +97,6 @@ def test_wide_configuration(self):
host2.vlan1 = VlanDevice(realdev=host2.eth0, vlan_id=self.params.vlan1_id)
host2.vlan2 = VlanDevice(realdev=host2.eth0, vlan_id=self.params.vlan2_id)

config = super().test_wide_configuration()

vlan0_ipv4_addr = interface_addresses(self.params.vlan0_ipv4)
vlan0_ipv6_addr = interface_addresses(self.params.vlan0_ipv6)
vlan1_ipv4_addr = interface_addresses(self.params.vlan1_ipv4)
Expand Down
Loading