neutron: retrieve physical network name from a multi-provider network
Multi-provider networks are a combination of vxlan and vlan networks. such a network has a special "segments" field that holds a list of networks. Each element of this list has the same structure as the 'provider network attributes'. These attributes are: - provider:network_type - provider:physical_network - provider:segmentation_id This patch will retrieve the relevant physical network name from a multi-provider network Change-Id: Icb9a546e6fcbf399fcef3e9ea686b35ec3817cd5 Closes-Bug: #1659467
This commit is contained in:
parent
35eaa27a04
commit
b9d9d96a40
@ -1019,6 +1019,10 @@ class API(base_api.NetworkAPI):
|
|||||||
self._refresh_neutron_extensions_cache(context, neutron=neutron)
|
self._refresh_neutron_extensions_cache(context, neutron=neutron)
|
||||||
return constants.AUTO_ALLOCATE_TOPO_EXT in self.extensions
|
return constants.AUTO_ALLOCATE_TOPO_EXT in self.extensions
|
||||||
|
|
||||||
|
def _has_multi_provider_extension(self, context, neutron=None):
|
||||||
|
self._refresh_neutron_extensions_cache(context, neutron=neutron)
|
||||||
|
return constants.MULTI_NET_EXT in self.extensions
|
||||||
|
|
||||||
def _get_pci_device_profile(self, pci_dev):
|
def _get_pci_device_profile(self, pci_dev):
|
||||||
dev_spec = self.pci_whitelist.get_devspec(pci_dev)
|
dev_spec = self.pci_whitelist.get_devspec(pci_dev)
|
||||||
if dev_spec:
|
if dev_spec:
|
||||||
@ -1402,6 +1406,37 @@ class API(base_api.NetworkAPI):
|
|||||||
raise exception.FixedIpNotFoundForSpecificInstance(
|
raise exception.FixedIpNotFoundForSpecificInstance(
|
||||||
instance_uuid=instance.uuid, ip=address)
|
instance_uuid=instance.uuid, ip=address)
|
||||||
|
|
||||||
|
def _get_phynet_info(self, context, neutron, net_id):
|
||||||
|
phynet_name = None
|
||||||
|
if self._has_multi_provider_extension(context, neutron=neutron):
|
||||||
|
network = neutron.show_network(net_id,
|
||||||
|
fields='segments').get('network')
|
||||||
|
segments = network.get('segments', {})
|
||||||
|
for net in segments:
|
||||||
|
# NOTE(vladikr): In general, "multi-segments" network is a
|
||||||
|
# combination of L2 segments. The current implementation
|
||||||
|
# contains a vxlan and vlan(s) segments, where only a vlan
|
||||||
|
# network will have a physical_network specified, but may
|
||||||
|
# change in the future. The purpose of this method
|
||||||
|
# is to find a first segment that provides a physical network.
|
||||||
|
# TODO(vladikr): Additional work will be required to handle the
|
||||||
|
# case of multiple vlan segments associated with different
|
||||||
|
# physical networks.
|
||||||
|
phynet_name = net.get('provider:physical_network')
|
||||||
|
if phynet_name:
|
||||||
|
return phynet_name
|
||||||
|
# Raising here as at least one segment should
|
||||||
|
# have a physical network provided.
|
||||||
|
if segments:
|
||||||
|
msg = (_("None of the segments of network %s provides a "
|
||||||
|
"physical_network") % net_id)
|
||||||
|
raise exception.NovaException(message=msg)
|
||||||
|
|
||||||
|
net = neutron.show_network(net_id,
|
||||||
|
fields='provider:physical_network').get('network')
|
||||||
|
phynet_name = net.get('provider:physical_network')
|
||||||
|
return phynet_name
|
||||||
|
|
||||||
def _get_port_vnic_info(self, context, neutron, port_id):
|
def _get_port_vnic_info(self, context, neutron, port_id):
|
||||||
"""Retrieve port vnic info
|
"""Retrieve port vnic info
|
||||||
|
|
||||||
@ -1415,9 +1450,7 @@ class API(base_api.NetworkAPI):
|
|||||||
network_model.VNIC_TYPE_NORMAL)
|
network_model.VNIC_TYPE_NORMAL)
|
||||||
if vnic_type in network_model.VNIC_TYPES_SRIOV:
|
if vnic_type in network_model.VNIC_TYPES_SRIOV:
|
||||||
net_id = port['network_id']
|
net_id = port['network_id']
|
||||||
net = neutron.show_network(net_id,
|
phynet_name = self._get_phynet_info(context, neutron, net_id)
|
||||||
fields='provider:physical_network').get('network')
|
|
||||||
phynet_name = net.get('provider:physical_network')
|
|
||||||
return vnic_type, phynet_name
|
return vnic_type, phynet_name
|
||||||
|
|
||||||
def create_pci_requests_for_sriov_ports(self, context, pci_requests,
|
def create_pci_requests_for_sriov_ports(self, context, pci_requests,
|
||||||
|
@ -19,3 +19,4 @@ PORTBINDING_EXT = 'Port Binding'
|
|||||||
VNIC_INDEX_EXT = 'VNIC Index'
|
VNIC_INDEX_EXT = 'VNIC Index'
|
||||||
DNS_INTEGRATION = 'DNS Integration'
|
DNS_INTEGRATION = 'DNS Integration'
|
||||||
AUTO_ALLOCATE_TOPO_EXT = 'Auto Allocated Topology Services'
|
AUTO_ALLOCATE_TOPO_EXT = 'Auto Allocated Topology Services'
|
||||||
|
MULTI_NET_EXT = 'Multi Provider Network'
|
||||||
|
@ -3139,6 +3139,98 @@ class TestNeutronv2(TestNeutronv2Base):
|
|||||||
self.assertEqual(0, len(networks))
|
self.assertEqual(0, len(networks))
|
||||||
|
|
||||||
@mock.patch.object(neutronapi, 'get_client', return_value=mock.Mock())
|
@mock.patch.object(neutronapi, 'get_client', return_value=mock.Mock())
|
||||||
|
def test_get_port_vnic_info_multi_segment(self, mock_get_client):
|
||||||
|
api = neutronapi.API()
|
||||||
|
self.mox.ResetAll()
|
||||||
|
test_port = {
|
||||||
|
'port': {'id': 'my_port_id1',
|
||||||
|
'network_id': 'net-id',
|
||||||
|
'binding:vnic_type': model.VNIC_TYPE_DIRECT,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
test_net = {'network': {'segments':
|
||||||
|
[{'provider:physical_network': 'phynet10',
|
||||||
|
'provider:segmentation_id': 1000,
|
||||||
|
'provider:network_type': 'vlan'},
|
||||||
|
{'provider:physical_network': None,
|
||||||
|
'provider:segmentation_id': 153,
|
||||||
|
'provider:network_type': 'vxlan'}]}}
|
||||||
|
test_ext_list = {'extensions':
|
||||||
|
[{'name': 'Multi Provider Network',
|
||||||
|
'alias': 'multi-segments'}]}
|
||||||
|
|
||||||
|
mock_client = mock_get_client()
|
||||||
|
mock_client.show_port.return_value = test_port
|
||||||
|
mock_client.list_extensions.return_value = test_ext_list
|
||||||
|
mock_client.show_network.return_value = test_net
|
||||||
|
vnic_type, phynet_name = api._get_port_vnic_info(
|
||||||
|
self.context, mock_client, test_port['port']['id'])
|
||||||
|
|
||||||
|
mock_client.show_network.assert_called_once_with(
|
||||||
|
test_port['port']['network_id'],
|
||||||
|
fields='segments')
|
||||||
|
self.assertEqual('phynet10', phynet_name)
|
||||||
|
|
||||||
|
@mock.patch.object(neutronapi, 'get_client', return_value=mock.Mock())
|
||||||
|
def test_get_port_vnic_info_vlan_with_multi_segment_ext(self,
|
||||||
|
mock_get_client):
|
||||||
|
api = neutronapi.API()
|
||||||
|
self.mox.ResetAll()
|
||||||
|
test_port = {
|
||||||
|
'port': {'id': 'my_port_id1',
|
||||||
|
'network_id': 'net-id',
|
||||||
|
'binding:vnic_type': model.VNIC_TYPE_DIRECT,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
test_net = {'network': {'provider:physical_network': 'phynet10',
|
||||||
|
'provider:segmentation_id': 1000,
|
||||||
|
'provider:network_type': 'vlan'}}
|
||||||
|
test_ext_list = {'extensions':
|
||||||
|
[{'name': 'Multi Provider Network',
|
||||||
|
'alias': 'multi-segments'}]}
|
||||||
|
|
||||||
|
mock_client = mock_get_client()
|
||||||
|
mock_client.show_port.return_value = test_port
|
||||||
|
mock_client.list_extensions.return_value = test_ext_list
|
||||||
|
mock_client.show_network.return_value = test_net
|
||||||
|
vnic_type, phynet_name = api._get_port_vnic_info(
|
||||||
|
self.context, mock_client, test_port['port']['id'])
|
||||||
|
|
||||||
|
mock_client.show_network.assert_called_with(
|
||||||
|
test_port['port']['network_id'],
|
||||||
|
fields='provider:physical_network')
|
||||||
|
self.assertEqual('phynet10', phynet_name)
|
||||||
|
|
||||||
|
@mock.patch.object(neutronapi, 'get_client', return_value=mock.Mock())
|
||||||
|
def test_get_port_vnic_info_multi_segment_no_phynet(self, mock_get_client):
|
||||||
|
api = neutronapi.API()
|
||||||
|
self.mox.ResetAll()
|
||||||
|
test_port = {
|
||||||
|
'port': {'id': 'my_port_id1',
|
||||||
|
'network_id': 'net-id',
|
||||||
|
'binding:vnic_type': model.VNIC_TYPE_DIRECT,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
test_net = {'network': {'segments':
|
||||||
|
[{'provider:physical_network': None,
|
||||||
|
'provider:segmentation_id': 1000,
|
||||||
|
'provider:network_type': 'vlan'},
|
||||||
|
{'provider:physical_network': None,
|
||||||
|
'provider:segmentation_id': 153,
|
||||||
|
'provider:network_type': 'vlan'}]}}
|
||||||
|
test_ext_list = {'extensions':
|
||||||
|
[{'name': 'Multi Provider Network',
|
||||||
|
'alias': 'multi-segments'}]}
|
||||||
|
|
||||||
|
mock_client = mock_get_client()
|
||||||
|
mock_client.show_port.return_value = test_port
|
||||||
|
mock_client.list_extensions.return_value = test_ext_list
|
||||||
|
mock_client.show_network.return_value = test_net
|
||||||
|
self.assertRaises(exception.NovaException,
|
||||||
|
api._get_port_vnic_info,
|
||||||
|
self.context, mock_client, test_port['port']['id'])
|
||||||
|
|
||||||
|
@mock.patch.object(neutronapi, 'get_client', return_value=mock.MagicMock())
|
||||||
def test_get_port_vnic_info_1(self, mock_get_client):
|
def test_get_port_vnic_info_1(self, mock_get_client):
|
||||||
api = neutronapi.API()
|
api = neutronapi.API()
|
||||||
self.mox.ResetAll()
|
self.mox.ResetAll()
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- Physical network name will be retrieved from a multi-segement network.
|
||||||
|
The current implementation will retrieve the physical network name for the
|
||||||
|
first segment that provides it. This is mostly intended to support a
|
||||||
|
combinatin of vxlan and vlan segments. Additional work will be required to
|
||||||
|
support a case of multiple vlan segments associated with different
|
||||||
|
physical networks.
|
Loading…
Reference in New Issue
Block a user