"Fossies" - the Fresh Open Source Software Archive

Member "nova-22.0.1/nova/virt/libvirt/vif.py" (19 Nov 2020, 34851 Bytes) of package /linux/misc/openstack/nova-22.0.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "vif.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 22.0.0_vs_22.0.1.

    1 # Copyright (C) 2011 Midokura KK
    2 # Copyright (C) 2011 Nicira, Inc
    3 # Copyright 2011 OpenStack Foundation
    4 # All Rights Reserved.
    5 # Copyright 2016 Red Hat, Inc.
    6 #
    7 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    8 #    not use this file except in compliance with the License. You may obtain
    9 #    a copy of the License at
   10 #
   11 #         http://www.apache.org/licenses/LICENSE-2.0
   12 #
   13 #    Unless required by applicable law or agreed to in writing, software
   14 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   15 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   16 #    License for the specific language governing permissions and limitations
   17 #    under the License.
   18 
   19 """VIF drivers for libvirt."""
   20 
   21 import os
   22 
   23 import os_vif
   24 from os_vif import exception as osv_exception
   25 from os_vif.objects import fields as osv_fields
   26 from os_vif.objects import vif as osv_vifs
   27 from oslo_concurrency import processutils
   28 from oslo_log import log as logging
   29 from oslo_utils import strutils
   30 
   31 import nova.conf
   32 from nova import exception
   33 from nova.i18n import _
   34 from nova.network import model as network_model
   35 from nova.network import os_vif_util
   36 from nova import objects
   37 from nova.pci import utils as pci_utils
   38 import nova.privsep.linux_net
   39 from nova import profiler
   40 from nova import utils
   41 from nova.virt.libvirt import config as vconfig
   42 from nova.virt.libvirt import designer
   43 from nova.virt import osinfo
   44 
   45 
   46 LOG = logging.getLogger(__name__)
   47 
   48 CONF = nova.conf.CONF
   49 
   50 SUPPORTED_VIF_MODELS = {
   51     'qemu': [
   52         network_model.VIF_MODEL_VIRTIO,
   53         network_model.VIF_MODEL_NE2K_PCI,
   54         network_model.VIF_MODEL_PCNET,
   55         network_model.VIF_MODEL_RTL8139,
   56         network_model.VIF_MODEL_E1000,
   57         network_model.VIF_MODEL_E1000E,
   58         network_model.VIF_MODEL_LAN9118,
   59         network_model.VIF_MODEL_SPAPR_VLAN,
   60         network_model.VIF_MODEL_VMXNET3],
   61     'kvm': [
   62         network_model.VIF_MODEL_VIRTIO,
   63         network_model.VIF_MODEL_NE2K_PCI,
   64         network_model.VIF_MODEL_PCNET,
   65         network_model.VIF_MODEL_RTL8139,
   66         network_model.VIF_MODEL_E1000,
   67         network_model.VIF_MODEL_E1000E,
   68         network_model.VIF_MODEL_SPAPR_VLAN,
   69         network_model.VIF_MODEL_VMXNET3],
   70     'xen': [
   71         network_model.VIF_MODEL_NETFRONT,
   72         network_model.VIF_MODEL_NE2K_PCI,
   73         network_model.VIF_MODEL_PCNET,
   74         network_model.VIF_MODEL_RTL8139,
   75         network_model.VIF_MODEL_E1000],
   76     'lxc': [],
   77     'uml': [],
   78     'parallels': [
   79         network_model.VIF_MODEL_VIRTIO,
   80         network_model.VIF_MODEL_RTL8139,
   81         network_model.VIF_MODEL_E1000],
   82 }
   83 
   84 
   85 def is_vif_model_valid_for_virt(virt_type, vif_model):
   86 
   87     if vif_model is None:
   88         return True
   89 
   90     if virt_type not in SUPPORTED_VIF_MODELS:
   91         raise exception.UnsupportedVirtType(virt=virt_type)
   92 
   93     return vif_model in SUPPORTED_VIF_MODELS[virt_type]
   94 
   95 
   96 def set_vf_interface_vlan(pci_addr, mac_addr, vlan=0):
   97     vlan_id = int(vlan)
   98     pf_ifname = pci_utils.get_ifname_by_pci_address(pci_addr,
   99                                                     pf_interface=True)
  100     vf_ifname = pci_utils.get_ifname_by_pci_address(pci_addr)
  101     vf_num = pci_utils.get_vf_num_by_pci_address(pci_addr)
  102 
  103     nova.privsep.linux_net.set_device_macaddr_and_vlan(
  104         pf_ifname, vf_num, mac_addr, vlan_id)
  105 
  106     # Bring up/down the VF's interface
  107     # TODO(edand): The mac is assigned as a workaround for the following issue
  108     #              https://bugzilla.redhat.com/show_bug.cgi?id=1372944
  109     #              once resolved it will be removed
  110     port_state = 'up' if vlan_id > 0 else 'down'
  111     nova.privsep.linux_net.set_device_macaddr(vf_ifname, mac_addr,
  112                                               port_state=port_state)
  113 
  114 
  115 def set_vf_trusted(pci_addr, trusted):
  116     """Configures the VF to be trusted or not
  117 
  118     :param pci_addr: PCI slot of the device
  119     :param trusted: Boolean value to indicate whether to
  120                     enable/disable 'trusted' capability
  121     """
  122     pf_ifname = pci_utils.get_ifname_by_pci_address(pci_addr,
  123                                                     pf_interface=True)
  124     vf_num = pci_utils.get_vf_num_by_pci_address(pci_addr)
  125     nova.privsep.linux_net.set_device_trust(
  126         pf_ifname, vf_num, trusted)
  127 
  128 
  129 @utils.synchronized('lock_vlan', external=True)
  130 def ensure_vlan(vlan_num, bridge_interface, mac_address=None, mtu=None,
  131                 interface=None):
  132     """Create a vlan unless it already exists."""
  133     if interface is None:
  134         interface = 'vlan%s' % vlan_num
  135     if not nova.privsep.linux_net.device_exists(interface):
  136         LOG.debug('Starting VLAN interface %s', interface)
  137         nova.privsep.linux_net.add_vlan(bridge_interface, interface,
  138                                         vlan_num)
  139         # (danwent) the bridge will inherit this address, so we want to
  140         # make sure it is the value set from the NetworkManager
  141         if mac_address:
  142             nova.privsep.linux_net.set_device_macaddr(
  143                 interface, mac_address)
  144         nova.privsep.linux_net.set_device_enabled(interface)
  145     # NOTE(vish): set mtu every time to ensure that changes to mtu get
  146     #             propagated
  147     nova.privsep.linux_net.set_device_mtu(interface, mtu)
  148     return interface
  149 
  150 
  151 @profiler.trace_cls("vif_driver")
  152 class LibvirtGenericVIFDriver(object):
  153     """Generic VIF driver for libvirt networking."""
  154 
  155     def get_vif_devname(self, vif):
  156         if 'devname' in vif:
  157             return vif['devname']
  158         return ("nic" + vif['id'])[:network_model.NIC_NAME_LEN]
  159 
  160     def get_vif_model(self, image_meta=None, vif_model=None):
  161 
  162         model = vif_model
  163 
  164         # If the user has specified a 'vif_model' against the
  165         # image then honour that model
  166         if image_meta:
  167             model = osinfo.HardwareProperties(image_meta).network_model
  168 
  169         # If the virt type is KVM/QEMU/VZ(Parallels), then use virtio according
  170         # to the global config parameter
  171         if (model is None and CONF.libvirt.virt_type in
  172                 ('kvm', 'qemu', 'parallels') and
  173                 CONF.libvirt.use_virtio_for_bridges):
  174             model = network_model.VIF_MODEL_VIRTIO
  175 
  176         return model
  177 
  178     def get_base_config(self, instance, mac, image_meta,
  179                         inst_type, virt_type, vnic_type):
  180         # TODO(sahid): We should rewrite it. This method handles too
  181         # many unrelated things. We probably need to have a specific
  182         # virtio, vhost, vhostuser functions.
  183 
  184         conf = vconfig.LibvirtConfigGuestInterface()
  185         # Default to letting libvirt / the hypervisor choose the model
  186         model = None
  187         driver = None
  188         vhost_queues = None
  189         rx_queue_size = None
  190 
  191         # NOTE(stephenfin): Skip most things here as only apply to virtio
  192         # devices
  193         if vnic_type in network_model.VNIC_TYPES_DIRECT_PASSTHROUGH:
  194             designer.set_vif_guest_frontend_config(
  195                 conf, mac, model, driver, vhost_queues, rx_queue_size)
  196             return conf
  197 
  198         rx_queue_size = CONF.libvirt.rx_queue_size
  199 
  200         # if model has already been defined,
  201         # image_meta contents will override it
  202         model = self.get_vif_model(image_meta=image_meta, vif_model=model)
  203 
  204         if not is_vif_model_valid_for_virt(virt_type, model):
  205             raise exception.UnsupportedHardware(model=model, virt=virt_type)
  206 
  207         # The rest of this only applies to virtio
  208         if model != network_model.VIF_MODEL_VIRTIO:
  209             designer.set_vif_guest_frontend_config(
  210                 conf, mac, model, driver, vhost_queues, rx_queue_size)
  211             return conf
  212 
  213         # Workaround libvirt bug, where it mistakenly enables vhost mode, even
  214         # for non-KVM guests
  215         if virt_type == 'qemu':
  216             driver = 'qemu'
  217 
  218         if virt_type in ('kvm', 'parallels'):
  219             vhost_drv, vhost_queues = self._get_virtio_mq_settings(image_meta,
  220                                                                    inst_type)
  221             # TODO(sahid): It seems that we return driver 'vhost' even
  222             # for vhostuser interface where for vhostuser interface
  223             # the driver should be 'vhost-user'. That currently does
  224             # not create any issue since QEMU ignores the driver
  225             # argument for vhostuser interface but we should probably
  226             # fix that anyway. Also we should enforce that the driver
  227             # use vhost and not None.
  228             driver = vhost_drv or driver
  229 
  230         if driver == 'vhost' or driver is None:
  231             # vhost backend only supports update of RX queue size
  232             if CONF.libvirt.rx_queue_size:
  233                 # TODO(sahid): Specifically force driver to be vhost
  234                 # that because if None we don't generate the XML
  235                 # driver element needed to set the queue size
  236                 # attribute. This can be removed when get_base_config
  237                 # will be fixed and rewrite to set the correct
  238                 # backend.
  239                 driver = 'vhost'
  240 
  241         designer.set_vif_guest_frontend_config(
  242             conf, mac, model, driver, vhost_queues, rx_queue_size)
  243 
  244         return conf
  245 
  246     def get_base_hostdev_pci_config(self, vif):
  247         conf = vconfig.LibvirtConfigGuestHostdevPCI()
  248         pci_slot = vif['profile']['pci_slot']
  249         designer.set_vif_host_backend_hostdev_pci_config(conf, pci_slot)
  250         return conf
  251 
  252     def _get_virtio_mq_settings(self, image_meta, flavor):
  253         """A methods to set the number of virtio queues,
  254            if it has been requested in extra specs.
  255         """
  256         driver = None
  257         vhost_queues = None
  258         if self._requests_multiqueue(image_meta):
  259             driver = 'vhost'
  260             max_tap_queues = self._get_max_tap_queues()
  261             if max_tap_queues:
  262                 vhost_queues = (max_tap_queues if flavor.vcpus > max_tap_queues
  263                     else flavor.vcpus)
  264             else:
  265                 vhost_queues = flavor.vcpus
  266 
  267         return (driver, vhost_queues)
  268 
  269     def _requests_multiqueue(self, image_meta):
  270         """Check if multiqueue property is set in the image metadata."""
  271 
  272         if not isinstance(image_meta, objects.ImageMeta):
  273             image_meta = objects.ImageMeta.from_dict(image_meta)
  274 
  275         img_props = image_meta.properties
  276 
  277         if img_props.get('hw_vif_multiqueue_enabled'):
  278             return True
  279 
  280         return False
  281 
  282     def _get_max_tap_queues(self):
  283         # Note(sean-k-mooney): some linux distros have backported
  284         # changes for newer kernels which make the kernel version
  285         # number unreliable to determine the max queues supported
  286         # To address this without making the code distro dependent
  287         # we introduce a new config option and prefer it if set.
  288         if CONF.libvirt.max_queues:
  289             return CONF.libvirt.max_queues
  290         # NOTE(kengo.sakai): In kernels prior to 3.0,
  291         # multiple queues on a tap interface is not supported.
  292         # In kernels 3.x, the number of queues on a tap interface
  293         # is limited to 8. From 4.0, the number is 256.
  294         # See: https://bugs.launchpad.net/nova/+bug/1570631
  295         kernel_version = int(os.uname()[2].split(".")[0])
  296         if kernel_version <= 2:
  297             return 1
  298         elif kernel_version == 3:
  299             return 8
  300         elif kernel_version == 4:
  301             return 256
  302         else:
  303             return None
  304 
  305     def get_bridge_name(self, vif):
  306         return vif['network']['bridge']
  307 
  308     def get_veth_pair_names(self, iface_id):
  309         return (("qvb%s" % iface_id)[:network_model.NIC_NAME_LEN],
  310                 ("qvo%s" % iface_id)[:network_model.NIC_NAME_LEN])
  311 
  312     def get_config_802qbg(self, instance, vif, image_meta,
  313                           inst_type, virt_type):
  314         conf = self.get_base_config(instance, vif['address'], image_meta,
  315                                     inst_type, virt_type, vif['vnic_type'])
  316 
  317         params = vif["qbg_params"]
  318         designer.set_vif_host_backend_802qbg_config(
  319             conf, vif['network'].get_meta('interface'),
  320             params['managerid'],
  321             params['typeid'],
  322             params['typeidversion'],
  323             params['instanceid'])
  324 
  325         designer.set_vif_bandwidth_config(conf, inst_type)
  326 
  327         return conf
  328 
  329     def get_config_802qbh(self, instance, vif, image_meta,
  330                           inst_type, virt_type):
  331         conf = self.get_base_config(instance, vif['address'], image_meta,
  332                                     inst_type, virt_type, vif['vnic_type'])
  333 
  334         profile = vif["profile"]
  335         vif_details = vif["details"]
  336         net_type = 'direct'
  337         if vif['vnic_type'] == network_model.VNIC_TYPE_DIRECT:
  338             net_type = 'hostdev'
  339 
  340         designer.set_vif_host_backend_802qbh_config(
  341             conf, net_type, profile['pci_slot'],
  342             vif_details[network_model.VIF_DETAILS_PROFILEID])
  343 
  344         designer.set_vif_bandwidth_config(conf, inst_type)
  345 
  346         return conf
  347 
  348     def get_config_hw_veb(self, instance, vif, image_meta,
  349                           inst_type, virt_type):
  350         conf = self.get_base_config(instance, vif['address'], image_meta,
  351                                     inst_type, virt_type, vif['vnic_type'])
  352 
  353         profile = vif["profile"]
  354         vif_details = vif["details"]
  355         net_type = 'direct'
  356         if vif['vnic_type'] == network_model.VNIC_TYPE_DIRECT:
  357             net_type = 'hostdev'
  358 
  359         designer.set_vif_host_backend_hw_veb(
  360             conf, net_type, profile['pci_slot'],
  361             vif_details[network_model.VIF_DETAILS_VLAN])
  362 
  363         designer.set_vif_bandwidth_config(conf, inst_type)
  364 
  365         return conf
  366 
  367     def get_config_hostdev_physical(self, instance, vif, image_meta,
  368                                     inst_type, virt_type):
  369         return self.get_base_hostdev_pci_config(vif)
  370 
  371     def get_config_macvtap(self, instance, vif, image_meta,
  372                            inst_type, virt_type):
  373         conf = self.get_base_config(instance, vif['address'], image_meta,
  374                                     inst_type, virt_type, vif['vnic_type'])
  375 
  376         vif_details = vif['details']
  377         macvtap_src = vif_details.get(network_model.VIF_DETAILS_MACVTAP_SOURCE)
  378         macvtap_mode = vif_details.get(network_model.VIF_DETAILS_MACVTAP_MODE)
  379         phys_interface = vif_details.get(
  380                                     network_model.VIF_DETAILS_PHYS_INTERFACE)
  381 
  382         missing_params = []
  383         if macvtap_src is None:
  384             missing_params.append(network_model.VIF_DETAILS_MACVTAP_SOURCE)
  385         if macvtap_mode is None:
  386             missing_params.append(network_model.VIF_DETAILS_MACVTAP_MODE)
  387         if phys_interface is None:
  388             missing_params.append(network_model.VIF_DETAILS_PHYS_INTERFACE)
  389 
  390         if len(missing_params) > 0:
  391             raise exception.VifDetailsMissingMacvtapParameters(
  392                                                 vif_id=vif['id'],
  393                                                 missing_params=missing_params)
  394 
  395         designer.set_vif_host_backend_direct_config(
  396             conf, macvtap_src, macvtap_mode)
  397 
  398         designer.set_vif_bandwidth_config(conf, inst_type)
  399 
  400         return conf
  401 
  402     def get_config_iovisor(self, instance, vif, image_meta,
  403                            inst_type, virt_type):
  404         conf = self.get_base_config(instance, vif['address'], image_meta,
  405                                     inst_type, virt_type, vif['vnic_type'])
  406 
  407         dev = self.get_vif_devname(vif)
  408         designer.set_vif_host_backend_ethernet_config(conf, dev)
  409 
  410         designer.set_vif_bandwidth_config(conf, inst_type)
  411 
  412         return conf
  413 
  414     def get_config_midonet(self, instance, vif, image_meta,
  415                            inst_type, virt_type):
  416         conf = self.get_base_config(instance, vif['address'], image_meta,
  417                                     inst_type, virt_type, vif['vnic_type'])
  418 
  419         dev = self.get_vif_devname(vif)
  420         designer.set_vif_host_backend_ethernet_config(conf, dev)
  421 
  422         return conf
  423 
  424     def get_config_tap(self, instance, vif, image_meta, inst_type, virt_type):
  425         conf = self.get_base_config(instance, vif['address'], image_meta,
  426                                     inst_type, virt_type, vif['vnic_type'])
  427 
  428         dev = self.get_vif_devname(vif)
  429         designer.set_vif_host_backend_ethernet_config(conf, dev)
  430 
  431         network = vif.get('network')
  432         if network and network.get_meta('mtu'):
  433             designer.set_vif_mtu_config(conf, network.get_meta("mtu"))
  434 
  435         return conf
  436 
  437     def get_config_ib_hostdev(self, instance, vif, image_meta,
  438                               inst_type, virt_type):
  439         return self.get_base_hostdev_pci_config(vif)
  440 
  441     def _set_config_VIFGeneric(self, instance, vif, conf):
  442         dev = vif.vif_name
  443         designer.set_vif_host_backend_ethernet_config(conf, dev)
  444 
  445     def _set_config_VIFBridge(self, instance, vif, conf):
  446         conf.net_type = "bridge"
  447         conf.source_dev = vif.bridge_name
  448         conf.target_dev = vif.vif_name
  449 
  450     def _set_config_VIFOpenVSwitch(self, instance, vif, conf):
  451         conf.net_type = "bridge"
  452         conf.source_dev = vif.bridge_name
  453         conf.target_dev = vif.vif_name
  454         self._set_config_VIFPortProfile(instance, vif, conf)
  455 
  456     def _set_config_VIFVHostUser(self, instance, vif, conf):
  457         # TODO(sahid): We should never configure a driver backend for
  458         # vhostuser interface. Specifically override driver to use
  459         # None. This can be removed when get_base_config will be fixed
  460         # and rewrite to set the correct backend.
  461         conf.driver_name = None
  462 
  463         designer.set_vif_host_backend_vhostuser_config(
  464             conf, vif.mode, vif.path, CONF.libvirt.rx_queue_size,
  465             CONF.libvirt.tx_queue_size, vif.vif_name)
  466 
  467     def _set_config_VIFHostDevice(self, instance, vif, conf):
  468         if vif.dev_type == osv_fields.VIFHostDeviceDevType.ETHERNET:
  469             # This sets the required fields for an <interface type='hostdev'>
  470             # section in a libvirt domain (by using a subset of hw_veb's
  471             # options).
  472             designer.set_vif_host_backend_hw_veb(
  473                 conf, 'hostdev', vif.dev_address, None)
  474         else:
  475             # TODO(jangutter): dev_type == VIFHostDeviceDevType.GENERIC
  476             # is currently unsupported under os-vif. The corresponding conf
  477             # class would be: LibvirtConfigGuestHostdevPCI
  478             # but os-vif only returns a LibvirtConfigGuestInterface object
  479             raise exception.InternalError(
  480                 _("Unsupported os-vif VIFHostDevice dev_type %(type)s") %
  481                 {'type': vif.dev_type})
  482 
  483     def _set_config_VIFPortProfileOpenVSwitch(self, profile, conf):
  484         conf.vporttype = "openvswitch"
  485         conf.add_vport_param("interfaceid",
  486                              profile.interface_id)
  487 
  488     def _set_config_VIFPortProfile(self, instance, vif, conf):
  489         # Set any port profile that may be required
  490         profile_name = vif.port_profile.obj_name()
  491         if profile_name == 'VIFPortProfileOpenVSwitch':
  492             self._set_config_VIFPortProfileOpenVSwitch(vif.port_profile, conf)
  493         else:
  494             raise exception.InternalError(
  495                 _('Unsupported VIF port profile type %s') % profile_name)
  496 
  497     def _get_config_os_vif(self, instance, vif, image_meta, inst_type,
  498                            virt_type, vnic_type):
  499         """Get the domain config for a VIF
  500 
  501         :param instance: nova.objects.Instance
  502         :param vif: os_vif.objects.vif.VIFBase subclass
  503         :param image_meta: nova.objects.ImageMeta
  504         :param inst_type: nova.objects.Flavor
  505         :param virt_type: virtualization type
  506         :param vnic_type: vnic type
  507 
  508         :returns: nova.virt.libvirt.config.LibvirtConfigGuestInterface
  509         """
  510 
  511         # Do the config that's common to all vif types
  512         conf = self.get_base_config(instance, vif.address, image_meta,
  513                                     inst_type, virt_type, vnic_type)
  514 
  515         # Do the VIF type specific config
  516         if isinstance(vif, osv_vifs.VIFGeneric):
  517             self._set_config_VIFGeneric(instance, vif, conf)
  518         elif isinstance(vif, osv_vifs.VIFBridge):
  519             self._set_config_VIFBridge(instance, vif, conf)
  520         elif isinstance(vif, osv_vifs.VIFOpenVSwitch):
  521             self._set_config_VIFOpenVSwitch(instance, vif, conf)
  522         elif isinstance(vif, osv_vifs.VIFVHostUser):
  523             self._set_config_VIFVHostUser(instance, vif, conf)
  524         elif isinstance(vif, osv_vifs.VIFHostDevice):
  525             self._set_config_VIFHostDevice(instance, vif, conf)
  526         else:
  527             raise exception.InternalError(
  528                 _("Unsupported VIF type %s") % vif.obj_name())
  529 
  530         # not all VIF types support bandwidth configuration
  531         # https://github.com/libvirt/libvirt/blob/568a41722/src/conf/netdev_bandwidth_conf.h#L38
  532         if vif.obj_name() not in ('VIFVHostUser', 'VIFHostDevice'):
  533             designer.set_vif_bandwidth_config(conf, inst_type)
  534 
  535         if 'network' in vif and 'mtu' in vif.network:
  536             designer.set_vif_mtu_config(conf, vif.network.mtu)
  537 
  538         return conf
  539 
  540     def get_config(self, instance, vif, image_meta, inst_type, virt_type):
  541         vif_type = vif['type']
  542         vnic_type = vif['vnic_type']
  543 
  544         # instance.display_name could be unicode
  545         instance_repr = utils.get_obj_repr_unicode(instance)
  546         LOG.debug('vif_type=%(vif_type)s instance=%(instance)s '
  547                   'vif=%(vif)s virt_type=%(virt_type)s',
  548                   {'vif_type': vif_type, 'instance': instance_repr,
  549                    'vif': vif, 'virt_type': virt_type})
  550 
  551         if vif_type is None:
  552             raise exception.InternalError(
  553                 _("vif_type parameter must be present "
  554                   "for this vif_driver implementation"))
  555 
  556         # Try os-vif codepath first
  557         vif_obj = os_vif_util.nova_to_osvif_vif(vif)
  558         if vif_obj is not None:
  559             return self._get_config_os_vif(instance, vif_obj, image_meta,
  560                                            inst_type, virt_type, vnic_type)
  561 
  562         # Legacy non-os-vif codepath
  563         args = (instance, vif, image_meta, inst_type, virt_type)
  564         if vif_type == network_model.VIF_TYPE_IOVISOR:
  565             return self.get_config_iovisor(*args)
  566         elif vif_type == network_model.VIF_TYPE_802_QBG:
  567             return self.get_config_802qbg(*args)
  568         elif vif_type == network_model.VIF_TYPE_802_QBH:
  569             return self.get_config_802qbh(*args)
  570         elif vif_type == network_model.VIF_TYPE_HW_VEB:
  571             return self.get_config_hw_veb(*args)
  572         elif vif_type == network_model.VIF_TYPE_HOSTDEV:
  573             return self.get_config_hostdev_physical(*args)
  574         elif vif_type == network_model.VIF_TYPE_MACVTAP:
  575             return self.get_config_macvtap(*args)
  576         elif vif_type == network_model.VIF_TYPE_MIDONET:
  577             return self.get_config_midonet(*args)
  578         elif vif_type == network_model.VIF_TYPE_TAP:
  579             return self.get_config_tap(*args)
  580         elif vif_type == network_model.VIF_TYPE_IB_HOSTDEV:
  581             return self.get_config_ib_hostdev(*args)
  582 
  583         raise exception.InternalError(_('Unexpected vif_type=%s') % vif_type)
  584 
  585     def plug_ib_hostdev(self, instance, vif):
  586         fabric = vif.get_physical_network()
  587         if not fabric:
  588             raise exception.NetworkMissingPhysicalNetwork(
  589                 network_uuid=vif['network']['id']
  590             )
  591         pci_slot = vif['profile']['pci_slot']
  592         device_id = instance['uuid']
  593         vnic_mac = vif['address']
  594         try:
  595             nova.privsep.libvirt.plug_infiniband_vif(
  596                 vnic_mac, device_id, fabric,
  597                 network_model.VIF_TYPE_IB_HOSTDEV, pci_slot)
  598         except processutils.ProcessExecutionError:
  599             LOG.exception("Failed while plugging ib hostdev vif",
  600                           instance=instance)
  601 
  602     def plug_hw_veb(self, instance, vif):
  603         # TODO(adrianc): The piece of code for MACVTAP can be removed once:
  604         #  1. neutron SR-IOV agent does not rely on the administrative mac
  605         #     as depicted in https://bugs.launchpad.net/neutron/+bug/1841067
  606         #  2. libvirt driver does not change mac address for macvtap VNICs
  607         #     or Alternatively does not rely on recreating libvirt's nodev
  608         #     name from the current mac address set on the netdevice.
  609         #     See: virt.libvrit.driver.LibvirtDriver._get_pcinet_info
  610         if vif['vnic_type'] == network_model.VNIC_TYPE_MACVTAP:
  611             set_vf_interface_vlan(
  612                 vif['profile']['pci_slot'],
  613                 mac_addr=vif['address'],
  614                 vlan=vif['details'][network_model.VIF_DETAILS_VLAN])
  615 
  616         elif vif['vnic_type'] == network_model.VNIC_TYPE_DIRECT:
  617             trusted = strutils.bool_from_string(
  618                 vif['profile'].get('trusted', "False"))
  619             if trusted:
  620                 set_vf_trusted(vif['profile']['pci_slot'], True)
  621 
  622     def plug_macvtap(self, instance, vif):
  623         vif_details = vif['details']
  624         vlan = vif_details.get(network_model.VIF_DETAILS_VLAN)
  625         if vlan:
  626             vlan_name = vif_details.get(
  627                                     network_model.VIF_DETAILS_MACVTAP_SOURCE)
  628             phys_if = vif_details.get(network_model.VIF_DETAILS_PHYS_INTERFACE)
  629             ensure_vlan(vlan, phys_if, interface=vlan_name)
  630 
  631     def plug_midonet(self, instance, vif):
  632         """Plug into MidoNet's network port
  633 
  634         Bind the vif to a MidoNet virtual port.
  635         """
  636         dev = self.get_vif_devname(vif)
  637         port_id = vif['id']
  638         try:
  639             nova.privsep.linux_net.create_tap_dev(dev)
  640             nova.privsep.libvirt.plug_midonet_vif(port_id, dev)
  641         except processutils.ProcessExecutionError:
  642             LOG.exception("Failed while plugging vif", instance=instance)
  643 
  644     def plug_iovisor(self, instance, vif):
  645         """Plug using PLUMgrid IO Visor Driver
  646 
  647         Connect a network device to their respective
  648         Virtual Domain in PLUMgrid Platform.
  649         """
  650         dev = self.get_vif_devname(vif)
  651         iface_id = vif['id']
  652         nova.privsep.linux_net.create_tap_dev(dev)
  653         net_id = vif['network']['id']
  654         tenant_id = instance.project_id
  655         try:
  656             nova.privsep.libvirt.plug_plumgrid_vif(
  657                 dev, iface_id, vif['address'], net_id, tenant_id)
  658         except processutils.ProcessExecutionError:
  659             LOG.exception("Failed while plugging vif", instance=instance)
  660 
  661     def plug_tap(self, instance, vif):
  662         """Plug a VIF_TYPE_TAP virtual interface."""
  663         dev = self.get_vif_devname(vif)
  664         mac = vif['details'].get(network_model.VIF_DETAILS_TAP_MAC_ADDRESS)
  665         image_meta = instance.image_meta
  666         vif_model = self.get_vif_model(image_meta=image_meta)
  667         # TODO(ganso): explore whether multiqueue works for other vif models
  668         # that go through this code path.
  669         multiqueue = (self._requests_multiqueue(image_meta) and
  670                       vif_model == network_model.VIF_MODEL_VIRTIO)
  671         nova.privsep.linux_net.create_tap_dev(dev, mac, multiqueue=multiqueue)
  672         network = vif.get('network')
  673         mtu = network.get_meta('mtu') if network else None
  674         nova.privsep.linux_net.set_device_mtu(dev, mtu)
  675 
  676     def _plug_os_vif(self, instance, vif):
  677         instance_info = os_vif_util.nova_to_osvif_instance(instance)
  678 
  679         try:
  680             os_vif.plug(vif, instance_info)
  681         except osv_exception.ExceptionBase as ex:
  682             msg = (_("Failure running os_vif plugin plug method: %(ex)s")
  683                    % {'ex': ex})
  684             raise exception.InternalError(msg)
  685 
  686     def plug(self, instance, vif):
  687         vif_type = vif['type']
  688 
  689         # instance.display_name could be unicode
  690         instance_repr = utils.get_obj_repr_unicode(instance)
  691         LOG.debug('vif_type=%(vif_type)s instance=%(instance)s '
  692                   'vif=%(vif)s',
  693                   {'vif_type': vif_type, 'instance': instance_repr,
  694                    'vif': vif})
  695 
  696         if vif_type is None:
  697             raise exception.VirtualInterfacePlugException(
  698                 _("vif_type parameter must be present "
  699                   "for this vif_driver implementation"))
  700 
  701         # Try os-vif codepath first
  702         vif_obj = os_vif_util.nova_to_osvif_vif(vif)
  703         if vif_obj is not None:
  704             self._plug_os_vif(instance, vif_obj)
  705             return
  706 
  707         # Legacy non-os-vif codepath
  708         if vif_type == network_model.VIF_TYPE_IB_HOSTDEV:
  709             self.plug_ib_hostdev(instance, vif)
  710         elif vif_type == network_model.VIF_TYPE_HW_VEB:
  711             self.plug_hw_veb(instance, vif)
  712         elif vif_type == network_model.VIF_TYPE_MACVTAP:
  713             self.plug_macvtap(instance, vif)
  714         elif vif_type == network_model.VIF_TYPE_MIDONET:
  715             self.plug_midonet(instance, vif)
  716         elif vif_type == network_model.VIF_TYPE_IOVISOR:
  717             self.plug_iovisor(instance, vif)
  718         elif vif_type == network_model.VIF_TYPE_TAP:
  719             self.plug_tap(instance, vif)
  720         elif vif_type in {network_model.VIF_TYPE_802_QBG,
  721                           network_model.VIF_TYPE_802_QBH,
  722                           network_model.VIF_TYPE_HOSTDEV}:
  723             # These are no-ops
  724             pass
  725         else:
  726             raise exception.VirtualInterfacePlugException(
  727                 _("Plug VIF failed because of unexpected "
  728                   "vif_type=%s") % vif_type)
  729 
  730     def unplug_ib_hostdev(self, instance, vif):
  731         fabric = vif.get_physical_network()
  732         if not fabric:
  733             raise exception.NetworkMissingPhysicalNetwork(
  734                 network_uuid=vif['network']['id']
  735             )
  736         vnic_mac = vif['address']
  737         try:
  738             nova.privsep.libvirt.unplug_infiniband_vif(fabric, vnic_mac)
  739         except Exception:
  740             LOG.exception("Failed while unplugging ib hostdev vif")
  741 
  742     def unplug_hw_veb(self, instance, vif):
  743         # TODO(sean-k-mooney): remove in Train after backporting 0 mac
  744         # change as this should no longer be needed with libvirt >= 3.2.0.
  745         if vif['vnic_type'] == network_model.VNIC_TYPE_MACVTAP:
  746             # NOTE(sean-k-mooney): Retaining the vm mac on the vf
  747             # after unplugging the vif prevents the PF from transmitting
  748             # a packet with that destination address. This would create a
  749             # a network partition in the event a vm is migrated or the neuton
  750             # port is reused for another vm before the VF is reused.
  751             # The ip utility accepts the MAC 00:00:00:00:00:00 which can
  752             # be used to reset the VF mac when no longer in use by a vm.
  753             # As such we hardcode the 00:00:00:00:00:00 mac.
  754             set_vf_interface_vlan(vif['profile']['pci_slot'],
  755                                   mac_addr='00:00:00:00:00:00')
  756         elif vif['vnic_type'] == network_model.VNIC_TYPE_DIRECT:
  757             if "trusted" in vif['profile']:
  758                 set_vf_trusted(vif['profile']['pci_slot'], False)
  759 
  760     def unplug_midonet(self, instance, vif):
  761         """Unplug from MidoNet network port
  762 
  763         Unbind the vif from a MidoNet virtual port.
  764         """
  765         dev = self.get_vif_devname(vif)
  766         port_id = vif['id']
  767         try:
  768             nova.privsep.libvirt.unplug_midonet_vif(port_id)
  769             nova.privsep.linux_net.delete_net_dev(dev)
  770         except processutils.ProcessExecutionError:
  771             LOG.exception("Failed while unplugging vif", instance=instance)
  772 
  773     def unplug_tap(self, instance, vif):
  774         """Unplug a VIF_TYPE_TAP virtual interface."""
  775         dev = self.get_vif_devname(vif)
  776         try:
  777             nova.privsep.linux_net.delete_net_dev(dev)
  778         except processutils.ProcessExecutionError:
  779             LOG.exception("Failed while unplugging vif", instance=instance)
  780 
  781     def unplug_iovisor(self, instance, vif):
  782         """Unplug using PLUMgrid IO Visor Driver
  783 
  784         Delete network device and to their respective
  785         connection to the Virtual Domain in PLUMgrid Platform.
  786         """
  787         dev = self.get_vif_devname(vif)
  788         try:
  789             nova.privsep.libvirt.unplug_plumgrid_vif(dev)
  790             nova.privsep.linux_net.delete_net_dev(dev)
  791         except processutils.ProcessExecutionError:
  792             LOG.exception("Failed while unplugging vif", instance=instance)
  793 
  794     def _unplug_os_vif(self, instance, vif):
  795         instance_info = os_vif_util.nova_to_osvif_instance(instance)
  796 
  797         try:
  798             os_vif.unplug(vif, instance_info)
  799         except osv_exception.ExceptionBase as ex:
  800             msg = (_("Failure running os_vif plugin unplug method: %(ex)s")
  801                    % {'ex': ex})
  802             raise exception.InternalError(msg)
  803 
  804     def unplug(self, instance, vif):
  805         vif_type = vif['type']
  806 
  807         # instance.display_name could be unicode
  808         instance_repr = utils.get_obj_repr_unicode(instance)
  809         LOG.debug('vif_type=%(vif_type)s instance=%(instance)s '
  810                   'vif=%(vif)s',
  811                   {'vif_type': vif_type, 'instance': instance_repr,
  812                    'vif': vif})
  813 
  814         if vif_type is None:
  815             msg = _("vif_type parameter must be present for this vif_driver "
  816                     "implementation")
  817             raise exception.InternalError(msg)
  818 
  819         # Try os-vif codepath first
  820         vif_obj = os_vif_util.nova_to_osvif_vif(vif)
  821         if vif_obj is not None:
  822             self._unplug_os_vif(instance, vif_obj)
  823             return
  824 
  825         # Legacy non-os-vif codepath
  826         if vif_type == network_model.VIF_TYPE_IB_HOSTDEV:
  827             self.unplug_ib_hostdev(instance, vif)
  828         elif vif_type == network_model.VIF_TYPE_HW_VEB:
  829             self.unplug_hw_veb(instance, vif)
  830         elif vif_type == network_model.VIF_TYPE_MIDONET:
  831             self.unplug_midonet(instance, vif)
  832         elif vif_type == network_model.VIF_TYPE_IOVISOR:
  833             self.unplug_iovisor(instance, vif)
  834         elif vif_type == network_model.VIF_TYPE_TAP:
  835             self.unplug_tap(instance, vif)
  836         elif vif_type in {network_model.VIF_TYPE_802_QBG,
  837                           network_model.VIF_TYPE_802_QBH,
  838                           network_model.VIF_TYPE_HOSTDEV,
  839                           network_model.VIF_TYPE_MACVTAP}:
  840             # These are no-ops
  841             pass
  842         else:
  843             # TODO(stephenfin): This should probably raise
  844             # VirtualInterfaceUnplugException
  845             raise exception.InternalError(
  846                 _("Unplug VIF failed because of unexpected "
  847                   "vif_type=%s") % vif_type)