Merge "[ovn] Add neutron network to metadata namespace names"
This commit is contained in:
commit
f2d520f6ee
@ -31,6 +31,7 @@ from neutron.agent.ovn.metadata import driver as metadata_driver
|
||||
from neutron.agent.ovn.metadata import ovsdb
|
||||
from neutron.agent.ovn.metadata import server as metadata_server
|
||||
from neutron.common.ovn import constants as ovn_const
|
||||
from neutron.common.ovn import utils as ovn_utils
|
||||
from neutron.common import utils
|
||||
from neutron.conf.plugins.ml2.drivers.ovn import ovn_conf as config
|
||||
|
||||
@ -80,9 +81,10 @@ class PortBindingChassisEvent(row_event.RowEvent):
|
||||
return
|
||||
with _SYNC_STATE_LOCK.read_lock():
|
||||
try:
|
||||
LOG.info(self.LOG_MSG, row.logical_port,
|
||||
str(row.datapath.uuid))
|
||||
self.agent.update_datapath(str(row.datapath.uuid))
|
||||
net_name = ovn_utils.get_network_name_from_datapath(
|
||||
row.datapath)
|
||||
LOG.info(self.LOG_MSG, row.logical_port, net_name)
|
||||
self.agent.update_datapath(str(row.datapath.uuid), net_name)
|
||||
except ConfigException:
|
||||
# We're now in the reader lock mode, we need to exit the
|
||||
# context and then use writer lock
|
||||
@ -323,14 +325,20 @@ class MetadataAgent(object):
|
||||
def _vif_ports(self, ports):
|
||||
return (p for p in ports if p.type in OVN_VIF_PORT_TYPES)
|
||||
|
||||
def teardown_datapath(self, datapath):
|
||||
def teardown_datapath(self, datapath, net_name=None):
|
||||
"""Unprovision this datapath to stop serving metadata.
|
||||
|
||||
This function will shutdown metadata proxy if it's running and delete
|
||||
the VETH pair, the OVS port and the namespace.
|
||||
"""
|
||||
self.update_chassis_metadata_networks(datapath, remove=True)
|
||||
namespace = self._get_namespace_name(datapath)
|
||||
|
||||
# TODO(dalvarez): Remove this in Y cycle when we are sure that all
|
||||
# namespaces will be created with the Neutron network UUID and not
|
||||
# anymore with the OVN datapath UUID.
|
||||
dp = net_name or datapath
|
||||
|
||||
namespace = self._get_namespace_name(dp)
|
||||
ip = ip_lib.IPWrapper(namespace)
|
||||
# If the namespace doesn't exist, return
|
||||
if not ip.netns.exists(namespace):
|
||||
@ -340,16 +348,16 @@ class MetadataAgent(object):
|
||||
namespace)
|
||||
|
||||
metadata_driver.MetadataDriver.destroy_monitored_metadata_proxy(
|
||||
self._process_monitor, datapath, self.conf, namespace)
|
||||
self._process_monitor, dp, self.conf, namespace)
|
||||
|
||||
veth_name = self._get_veth_name(datapath)
|
||||
veth_name = self._get_veth_name(dp)
|
||||
self.ovs_idl.del_port(veth_name[0]).execute()
|
||||
if ip_lib.device_exists(veth_name[0]):
|
||||
ip_lib.IPWrapper().del_veth(veth_name[0])
|
||||
|
||||
ip.garbage_collect_namespace()
|
||||
|
||||
def update_datapath(self, datapath):
|
||||
def update_datapath(self, datapath, net_name):
|
||||
"""Update the metadata service for this datapath.
|
||||
|
||||
This function will:
|
||||
@ -364,9 +372,9 @@ class MetadataAgent(object):
|
||||
datapath_ports = [p for p in self._vif_ports(ports) if
|
||||
str(p.datapath.uuid) == datapath]
|
||||
if datapath_ports:
|
||||
self.provision_datapath(datapath)
|
||||
self.provision_datapath(datapath, net_name)
|
||||
else:
|
||||
self.teardown_datapath(datapath)
|
||||
self.teardown_datapath(datapath, net_name)
|
||||
|
||||
def _ensure_datapath_checksum(self, namespace):
|
||||
"""Ensure the correct checksum in the metadata packets in DPDK bridges
|
||||
@ -385,7 +393,7 @@ class MetadataAgent(object):
|
||||
iptables_mgr.ipv4['mangle'].add_rule('POSTROUTING', rule, wrap=False)
|
||||
iptables_mgr.apply()
|
||||
|
||||
def provision_datapath(self, datapath):
|
||||
def provision_datapath(self, datapath, net_name):
|
||||
"""Provision the datapath so that it can serve metadata.
|
||||
|
||||
This function will create the namespace and VETH pair if needed
|
||||
@ -395,7 +403,7 @@ class MetadataAgent(object):
|
||||
|
||||
:return: The metadata namespace name of this datapath
|
||||
"""
|
||||
LOG.debug("Provisioning datapath %s", datapath)
|
||||
LOG.debug("Provisioning metadata for network %s", net_name)
|
||||
port = self.sb_idl.get_metadata_port_network(datapath)
|
||||
# If there's no metadata port or it doesn't have a MAC or IP
|
||||
# addresses, then tear the namespace down if needed. This might happen
|
||||
@ -403,10 +411,10 @@ class MetadataAgent(object):
|
||||
# an IP address.
|
||||
if not (port and port.mac and
|
||||
port.external_ids.get(ovn_const.OVN_CIDRS_EXT_ID_KEY, None)):
|
||||
LOG.debug("There is no metadata port for datapath %s or it has no "
|
||||
LOG.debug("There is no metadata port for network %s or it has no "
|
||||
"MAC or IP addresses configured, tearing the namespace "
|
||||
"down if needed", datapath)
|
||||
self.teardown_datapath(datapath)
|
||||
"down if needed", net_name)
|
||||
self.teardown_datapath(datapath, net_name)
|
||||
return
|
||||
|
||||
# First entry of the mac field must be the MAC address.
|
||||
@ -414,9 +422,9 @@ class MetadataAgent(object):
|
||||
# If it is not, we can't provision the namespace. Tear it down if
|
||||
# needed and log the error.
|
||||
if not match:
|
||||
LOG.error("Metadata port for datapath %s doesn't have a MAC "
|
||||
LOG.error("Metadata port for network %s doesn't have a MAC "
|
||||
"address, tearing the namespace down if needed",
|
||||
datapath)
|
||||
net_name)
|
||||
self.teardown_datapath(datapath)
|
||||
return
|
||||
|
||||
@ -428,8 +436,8 @@ class MetadataAgent(object):
|
||||
|
||||
# Create the VETH pair if it's not created. Also the add_veth function
|
||||
# will create the namespace for us.
|
||||
namespace = self._get_namespace_name(datapath)
|
||||
veth_name = self._get_veth_name(datapath)
|
||||
namespace = self._get_namespace_name(net_name)
|
||||
veth_name = self._get_veth_name(net_name)
|
||||
|
||||
ip1 = ip_lib.IPDevice(veth_name[0])
|
||||
if ip_lib.device_exists(veth_name[1], namespace):
|
||||
@ -499,9 +507,9 @@ class MetadataAgent(object):
|
||||
metadata_driver.MetadataDriver.spawn_monitored_metadata_proxy(
|
||||
self._process_monitor, namespace, n_const.METADATA_PORT,
|
||||
self.conf, bind_address=n_const.METADATA_V4_IP,
|
||||
network_id=datapath)
|
||||
network_id=net_name)
|
||||
|
||||
self.update_chassis_metadata_networks(datapath)
|
||||
self.update_chassis_metadata_networks(net_name)
|
||||
return namespace
|
||||
|
||||
def ensure_all_networks_provisioned(self):
|
||||
@ -516,11 +524,13 @@ class MetadataAgent(object):
|
||||
"""
|
||||
# Retrieve all VIF ports in our Chassis
|
||||
ports = self.sb_idl.get_ports_on_chassis(self.chassis)
|
||||
datapaths = {str(p.datapath.uuid) for p in self._vif_ports(ports)}
|
||||
nets = {(str(p.datapath.uuid),
|
||||
ovn_utils.get_network_name_from_datapath(p.datapath))
|
||||
for p in self._vif_ports(ports)}
|
||||
namespaces = []
|
||||
# Make sure that all those datapaths are serving metadata
|
||||
for datapath in datapaths:
|
||||
netns = self.provision_datapath(datapath)
|
||||
for datapath, net_name in nets:
|
||||
netns = self.provision_datapath(datapath, net_name)
|
||||
if netns:
|
||||
namespaces.append(netns)
|
||||
|
||||
|
@ -561,3 +561,7 @@ def parse_ovn_lb_port_forwarding(ovn_rtr_lb_pfs):
|
||||
fip_dict[protocol] = fip_dict_proto
|
||||
result[fip_id] = fip_dict
|
||||
return result
|
||||
|
||||
|
||||
def get_network_name_from_datapath(datapath):
|
||||
return datapath.external_ids['name'].replace('neutron-', '')
|
||||
|
@ -816,8 +816,14 @@ class OvsdbSbOvnIdl(sb_impl_idl.OvnSbApiIdlImpl, Backend):
|
||||
rows = self.db_list_rows('Port_Binding').execute(check_error=True)
|
||||
# TODO(twilson) It would be useful to have a db_find that takes a
|
||||
# comparison function
|
||||
# TODO(dalvarez): Remove the comparison to r.datapath.uuid in Y cycle
|
||||
# when we are sure that all namespaces will be created with the
|
||||
# Neutron network UUID and not anymore with the OVN datapath UUID.
|
||||
return [r for r in rows
|
||||
if (r.mac and str(r.datapath.uuid) == network) and
|
||||
if (r.mac and (
|
||||
str(r.datapath.uuid) == network or
|
||||
utils.get_network_name_from_datapath(
|
||||
r.datapath) == network)) and
|
||||
ip_address in r.mac[0].split(' ')]
|
||||
|
||||
def set_port_cidrs(self, name, cidrs):
|
||||
|
@ -33,7 +33,7 @@ from neutron.tests import base
|
||||
|
||||
OvnPortInfo = collections.namedtuple(
|
||||
'OvnPortInfo', ['datapath', 'type', 'mac', 'external_ids', 'logical_port'])
|
||||
DatapathInfo = collections.namedtuple('DatapathInfo', 'uuid')
|
||||
DatapathInfo = collections.namedtuple('DatapathInfo', ['uuid', 'external_ids'])
|
||||
|
||||
|
||||
def makePort(datapath=None, type='', mac=None, external_ids=None,
|
||||
@ -119,11 +119,14 @@ class TestMetadataAgent(base.BaseTestCase):
|
||||
|
||||
ports = []
|
||||
for i in range(0, 3):
|
||||
ports.append(makePort(datapath=DatapathInfo(uuid=str(i))))
|
||||
ports.append(makePort(datapath=DatapathInfo(uuid='1')))
|
||||
ports.append(makePort(datapath=DatapathInfo(uuid='3'),
|
||||
type='external'))
|
||||
ports.append(makePort(datapath=DatapathInfo(uuid='5'), type='unknown'))
|
||||
ports.append(makePort(datapath=DatapathInfo(uuid=str(i),
|
||||
external_ids={'name': 'neutron-%d' % i})))
|
||||
ports.append(makePort(datapath=DatapathInfo(uuid='1',
|
||||
external_ids={'name': 'neutron-1'})))
|
||||
ports.append(makePort(datapath=DatapathInfo(uuid='3',
|
||||
external_ids={'name': 'neutron-3'}), type='external'))
|
||||
ports.append(makePort(datapath=DatapathInfo(uuid='5',
|
||||
external_ids={'name': 'neutron-5'}), type='unknown'))
|
||||
|
||||
with mock.patch.object(self.agent, 'provision_datapath',
|
||||
return_value=None) as pdp,\
|
||||
@ -131,40 +134,42 @@ class TestMetadataAgent(base.BaseTestCase):
|
||||
return_value=ports):
|
||||
self.agent.ensure_all_networks_provisioned()
|
||||
|
||||
expected_calls = [mock.call(str(i)) for i in range(0, 4)]
|
||||
expected_calls = [mock.call(str(i), str(i)) for i in range(0, 4)]
|
||||
self.assertEqual(sorted(expected_calls),
|
||||
sorted(pdp.call_args_list))
|
||||
|
||||
def test_update_datapath_provision(self):
|
||||
ports = []
|
||||
for i in range(0, 3):
|
||||
ports.append(makePort(datapath=DatapathInfo(uuid=str(i))))
|
||||
ports.append(makePort(datapath=DatapathInfo(uuid='3'),
|
||||
type='external'))
|
||||
ports.append(makePort(datapath=DatapathInfo(uuid=str(i),
|
||||
external_ids={'name': 'neutron-%d' % i})))
|
||||
ports.append(makePort(datapath=DatapathInfo(uuid='3',
|
||||
external_ids={'name': 'neutron-3'}), type='external'))
|
||||
|
||||
with mock.patch.object(self.agent, 'provision_datapath',
|
||||
return_value=None) as pdp,\
|
||||
mock.patch.object(self.agent, 'teardown_datapath') as tdp,\
|
||||
mock.patch.object(self.agent.sb_idl, 'get_ports_on_chassis',
|
||||
return_value=ports):
|
||||
self.agent.update_datapath('1')
|
||||
self.agent.update_datapath('3')
|
||||
expected_calls = [mock.call('1'), mock.call('3')]
|
||||
self.agent.update_datapath('1', 'a')
|
||||
self.agent.update_datapath('3', 'b')
|
||||
expected_calls = [mock.call('1', 'a'), mock.call('3', 'b')]
|
||||
pdp.assert_has_calls(expected_calls)
|
||||
tdp.assert_not_called()
|
||||
|
||||
def test_update_datapath_teardown(self):
|
||||
ports = []
|
||||
for i in range(0, 3):
|
||||
ports.append(makePort(datapath=DatapathInfo(uuid=str(i))))
|
||||
ports.append(makePort(datapath=DatapathInfo(uuid=str(i),
|
||||
external_ids={'name': 'neutron-%d' % i})))
|
||||
|
||||
with mock.patch.object(self.agent, 'provision_datapath',
|
||||
return_value=None) as pdp,\
|
||||
mock.patch.object(self.agent, 'teardown_datapath') as tdp,\
|
||||
mock.patch.object(self.agent.sb_idl, 'get_ports_on_chassis',
|
||||
return_value=ports):
|
||||
self.agent.update_datapath('5')
|
||||
tdp.assert_called_once_with('5')
|
||||
self.agent.update_datapath('5', 'a')
|
||||
tdp.assert_called_once_with('5', 'a')
|
||||
pdp.assert_not_called()
|
||||
|
||||
def test_teardown_datapath(self):
|
||||
@ -243,7 +248,7 @@ class TestMetadataAgent(base.BaseTestCase):
|
||||
# We need to assert that it was deleted first.
|
||||
self.agent.ovs_idl.list_br.return_value.execute.return_value = (
|
||||
['br-int', 'br-fake'])
|
||||
self.agent.provision_datapath('1')
|
||||
self.agent.provision_datapath('1', '1')
|
||||
|
||||
# Check that the port was deleted from br-fake
|
||||
self.agent.ovs_idl.del_port.assert_called_once_with(
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
other:
|
||||
- |
|
||||
The ``OVN Metadata Agent`` now creates the network namespaces including the
|
||||
Neutron network UUID in its name. Previously, the OVN datapath UUID was used
|
||||
and it was not obvious for operators and during debugging to figure out which
|
||||
namespace corresponded to what Neutron network.
|
Loading…
Reference in New Issue
Block a user