Merge "neutron: Update the port with a MAC address for PFs"

This commit is contained in:
Jenkins
2016-04-01 15:31:30 +00:00
committed by Gerrit Code Review
2 changed files with 105 additions and 0 deletions

View File

@@ -37,8 +37,10 @@ from nova.network import base_api
from nova.network import model as network_model
from nova.network.neutronv2 import constants
from nova import objects
from nova.objects import fields as obj_fields
from nova.pci import manager as pci_manager
from nova.pci import request as pci_request
from nova.pci import utils as pci_utils
from nova.pci import whitelist as pci_whitelist
neutron_opts = [
@@ -643,6 +645,8 @@ class API(base_api.NetworkAPI):
context, instance, request.pci_request_id, port_req_body,
network=network, neutron=neutron,
bind_host_id=bind_host_id)
self._populate_mac_address(instance, request.pci_request_id,
port_req_body)
if request.port_id:
port = ports[request.port_id]
port_client.update_port(port['id'], port_req_body)
@@ -716,6 +720,38 @@ class API(base_api.NetworkAPI):
}
port_req_body['port']['binding:profile'] = profile
@staticmethod
def _populate_mac_address(instance, pci_request_id, port_req_body):
"""Add the updated MAC address value to the update_port request body.
Currently this is done only for PF passthrough.
"""
if pci_request_id is not None:
pci_devs = pci_manager.get_instance_pci_devs(
instance, pci_request_id)
if len(pci_devs) != 1:
# NOTE(ndipanov): We shouldn't ever get here since
# InstancePCIRequest instances built from network requests
# only ever index a single device, which needs to be
# successfully claimed for this to be called as part of
# allocate_networks method
LOG.error(_LE("PCI request %s does not have a "
"unique device associated with it. Unable to "
"determine MAC address"),
pci_request, instance=instance)
return
pci_dev = pci_devs[0]
if pci_dev.dev_type == obj_fields.PciDeviceType.SRIOV_PF:
try:
mac = pci_utils.get_mac_by_pci_address(pci_dev.address)
except exception.PciDeviceNotFoundById as e:
LOG.error(
_LE("Could not determine MAC address for %(addr)s, "
"error: %(e)s"),
{"addr": pci_dev.address, "e": e}, instance=instance)
else:
port_req_body['port']['mac_address'] = mac
def _populate_neutron_extension_values(self, context, instance,
pci_request_id, port_req_body,
network=None, neutron=None,

View File

@@ -41,6 +41,7 @@ from nova.network.neutronv2 import api as neutronapi
from nova.network.neutronv2 import constants
from nova import objects
from nova.pci import manager as pci_manager
from nova.pci import utils as pci_utils
from nova.pci import whitelist as pci_whitelist
from nova import policy
from nova import test
@@ -3907,6 +3908,74 @@ class TestNeutronv2Portbinding(TestNeutronv2Base):
self.assertEqual(profile, port_req_body['port']['binding:profile'])
def _populate_mac_address_fakes(self):
instance = fake_instance.fake_instance_obj(self.context)
pci_dev = {'vendor_id': '1377',
'product_id': '0047',
'address': '0000:0a:00.1',
'dev_type': 'type-PF'}
pf = objects.PciDevice()
vf = objects.PciDevice()
pf.update_device(pci_dev)
pci_dev['dev_type'] = 'type-VF'
vf.update_device(pci_dev)
return instance, pf, vf
@mock.patch.object(pci_manager, 'get_instance_pci_devs')
@mock.patch.object(pci_utils, 'get_mac_by_pci_address')
def test_populate_mac_address_pf(self, mock_get_mac_by_pci_address,
mock_get_instance_pci_devs):
api = neutronapi.API()
instance, pf, vf = self._populate_mac_address_fakes()
port_req_body = {'port': {}}
mock_get_instance_pci_devs.return_value = [pf]
mock_get_mac_by_pci_address.return_value = 'fake-mac-address'
expected_port_req_body = {'port': {'mac_address': 'fake-mac-address'}}
req = port_req_body.copy()
api._populate_mac_address(instance, 0, req)
self.assertEqual(expected_port_req_body, req)
@mock.patch.object(pci_manager, 'get_instance_pci_devs')
@mock.patch.object(pci_utils, 'get_mac_by_pci_address')
def test_populate_mac_address_vf(self, mock_get_mac_by_pci_address,
mock_get_instance_pci_devs):
api = neutronapi.API()
instance, pf, vf = self._populate_mac_address_fakes()
port_req_body = {'port': {}}
mock_get_instance_pci_devs.return_value = [vf]
req = port_req_body.copy()
api._populate_mac_address(instance, 42, port_req_body)
self.assertEqual(port_req_body, req)
@mock.patch.object(pci_manager, 'get_instance_pci_devs')
@mock.patch.object(pci_utils, 'get_mac_by_pci_address')
def test_populate_mac_address_vf_fail(self, mock_get_mac_by_pci_address,
mock_get_instance_pci_devs):
api = neutronapi.API()
instance, pf, vf = self._populate_mac_address_fakes()
port_req_body = {'port': {}}
mock_get_instance_pci_devs.return_value = [vf]
mock_get_mac_by_pci_address.side_effect = (
exception.PciDeviceNotFoundById)
req = port_req_body.copy()
api._populate_mac_address(instance, 42, port_req_body)
self.assertEqual(port_req_body, req)
@mock.patch.object(pci_manager, 'get_instance_pci_devs')
def test_populate_mac_address_no_device(self, mock_get_instance_pci_devs):
api = neutronapi.API()
instance, pf, vf = self._populate_mac_address_fakes()
port_req_body = {'port': {}}
mock_get_instance_pci_devs.return_value = []
req = port_req_body.copy()
api._populate_mac_address(instance, 42, port_req_body)
self.assertEqual(port_req_body, req)
def _test_update_port_binding_false(self, func_name, *args):
api = neutronapi.API()
func = getattr(api, func_name)