summaryrefslogtreecommitdiff
path: root/netplan/cli/sriov.py
diff options
context:
space:
mode:
Diffstat (limited to 'netplan/cli/sriov.py')
-rw-r--r--netplan/cli/sriov.py114
1 files changed, 39 insertions, 75 deletions
diff --git a/netplan/cli/sriov.py b/netplan/cli/sriov.py
index b83e37f..ed81209 100644
--- a/netplan/cli/sriov.py
+++ b/netplan/cli/sriov.py
@@ -182,30 +182,24 @@ def unbind_vfs(vfs: typing.Iterable[PCIDevice], driver) -> typing.Iterable[PCIDe
return unbound_vfs
-def _get_target_interface(interfaces, config_manager, pf_link, pfs):
+def _get_target_interface(interfaces, np_state, pf_link, pfs):
if pf_link not in pfs:
# handle the match: syntax, get the actual device name
- pf_dev = config_manager.ethernets[pf_link]
- pf_match = pf_dev.get('match')
- if pf_match:
+ pf_dev = np_state[pf_link]
+ if pf_dev.has_match:
# now here it's a bit tricky
- set_name = pf_dev.get('set-name')
+ set_name = pf_dev.set_name
if set_name and set_name in interfaces:
# if we had a match: stanza and set-name: this means we should
# assume that, if found, the interface has already been
# renamed - use the new name
pfs[pf_link] = set_name
else:
- # no set-name (or interfaces not yet renamed) so we need to do
- # the matching ourselves
- by_name = pf_match.get('name')
- by_mac = pf_match.get('macaddress')
- by_driver = pf_match.get('driver')
-
for interface in interfaces:
- if ((by_name and not utils.is_interface_matching_name(interface, by_name)) or
- (by_mac and not utils.is_interface_matching_macaddress(interface, by_mac)) or
- (by_driver and not utils.is_interface_matching_driver_name(interface, by_driver))):
+ if not pf_dev.match_interface(
+ itf_name=interface,
+ itf_driver=utils.get_interface_driver_name(interface),
+ itf_mac=utils.get_interface_macaddress(interface)):
continue
# we have a matching PF
# store the matching interface in the dictionary of
@@ -238,53 +232,27 @@ def _get_pci_slot_name(netdev):
raise RuntimeError('failed parsing PCI slot name for %s: %s' % (netdev, str(e)))
-def get_vf_count_and_functions(interfaces, config_manager,
+def get_vf_count_and_functions(interfaces, np_state,
vf_counts, vfs, pfs):
"""
Go through the list of netplan ethernet devices and identify which are
PFs and VFs, matching the former with actual networking interfaces.
Count how many VFs each PF will need.
"""
- explicit_counts = {}
- for ethernet, settings in config_manager.ethernets.items():
- if not settings:
- continue
- if ethernet == 'renderer':
+ for nid, netdef in np_state.ethernets.items():
+ if netdef.sriov_link and _get_target_interface(interfaces, np_state, netdef.sriov_link.id, pfs):
+ vfs[nid] = None
+
+ try:
+ count = netdef.vf_count
+ except libnetplan.LibNetplanException as e:
+ raise ConfigurationError(*e.args)
+ if count == 0:
continue
- # we now also support explicitly stating how many VFs should be
- # allocated for a PF
- explicit_num = settings.get('virtual-function-count')
- if explicit_num:
- pf = _get_target_interface(interfaces, config_manager, ethernet, pfs)
- if pf:
- explicit_counts[pf] = explicit_num
- continue
-
- pf_link = settings.get('link')
- if pf_link and pf_link in config_manager.ethernets:
- _get_target_interface(interfaces, config_manager, pf_link, pfs)
-
- if pf_link in pfs:
- vf_counts[pfs[pf_link]] += 1
- else:
- logging.warning('could not match physical interface for the defined PF: %s' % pf_link)
- # continue looking for other VFs
- continue
-
- # we can't yet perform matching on VFs as those are only
- # created later - but store, for convenience, all the valid
- # VFs that we encounter so far
- vfs[ethernet] = None
-
- # sanity check: since we can explicitly state the VF count, make sure
- # that this number isn't smaller than the actual number of VFs declared
- # the explicit number also overrides the number of actual VFs
- for pf, count in explicit_counts.items():
- if pf in vf_counts and vf_counts[pf] > count:
- raise ConfigurationError(
- 'more VFs allocated than the explicit size declared: %s > %s' % (vf_counts[pf], count))
- vf_counts[pf] = count
+ pf = _get_target_interface(interfaces, np_state, nid, pfs)
+ if pf:
+ vf_counts[pf] = count
def set_numvfs_for_pf(pf, vf_count):
@@ -350,7 +318,7 @@ def perform_hardware_specific_quirks(pf):
combined_id = ':'.join([vendor_id, device_id])
quirk_devices = () # TODO: add entries to the list
- if combined_id in quirk_devices:
+ if combined_id in quirk_devices: # pragma: nocover (empty quirk_devices)
# some devices need special handling, so this is the place
# Currently this part is empty, but has been added as a preemptive
@@ -415,6 +383,7 @@ def apply_sriov_config(config_manager, rootdir='/'):
config_manager.parse()
interfaces = netifaces.interfaces()
+ np_state = config_manager.np_state
# for sr-iov devices, we identify VFs by them having a link: field
# pointing to an PF. So let's browse through all ethernet devices,
@@ -427,7 +396,7 @@ def apply_sriov_config(config_manager, rootdir='/'):
pfs = {}
get_vf_count_and_functions(
- interfaces, config_manager, vf_counts, vfs, pfs)
+ interfaces, np_state, vf_counts, vfs, pfs)
# setup the required number of VFs per PF
# at the same time store which PFs got changed in case the NICs
@@ -456,22 +425,17 @@ def apply_sriov_config(config_manager, rootdir='/'):
# filtered VLANs for those.
# XXX: does matching those even make sense?
for vf in vfs:
- settings = config_manager.ethernets.get(vf)
- match = settings.get('match')
- if match:
+ netdef = np_state[vf]
+ if netdef.has_match:
# right now we only match by name, as I don't think matching per
# driver and/or macaddress makes sense
- by_name = match.get('name')
- # by_mac = match.get('macaddress')
- # by_driver = match.get('driver')
# TODO: print warning if other matches are provided
for interface in interfaces:
- if by_name and not utils.is_interface_matching_name(interface, by_name):
- continue
- if vf in vfs and vfs[vf]:
- raise ConfigurationError('matched more than one interface for a VF device: %s' % vf)
- vfs[vf] = interface
+ if netdef.match_interface(itf_name=interface):
+ if vf in vfs and vfs[vf]:
+ raise ConfigurationError('matched more than one interface for a VF device: %s' % vf)
+ vfs[vf] = interface
else:
if vf in interfaces:
vfs[vf] = vf
@@ -495,31 +459,31 @@ def apply_sriov_config(config_manager, rootdir='/'):
bind_vfs(pcidev.vfs, pcidev.driver)
filtered_vlans_set = set()
- for vlan, settings in config_manager.vlans.items():
+ for vlan, netdef in np_state.vlans.items():
# there is a special sriov vlan renderer that one can use to mark
# a selected vlan to be done in hardware (VLAN filtering)
- if settings.get('renderer') == 'sriov':
+ if netdef.has_sriov_vlan_filter:
# this only works for SR-IOV VF interfaces
- link = settings.get('link')
- vlan_id = settings.get('id')
- vf = vfs.get(link)
+ link = netdef.vlan_link
+ vlan_id = netdef.vlan_id
+
+ vf = vfs.get(link.id)
if not vf:
# it is possible this is not an error, for instance when
# the configuration has been defined 'for the future'
# XXX: but maybe we should error out here as well?
logging.warning(
- 'SR-IOV vlan defined for %s but link %s is either not a VF or has no matches' % (vlan, link))
+ 'SR-IOV vlan defined for %s but link %s is either not a VF or has no matches' % (vlan, link.id))
continue
# get the parent pf interface
# first we fetch the related vf netplan entry
- vf_parent_entry = config_manager.ethernets.get(link).get('link')
# and finally, get the matched pf interface
- pf = pfs.get(vf_parent_entry)
+ pf = pfs.get(link.sriov_link.id)
if vf in filtered_vlans_set:
raise ConfigurationError(
- 'interface %s for netplan device %s (%s) already has an SR-IOV vlan defined' % (vf, link, vlan))
+ 'interface %s for netplan device %s (%s) already has an SR-IOV vlan defined' % (vf, link.id, vlan))
# TODO: make sure that we don't apply the filter twice
apply_vlan_filter_for_vf(pf, vf, vlan, vlan_id)