Skip to content

Commit b4f3b2b

Browse files
committed
vif: Stop using getattr for VIF lookups
'getattr' is really powerful and we make extensive use of it in nova. However, the way we've used it for VIF lookups, where we use it to retrieve functions by a key, seems to be a bit of an anti-pattern. Not only does it completely break static code coverage analysers that we can use to help us root out code that's not tested (or is tested but is never used in production) but, more importantly, it makes it so much more difficult to figure out what on earth is going on in an already complex part of the codebase. Be verbose and, in the absence of a true switch statement in Python, use simple if-else blocks to do the lookups. Due to how this is done, we're able to remove a few previously no-op functions. Funnily enough, this actually results in fewer LOC despite being more explicit. #winning? Change-Id: Idf08adca1e3a0d19e20bca2447c83f7372516cb7 Signed-off-by: Stephen Finucane <[email protected]>
1 parent 17bc342 commit b4f3b2b

File tree

2 files changed

+129
-152
lines changed

2 files changed

+129
-152
lines changed

nova/network/os_vif_util.py

Lines changed: 43 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818
versioned object model os_vif.objects.*
1919
'''
2020

21-
import sys
22-
2321
from os_vif import objects
2422
from oslo_config import cfg
2523
from oslo_log import log as logging
@@ -32,6 +30,13 @@
3230
LOG = logging.getLogger(__name__)
3331
CONF = cfg.CONF
3432

33+
LEGACY_VIFS = {
34+
model.VIF_TYPE_DVS, model.VIF_TYPE_IOVISOR, model.VIF_TYPE_802_QBG,
35+
model.VIF_TYPE_802_QBH, model.VIF_TYPE_HW_VEB, model.VIF_TYPE_HOSTDEV,
36+
model.VIF_TYPE_IB_HOSTDEV, model.VIF_TYPE_MIDONET, model.VIF_TYPE_TAP,
37+
model.VIF_TYPE_MACVTAP
38+
}
39+
3540

3641
def _get_vif_name(vif):
3742
"""Get a VIF device name
@@ -495,82 +500,6 @@ def _nova_to_osvif_vif_vrouter(vif):
495500
return obj
496501

497502

498-
# VIF_TYPE_DVS = 'dvs'
499-
def _nova_to_osvif_vif_dvs(vif):
500-
raise NotImplementedError()
501-
502-
503-
# VIF_TYPE_IOVISOR = 'iovisor'
504-
def _nova_to_osvif_vif_iovisor(vif):
505-
raise NotImplementedError()
506-
507-
508-
# VIF_TYPE_802_QBG = '802.1qbg'
509-
def _nova_to_osvif_vif_802_1qbg(vif):
510-
raise NotImplementedError()
511-
512-
513-
# VIF_TYPE_802_QBH = '802.1qbh'
514-
def _nova_to_osvif_vif_802_1qbh(vif):
515-
raise NotImplementedError()
516-
517-
518-
# VIF_TYPE_HW_VEB = 'hw_veb'
519-
def _nova_to_osvif_vif_hw_veb(vif):
520-
raise NotImplementedError()
521-
522-
523-
# VIF_TYPE_IB_HOSTDEV = 'ib_hostdev'
524-
def _nova_to_osvif_vif_ib_hostdev(vif):
525-
raise NotImplementedError()
526-
527-
528-
# VIF_TYPE_MIDONET = 'midonet'
529-
def _nova_to_osvif_vif_midonet(vif):
530-
raise NotImplementedError()
531-
532-
533-
# VIF_TYPE_TAP = 'tap'
534-
def _nova_to_osvif_vif_tap(vif):
535-
raise NotImplementedError()
536-
537-
538-
# VIF_TYPE_MACVTAP = 'macvtap'
539-
def _nova_to_osvif_vif_macvtap(vif):
540-
raise NotImplementedError()
541-
542-
543-
# VIF_TYPE_HOSTDEV = 'hostdev_physical'
544-
def _nova_to_osvif_vif_hostdev_physical(vif):
545-
raise NotImplementedError()
546-
547-
548-
# VIF_TYPE_BINDING_FAILED = 'binding_failed'
549-
def _nova_to_osvif_vif_binding_failed(vif):
550-
"""Special handler for the "binding_failed" vif type.
551-
552-
The "binding_failed" vif type indicates port binding to a host failed
553-
and we are trying to plug the vifs again, which will fail because we
554-
do not know the actual real vif type, like ovs, bridge, etc. We raise
555-
NotImplementedError to indicate to the caller that we cannot handle
556-
this type of vif rather than the generic "Unsupported VIF type" error
557-
in nova_to_osvif_vif.
558-
"""
559-
raise NotImplementedError()
560-
561-
562-
# VIF_TYPE_UNBOUND = 'unbound'
563-
def _nova_to_osvif_vif_unbound(vif):
564-
"""Special handler for the "unbound" vif type.
565-
566-
The "unbound" vif type indicates a port has not been hooked up to backend
567-
network driver (OVS, linux bridge, ...). We raise NotImplementedError to
568-
indicate to the caller that we cannot handle this type of vif rather than
569-
the generic "Unsupported VIF type" error in nova_to_osvif_vif.
570-
"""
571-
raise NotImplementedError()
572-
573-
574503
def nova_to_osvif_vif(vif):
575504
"""Convert a Nova VIF model to an os-vif object
576505
@@ -586,19 +515,40 @@ def nova_to_osvif_vif(vif):
586515

587516
LOG.debug("Converting VIF %s", vif)
588517

589-
funcname = "_nova_to_osvif_vif_" + vif['type'].replace(".", "_")
590-
func = getattr(sys.modules[__name__], funcname, None)
591-
592-
if not func:
593-
raise exception.NovaException(
594-
"Unsupported VIF type %(type)s convert '%(func)s'" %
595-
{'type': vif['type'], 'func': funcname})
596-
597-
try:
598-
vifobj = func(vif)
599-
LOG.debug("Converted object %s", vifobj)
600-
return vifobj
601-
except NotImplementedError:
602-
LOG.debug("No conversion for VIF type %s yet",
603-
vif['type'])
518+
vif_type = vif['type']
519+
520+
if vif_type in LEGACY_VIFS:
521+
# We want to explicitly fall back to the legacy path for these VIF
522+
# types
523+
LOG.debug('No conversion for VIF type %s yet', vif_type)
604524
return None
525+
526+
if vif_type in {model.VIF_TYPE_BINDING_FAILED, model.VIF_TYPE_UNBOUND}:
527+
# These aren't real VIF types. VIF_TYPE_BINDING_FAILED indicates port
528+
# binding to a host failed and we are trying to plug the VIFs again,
529+
# which will fail because we do not know the actual real VIF type, like
530+
# VIF_TYPE_OVS, VIF_TYPE_BRIDGE, etc. VIF_TYPE_UNBOUND, by comparison,
531+
# is the default VIF type of a driver when it is not bound to any host,
532+
# i.e. we have not set the host ID in the binding driver. This should
533+
# also only happen in error cases.
534+
# TODO(stephenfin): We probably want a more meaningful log here
535+
LOG.debug('No conversion for VIF type %s yet', vif_type)
536+
return None
537+
538+
if vif_type == model.VIF_TYPE_OVS:
539+
vif_obj = _nova_to_osvif_vif_ovs(vif)
540+
elif vif_type == model.VIF_TYPE_IVS:
541+
vif_obj = _nova_to_osvif_vif_ivs(vif)
542+
elif vif_type == model.VIF_TYPE_BRIDGE:
543+
vif_obj = _nova_to_osvif_vif_bridge(vif)
544+
elif vif_type == model.VIF_TYPE_AGILIO_OVS:
545+
vif_obj = _nova_to_osvif_vif_agilio_ovs(vif)
546+
elif vif_type == model.VIF_TYPE_VHOSTUSER:
547+
vif_obj = _nova_to_osvif_vif_vhostuser(vif)
548+
elif vif_type == model.VIF_TYPE_VROUTER:
549+
vif_obj = _nova_to_osvif_vif_vrouter(vif)
550+
else:
551+
raise exception.NovaException('Unsupported VIF type %s' % vif_type)
552+
553+
LOG.debug('Converted object %s', vif_obj)
554+
return vif_obj

nova/virt/libvirt/vif.py

Lines changed: 86 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import os_vif
2424
from os_vif import exception as osv_exception
2525
from os_vif.objects import fields as osv_fields
26+
from os_vif.objects import vif as osv_vifs
2627
from oslo_concurrency import processutils
2728
from oslo_log import log as logging
2829
from oslo_utils import strutils
@@ -120,9 +121,6 @@ def set_vf_interface_vlan(pci_addr, mac_addr, vlan=0):
120121
class LibvirtGenericVIFDriver(object):
121122
"""Generic VIF driver for libvirt networking."""
122123

123-
def _normalize_vif_type(self, vif_type):
124-
return vif_type.replace('2.1q', '2q')
125-
126124
def get_vif_devname(self, vif):
127125
if 'devname' in vif:
128126
return vif['devname']
@@ -432,6 +430,10 @@ def get_config_tap(self, instance, vif, image_meta,
432430

433431
return conf
434432

433+
def get_config_ib_hostdev(self, instance, vif, image_meta,
434+
inst_type, virt_type, host):
435+
return self.get_base_hostdev_pci_config(vif)
436+
435437
def _get_virtio_queue_sizes(self, host):
436438
"""Returns rx/tx queue sizes configured or (None, None)
437439
@@ -464,10 +466,6 @@ def _get_virtio_queue_sizes(self, host):
464466
tx = None
465467
return rx, tx
466468

467-
def get_config_ib_hostdev(self, instance, vif, image_meta,
468-
inst_type, virt_type, host):
469-
return self.get_base_hostdev_pci_config(vif)
470-
471469
def _set_config_VIFGeneric(self, instance, vif, conf, host):
472470
dev = vif.vif_name
473471
designer.set_vif_host_backend_ethernet_config(conf, dev, host)
@@ -522,14 +520,12 @@ def _set_config_VIFPortProfileOpenVSwitch(self, profile, conf):
522520

523521
def _set_config_VIFPortProfile(self, instance, vif, conf):
524522
# Set any port profile that may be required
525-
profilefunc = "_set_config_" + vif.port_profile.obj_name()
526-
func = getattr(self, profilefunc, None)
527-
if not func:
523+
profile_name = vif.port_profile.obj_name()
524+
if profile_name == 'VIFPortProfileOpenVSwitch':
525+
self._set_config_VIFPortProfileOpenVSwitch(vif.port_profile, conf)
526+
else:
528527
raise exception.InternalError(
529-
_("Unsupported VIF port profile type %(obj)s func %(func)s") %
530-
{'obj': vif.port_profile.obj_name(), 'func': profilefunc})
531-
532-
func(vif.port_profile, conf)
528+
_('Unsupported VIF port profile type %s') % profile_name)
533529

534530
def _get_config_os_vif(self, instance, vif, image_meta, inst_type,
535531
virt_type, host, vnic_type):
@@ -552,13 +548,19 @@ def _get_config_os_vif(self, instance, vif, image_meta, inst_type,
552548
host)
553549

554550
# Do the VIF type specific config
555-
viffunc = "_set_config_" + vif.obj_name()
556-
func = getattr(self, viffunc, None)
557-
if not func:
551+
if isinstance(vif, osv_vifs.VIFGeneric):
552+
self._set_config_VIFGeneric(instance, vif, conf, host)
553+
elif isinstance(vif, osv_vifs.VIFBridge):
554+
self._set_config_VIFBridge(instance, vif, conf, host)
555+
elif isinstance(vif, osv_vifs.VIFOpenVSwitch):
556+
self._set_config_VIFOpenVSwitch(instance, vif, conf, host)
557+
elif isinstance(vif, osv_vifs.VIFVHostUser):
558+
self._set_config_VIFVHostUser(instance, vif, conf, host)
559+
elif isinstance(vif, osv_vifs.VIFHostDevice):
560+
self._set_config_VIFHostDevice(instance, vif, conf, host)
561+
else:
558562
raise exception.InternalError(
559-
_("Unsupported VIF type %(obj)s func %(func)s") %
560-
{'obj': vif.obj_name(), 'func': viffunc})
561-
func(instance, vif, conf, host)
563+
_("Unsupported VIF type %s") % vif.obj_name())
562564

563565
# not all VIF types support bandwidth configuration
564566
# https://github.com/libvirt/libvirt/blob/568a41722/src/conf/netdev_bandwidth_conf.h#L38
@@ -596,13 +598,29 @@ def get_config(self, instance, vif, image_meta,
596598
vnic_type)
597599

598600
# Legacy non-os-vif codepath
599-
vif_slug = self._normalize_vif_type(vif_type)
600-
func = getattr(self, 'get_config_%s' % vif_slug, None)
601-
if not func:
602-
raise exception.InternalError(
603-
_("Unexpected vif_type=%s") % vif_type)
604-
return func(instance, vif, image_meta,
605-
inst_type, virt_type, host)
601+
args = (instance, vif, image_meta, inst_type, virt_type, host)
602+
if vif_type == network_model.VIF_TYPE_IOVISOR:
603+
return self.get_config_iovisor(*args)
604+
elif vif_type == network_model.VIF_TYPE_BRIDGE:
605+
return self.get_config_bridge(*args)
606+
elif vif_type == network_model.VIF_TYPE_802_QBG:
607+
return self.get_config_802qbg(*args)
608+
elif vif_type == network_model.VIF_TYPE_802_QBH:
609+
return self.get_config_802qbh(*args)
610+
elif vif_type == network_model.VIF_TYPE_HW_VEB:
611+
return self.get_config_hw_veb(*args)
612+
elif vif_type == network_model.VIF_TYPE_HOSTDEV:
613+
return self.get_config_hostdev_physical(*args)
614+
elif vif_type == network_model.VIF_TYPE_MACVTAP:
615+
return self.get_config_macvtap(*args)
616+
elif vif_type == network_model.VIF_TYPE_MIDONET:
617+
return self.get_config_midonet(*args)
618+
elif vif_type == network_model.VIF_TYPE_TAP:
619+
return self.get_config_tap(*args)
620+
elif vif_type == network_model.VIF_TYPE_IB_HOSTDEV:
621+
return self.get_config_ib_hostdev(*args)
622+
623+
raise exception.InternalError(_('Unexpected vif_type=%s') % vif_type)
606624

607625
def plug_ib_hostdev(self, instance, vif):
608626
fabric = vif.get_physical_network()
@@ -621,12 +639,6 @@ def plug_ib_hostdev(self, instance, vif):
621639
LOG.exception(_("Failed while plugging ib hostdev vif"),
622640
instance=instance)
623641

624-
def plug_802qbg(self, instance, vif):
625-
pass
626-
627-
def plug_802qbh(self, instance, vif):
628-
pass
629-
630642
def plug_hw_veb(self, instance, vif):
631643
# TODO(vladikr): This code can be removed once the minimum version of
632644
# Libvirt is incleased above 1.3.5, as vlan will be set by libvirt
@@ -642,9 +654,6 @@ def plug_hw_veb(self, instance, vif):
642654
if trusted:
643655
linux_net.set_vf_trusted(vif['profile']['pci_slot'], True)
644656

645-
def plug_hostdev_physical(self, instance, vif):
646-
pass
647-
648657
def plug_macvtap(self, instance, vif):
649658
vif_details = vif['details']
650659
vlan = vif_details.get(network_model.VIF_DETAILS_VLAN)
@@ -726,13 +735,27 @@ def plug(self, instance, vif):
726735
return
727736

728737
# Legacy non-os-vif codepath
729-
vif_slug = self._normalize_vif_type(vif_type)
730-
func = getattr(self, 'plug_%s' % vif_slug, None)
731-
if not func:
738+
if vif_type == network_model.VIF_TYPE_IB_HOSTDEV:
739+
self.plug_ib_hostdev(instance, vif)
740+
elif vif_type == network_model.VIF_TYPE_HW_VEB:
741+
self.plug_hw_veb(instance, vif)
742+
elif vif_type == network_model.VIF_TYPE_MACVTAP:
743+
self.plug_macvtap(instance, vif)
744+
elif vif_type == network_model.VIF_TYPE_MIDONET:
745+
self.plug_midonet(instance, vif)
746+
elif vif_type == network_model.VIF_TYPE_IOVISOR:
747+
self.plug_iovisor(instance, vif)
748+
elif vif_type == network_model.VIF_TYPE_TAP:
749+
self.plug_tap(instance, vif)
750+
elif vif_type in {network_model.VIF_TYPE_802_QBG,
751+
network_model.VIF_TYPE_802_QBH,
752+
network_model.VIF_TYPE_HOSTDEV}:
753+
# These are no-ops
754+
pass
755+
else:
732756
raise exception.VirtualInterfacePlugException(
733-
_("Plug vif failed because of unexpected "
757+
_("Plug VIF failed because of unexpected "
734758
"vif_type=%s") % vif_type)
735-
func(instance, vif)
736759

737760
def unplug_ib_hostdev(self, instance, vif):
738761
fabric = vif.get_physical_network()
@@ -746,12 +769,6 @@ def unplug_ib_hostdev(self, instance, vif):
746769
except Exception:
747770
LOG.exception(_("Failed while unplugging ib hostdev vif"))
748771

749-
def unplug_802qbg(self, instance, vif):
750-
pass
751-
752-
def unplug_802qbh(self, instance, vif):
753-
pass
754-
755772
def unplug_hw_veb(self, instance, vif):
756773
# TODO(sean-k-mooney): remove in Train after backporting 0 mac
757774
# change as this should no longer be needed with libvirt >= 3.2.0.
@@ -770,12 +787,6 @@ def unplug_hw_veb(self, instance, vif):
770787
if "trusted" in vif['profile']:
771788
linux_net.set_vf_trusted(vif['profile']['pci_slot'], False)
772789

773-
def unplug_hostdev_physical(self, instance, vif):
774-
pass
775-
776-
def unplug_macvtap(self, instance, vif):
777-
pass
778-
779790
def unplug_midonet(self, instance, vif):
780791
"""Unplug from MidoNet network port
781792
@@ -842,9 +853,25 @@ def unplug(self, instance, vif):
842853
return
843854

844855
# Legacy non-os-vif codepath
845-
vif_slug = self._normalize_vif_type(vif_type)
846-
func = getattr(self, 'unplug_%s' % vif_slug, None)
847-
if not func:
848-
msg = _("Unexpected vif_type=%s") % vif_type
849-
raise exception.InternalError(msg)
850-
func(instance, vif)
856+
if vif_type == network_model.VIF_TYPE_IB_HOSTDEV:
857+
self.unplug_ib_hostdev(instance, vif)
858+
elif vif_type == network_model.VIF_TYPE_HW_VEB:
859+
self.unplug_hw_veb(instance, vif)
860+
elif vif_type == network_model.VIF_TYPE_MIDONET:
861+
self.unplug_midonet(instance, vif)
862+
elif vif_type == network_model.VIF_TYPE_IOVISOR:
863+
self.unplug_iovisor(instance, vif)
864+
elif vif_type == network_model.VIF_TYPE_TAP:
865+
self.unplug_tap(instance, vif)
866+
elif vif_type in {network_model.VIF_TYPE_802_QBG,
867+
network_model.VIF_TYPE_802_QBH,
868+
network_model.VIF_TYPE_HOSTDEV,
869+
network_model.VIF_TYPE_MACVTAP}:
870+
# These are no-ops
871+
pass
872+
else:
873+
# TODO(stephenfin): This should probably raise
874+
# VirtualInterfaceUnplugException
875+
raise exception.InternalError(
876+
_("Unplug VIF failed because of unexpected "
877+
"vif_type=%s") % vif_type)

0 commit comments

Comments
 (0)