Migration scenario, SR-IOV vif contains source physical ports

This is not a bug, this is related to future work to support migration for
SR-IOV VMs. In migration scenarios, SR-IOV plug mechanism receives vif and
it proceeds to create vNIC. This fails due to physical ports mismatch. As
there are no physical ports matching with location codes in incoming vif,
no backing device could be created.

This is due to the fact that rebuild logic in nova compute, retrieves vif
details from nova instance and feeds it to plug mechanism. Though neutron
SR-IOV mechanism driver provides new and valid physical ports corresponding
to destination host, it is ignored.

A fix is needed in SR-IOV plug mechanism to retrieve appropriate SR_IOV
physical ports that corresponds to related physical network (from related
neutron network) and consume.

There are two parts to this fix. One is related to physical_network. If
there are no physical network in incoming vif detail, it is retreived using
network id. Refer to
https://bugs.launchpad.net/networking-powervm/+bug/1651129
for a fix on networking-powervm to avoid this moving forward.

Second part is to retrieve physical ports from the environment using
physical_network against port label attribute.

Change-Id: Ic511314095472da21c3a5588d77955c939b7e0f1
This commit is contained in:
Sridhar Venkat 2016-12-19 09:23:15 -05:00
parent eedae5b0d4
commit ef98898379
2 changed files with 138 additions and 8 deletions

View File

@ -18,6 +18,7 @@ import mock
from nova import exception
from nova.network import model
from nova.network.neutronv2 import api as netapi
from nova import test
from oslo_config import cfg
from pypowervm import exceptions as pvm_ex
@ -39,6 +40,16 @@ def cna(mac):
return nic
class FakeNetworkAPI(object):
def __init__(self, physnet):
self.physical_network = physnet
def get(self, context, netid):
physnet = mock.MagicMock()
physnet.physical_network = self.physical_network
return physnet
class TestVifFunctions(test.TestCase):
def setUp(self):
@ -312,19 +323,115 @@ class TestVifSriovDriver(test.TestCase):
self.inst = mock.MagicMock()
self.drv = vif.PvmVnicSriovVifDriver(self.adpt, 'host_uuid', self.inst)
def test_plug_no_pports(self):
@mock.patch('pypowervm.wrappers.managed_system.System.get')
def test_plug_no_pports(self, mock_sysget):
"""Raise when plug is called with a network with no physical ports."""
sriov_adaps = [
mock.Mock(phys_ports=[
mock.Mock(loc_code='loc1', label='foo'),
mock.Mock(loc_code='loc2', label='')]),
mock.Mock(phys_ports=[
mock.Mock(loc_code='loc3', label='bar'),
mock.Mock(loc_code='loc4', label='foo')])]
sys = mock.Mock(asio_config=mock.Mock(sriov_adapters=sriov_adaps))
mock_sysget.return_value = [sys]
self.assertRaises(exception.VirtualInterfacePlugException,
self.drv.plug, FakeDirectVif('net2', pports=[]), 1)
@mock.patch('pypowervm.wrappers.iocard.VNIC.bld')
@mock.patch('nova_powervm.virt.powervm.vm.get_pvm_uuid')
@mock.patch('pypowervm.tasks.sriov.set_vnic_back_devs')
@mock.patch('pypowervm.wrappers.managed_system.System.get')
def test_plug_no_physnet(self, mock_sysget, mock_back_devs, mock_pvm_uuid,
mock_vnic_bld):
slot = 10
pports = ['port1', 'port2']
sriov_adaps = [
mock.Mock(phys_ports=[
mock.Mock(loc_code='port11', label='default'),
mock.Mock(loc_code='port3', label='data1')]),
mock.Mock(phys_ports=[
mock.Mock(loc_code='port4', label='data2'),
mock.Mock(loc_code='port22', label='default')])]
sys = mock.Mock(asio_config=mock.Mock(sriov_adapters=sriov_adaps))
mock_sysget.return_value = [sys]
netapi.API = mock.Mock(return_value=FakeNetworkAPI('default'))
self.drv.plug(FakeDirectVif('', pports=pports), slot)
# Ensure back devs are created with pports from sriov_adaps and
# not with what pports passed into plug method
mock_back_devs.assert_called_once_with(
mock_vnic_bld.return_value, ['port11', 'port22'], redundancy=3,
capacity=None, check_port_status=True,
sys_w=sys)
@mock.patch('pypowervm.wrappers.iocard.VNIC.bld')
@mock.patch('nova_powervm.virt.powervm.vm.get_pvm_uuid')
@mock.patch('pypowervm.tasks.sriov.set_vnic_back_devs')
@mock.patch('pypowervm.wrappers.managed_system.System.get')
def test_plug_no_matching_pports(self, mock_sysget, mock_back_devs,
mock_pvm_uuid, mock_vnic_bld):
slot = 10
pports = ['port1', 'port2']
sriov_adaps = [
mock.Mock(phys_ports=[
mock.Mock(loc_code='port1', label='data1'),
mock.Mock(loc_code='port3', label='data1')]),
mock.Mock(phys_ports=[
mock.Mock(loc_code='port4', label='data2'),
mock.Mock(loc_code='port2', label='data2')])]
sys = mock.Mock(asio_config=mock.Mock(sriov_adapters=sriov_adaps))
mock_sysget.return_value = [sys]
netapi.API = mock.Mock(return_value=FakeNetworkAPI('default'))
# Ensure Plug exception is raised when there are no matching pports
# for physical network of corresponding neutron network
self.assertRaises(exception.VirtualInterfacePlugException,
self.drv.plug,
FakeDirectVif('default', pports=pports), slot)
@mock.patch('pypowervm.wrappers.iocard.VNIC.bld')
@mock.patch('nova_powervm.virt.powervm.vm.get_pvm_uuid')
@mock.patch('pypowervm.tasks.sriov.set_vnic_back_devs')
@mock.patch('pypowervm.wrappers.managed_system.System.get')
def test_plug_bad_pports(self, mock_sysget, mock_back_devs, mock_pvm_uuid,
mock_vnic_bld):
slot = 10
pports = ['bad1', 'bad2']
sriov_adaps = [
mock.Mock(phys_ports=[
mock.Mock(loc_code='port1', label='default'),
mock.Mock(loc_code='port3', label='data1')]),
mock.Mock(phys_ports=[
mock.Mock(loc_code='port4', label='data2'),
mock.Mock(loc_code='port2', label='default')])]
sys = mock.Mock(asio_config=mock.Mock(sriov_adapters=sriov_adaps))
mock_sysget.return_value = [sys]
netapi.API = mock.Mock(return_value=FakeNetworkAPI('default'))
self.drv.plug(FakeDirectVif('', pports=pports), slot)
# Ensure back devs are created with correct pports belonging to same
# physical network corresonding to neutron network
mock_back_devs.assert_called_once_with(
mock_vnic_bld.return_value, ['port1', 'port2'], redundancy=3,
capacity=None, check_port_status=True,
sys_w=sys)
@mock.patch('pypowervm.wrappers.managed_system.System.get')
@mock.patch('pypowervm.util.sanitize_mac_for_api')
@mock.patch('pypowervm.wrappers.iocard.VNIC.bld')
@mock.patch('pypowervm.tasks.sriov.set_vnic_back_devs')
@mock.patch('nova_powervm.virt.powervm.vm.get_pvm_uuid')
def test_plug(self, mock_pvm_uuid, mock_back_devs, mock_vnic_bld,
mock_san_mac):
mock_san_mac, mock_sysget):
slot = 10
pports = ['port1', 'port2']
sriov_adaps = [
mock.Mock(phys_ports=[
mock.Mock(loc_code='port1', label='default'),
mock.Mock(loc_code='port3', label='data1')]),
mock.Mock(phys_ports=[
mock.Mock(loc_code='port4', label='data2'),
mock.Mock(loc_code='port2', label='default')])]
sys = mock.Mock(asio_config=mock.Mock(sriov_adapters=sriov_adaps))
mock_sysget.return_value = [sys]
self.drv.plug(FakeDirectVif('default', pports=pports),
slot)
mock_san_mac.assert_called_once_with('ab:ab:ab:ab:ab:ab')
@ -334,7 +441,8 @@ class TestVifSriovDriver(test.TestCase):
allowed_macs='NONE')
mock_back_devs.assert_called_once_with(
mock_vnic_bld.return_value, ['port1', 'port2'], redundancy=3,
capacity=None, check_port_status=True)
capacity=None, check_port_status=True,
sys_w=sys)
mock_pvm_uuid.assert_called_once_with(self.drv.instance)
mock_vnic_bld.return_value.create.assert_called_once_with(
parent_type=pvm_lpar.LPAR, parent_uuid=mock_pvm_uuid.return_value)
@ -353,7 +461,8 @@ class TestVifSriovDriver(test.TestCase):
allowed_macs='NONE')
mock_back_devs.assert_called_once_with(
mock_vnic_bld.return_value, ['port1', 'port2'],
redundancy=3, capacity=0.08, check_port_status=True)
redundancy=3, capacity=0.08, check_port_status=True,
sys_w=sys)
mock_pvm_uuid.assert_called_once_with(self.drv.instance)
mock_vnic_bld.return_value.create.assert_called_once_with(
parent_type=pvm_lpar.LPAR, parent_uuid=mock_pvm_uuid.return_value)

View File

@ -17,7 +17,9 @@
import abc
import six
from nova import context as ctx
from nova import exception
from nova import network as net_api
from nova.network import linux_net
from nova.network import model as network_model
from nova import utils
@ -616,12 +618,30 @@ class PvmVnicSriovVifDriver(PvmVifDriver):
return None
physnet = vif.get_physical_network()
if not physnet:
# Get physnet from neutron network if not present in vif
# TODO(svenkat): This section of code will be eliminated in
# pike release. Design will be in place to fix any vif
# that has physical_network missing. The fix will be in
# compute startup code.
net_id = vif['network']['id']
admin_context = ctx.get_admin_context()
napi = net_api.API()
network = napi.get(admin_context, net_id)
physnet = network.physical_network
LOG.debug("Plugging vNIC SR-IOV vif for physical network "
"'%(physnet)s' into instance %(inst)s.",
{'physnet': physnet, 'inst': self.instance.name})
{'physnet': physnet, 'inst': self.instance.name},
instance=self.instance)
# Get the msys
msys = pvm_ms.System.get(self.adapter)[0]
# Physical ports for the given port label
pports_w = sriovtask.find_pports_for_portlabel(physnet, self.adapter,
msys)
pports = [pport.loc_code for pport in pports_w]
# Physical ports for the given physical network
pports = vif['details']['physical_ports']
if not pports:
raise exception.VirtualInterfacePlugException(
_("Unable to find SR-IOV physical ports for physical "
@ -645,7 +665,8 @@ class PvmVnicSriovVifDriver(PvmVifDriver):
allowed_vlans=pvm_util.VLANList.NONE,
allowed_macs=pvm_util.MACList.NONE)
sriovtask.set_vnic_back_devs(vnic, pports, redundancy=redundancy,
sriovtask.set_vnic_back_devs(vnic, pports, sys_w=msys,
redundancy=redundancy,
capacity=capacity, check_port_status=True)
return vnic.create(parent_type=pvm_lpar.LPAR,