Skip to content

Commit 5ffec5d

Browse files
committed
[OVN] Set MTU of the VETH interfaces between OVS and metadata
The VETH pair between the metadata namespace and the local OVS now has the same MTU as the network associated to this metadata service. The "LSP.external_ids" field has a new key defined: "neutron:mtu". This is the value of the network MTU. This patch does not update the previous metadata datapaths nor the existing LSP. This change will affect only to new created ports and the corresponding metadata datapaths. Conflicts: neutron/agent/ovn/metadata/agent.py Closes-Bug: #2053274 Change-Id: I7ff300e9634e5e3fc68d70540392109fd8b9babc (cherry picked from commit 47b4d14) (cherry picked from commit 101898f)
1 parent 0673a9b commit 5ffec5d

File tree

3 files changed

+56
-57
lines changed

3 files changed

+56
-57
lines changed

neutron/agent/ovn/metadata/agent.py

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def run(self, event, row, old):
100100
with _SYNC_STATE_LOCK.read_lock():
101101
self.log_row(row)
102102
try:
103-
self.agent.provision_datapath(row.datapath)
103+
self.agent.provision_datapath(row)
104104
except ConfigException:
105105
# We're now in the reader lock mode, we need to exit the
106106
# context and then use writer lock
@@ -400,12 +400,12 @@ def _get_ovn_bridge(self):
400400
"br-int instead.")
401401
return 'br-int'
402402

403-
def get_networks_datapaths(self):
404-
"""Return a set of datapath objects of the VIF ports on the current
403+
def get_networks_port_bindings(self):
404+
"""Return a set of Port_Binding objects of the VIF ports on the current
405405
chassis.
406406
"""
407407
ports = self.sb_idl.get_ports_on_chassis(self.chassis)
408-
return set(p.datapath for p in self._vif_ports(ports))
408+
return list(self._vif_ports(ports))
409409

410410
@_sync_lock
411411
def sync(self, provision=True):
@@ -420,12 +420,12 @@ def sync(self, provision=True):
420420
system_namespaces = tuple(
421421
ns.decode('utf-8') if isinstance(ns, bytes) else ns
422422
for ns in ip_lib.list_network_namespaces())
423-
net_datapaths = self.get_networks_datapaths()
424-
metadata_namespaces = [
423+
net_port_bindings = self.get_networks_port_bindings()
424+
metadata_namespaces = set(
425425
self._get_namespace_name(
426426
ovn_utils.get_network_name_from_datapath(datapath))
427-
for datapath in net_datapaths
428-
]
427+
for datapath in (pb.datapath for pb in net_port_bindings)
428+
)
429429
unused_namespaces = [ns for ns in system_namespaces if
430430
ns.startswith(NS_PREFIX) and
431431
ns not in metadata_namespaces]
@@ -439,8 +439,8 @@ def sync(self, provision=True):
439439
# even those that are already running. This is to make sure
440440
# everything within each namespace is up to date.
441441
if provision:
442-
for datapath in net_datapaths:
443-
self.provision_datapath(datapath)
442+
for port_binding in net_port_bindings:
443+
self.provision_datapath(port_binding)
444444

445445
@staticmethod
446446
def _get_veth_name(datapath):
@@ -611,19 +611,21 @@ def _get_provision_params(self, datapath):
611611

612612
return net_name, datapath_ports_ips, metadata_port_info
613613

614-
def provision_datapath(self, datapath):
614+
def provision_datapath(self, port_binding):
615615
"""Provision the datapath so that it can serve metadata.
616616
617617
This function will create the namespace and VETH pair if needed
618618
and assign the IP addresses to the interface corresponding to the
619619
metadata port of the network. It will also remove existing IP from
620620
the namespace if they are no longer needed.
621621
622-
:param datapath: datapath object.
623-
:return: The metadata namespace name for the datapath or None
624-
if namespace was not provisioned
622+
:param port_binding: Port_Binding object.
623+
:return: The metadata namespace name for the Port_Binding.datapath or
624+
None if namespace was not provisioned
625625
"""
626-
626+
datapath = port_binding.datapath
627+
mtu = int(port_binding.external_ids.get(
628+
ovn_const.OVN_NETWORK_MTU_EXT_ID_KEY) or '0')
627629
provision_params = self._get_provision_params(datapath)
628630
if not provision_params:
629631
return
@@ -652,6 +654,11 @@ def provision_datapath(self, datapath):
652654
# Configure the MAC address.
653655
ip2.link.set_address(metadata_port_info.mac)
654656

657+
# Set VETH ports MTU.
658+
if mtu:
659+
ip1.link.set_mtu(mtu)
660+
ip2.link.set_mtu(mtu)
661+
655662
# Make sure both ends of the VETH are up
656663
ip1.link.set_up()
657664
ip2.link.set_up()

neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
"address6_scope_id",
8080
"vnic_type",
8181
"capabilities",
82+
"mtu",
8283
],
8384
)
8485

@@ -324,6 +325,7 @@ def _get_port_options(self, port):
324325
address6_scope_id = ""
325326
dhcpv4_options = self._get_port_dhcp_options(port, const.IP_VERSION_4)
326327
dhcpv6_options = self._get_port_dhcp_options(port, const.IP_VERSION_6)
328+
mtu = ''
327329
if vtep_physical_switch:
328330
vtep_logical_switch = bp_info.bp_param.get('vtep-logical-switch')
329331
port_type = 'vtep'
@@ -421,10 +423,10 @@ def _get_port_options(self, port):
421423
ovn_const.VIF_DETAILS_PF_MAC_ADDRESS in bp_info.bp_param):
422424
port_net = self._plugin.get_network(
423425
context, port['network_id'])
426+
mtu = str(port_net['mtu'])
424427
options.update({
425428
ovn_const.LSP_OPTIONS_VIF_PLUG_TYPE_KEY: 'representor',
426-
ovn_const.LSP_OPTIONS_VIF_PLUG_MTU_REQUEST_KEY: str(
427-
port_net['mtu']),
429+
ovn_const.LSP_OPTIONS_VIF_PLUG_MTU_REQUEST_KEY: mtu,
428430
ovn_const.LSP_OPTIONS_VIF_PLUG_REPRESENTOR_PF_MAC_KEY: (
429431
bp_info.bp_param.get(
430432
ovn_const.VIF_DETAILS_PF_MAC_ADDRESS)),
@@ -465,7 +467,7 @@ def _get_port_options(self, port):
465467
parent_name, tag, dhcpv4_options, dhcpv6_options,
466468
cidrs.strip(), device_owner, sg_ids,
467469
address4_scope_id, address6_scope_id,
468-
bp_info.vnic_type, bp_info.capabilities
470+
bp_info.vnic_type, bp_info.capabilities, mtu
469471
)
470472

471473
def update_port_dhcp_options(self, port_info, txn):
@@ -506,6 +508,7 @@ def get_external_ids_from_port(self, port):
506508
ovn_const.OVN_PORT_VNIC_TYPE_KEY: port_info.vnic_type,
507509
ovn_const.OVN_PORT_BP_CAPABILITIES_KEY:
508510
';'.join(port_info.capabilities),
511+
ovn_const.OVN_NETWORK_MTU_EXT_ID_KEY: port_info.mtu,
509512
}
510513
return port_info, external_ids
511514

neutron/tests/unit/agent/ovn/metadata/test_agent.py

Lines changed: 28 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from neutron.agent.linux.ip_lib import IPWrapper as ip_wrap
2929
from neutron.agent.ovn.metadata import agent
3030
from neutron.agent.ovn.metadata import driver
31+
from neutron.common.ovn import constants as ovn_const
3132
from neutron.conf.agent.metadata import config as meta_conf
3233
from neutron.conf.agent.ovn.metadata import config as ovn_meta_conf
3334
from neutron.conf.plugins.ml2.drivers.ovn import ovn_conf
@@ -100,14 +101,8 @@ def test_sync(self):
100101

101102
self.agent.sync()
102103

103-
pdp.assert_has_calls(
104-
[
105-
mock.call(p.datapath)
106-
for p in self.ports
107-
],
108-
any_order=True
109-
)
110-
104+
pdp.assert_has_calls([mock.call(p) for p in self.ports],
105+
any_order=True)
111106
lnn.assert_called_once_with()
112107
tdp.assert_not_called()
113108

@@ -124,13 +119,8 @@ def test_sync_teardown_namespace(self):
124119

125120
self.agent.sync()
126121

127-
pdp.assert_has_calls(
128-
[
129-
mock.call(p.datapath)
130-
for p in self.ports
131-
],
132-
any_order=True
133-
)
122+
pdp.assert_has_calls([mock.call(p) for p in self.ports],
123+
any_order=True)
134124
lnn.assert_called_once_with()
135125
tdp.assert_called_once_with('3')
136126

@@ -149,27 +139,23 @@ def test_sync_teardown_namespace_does_not_crash_on_error(self):
149139
side_effect=Exception()) as tdp:
150140
self.agent.sync()
151141

152-
pdp.assert_has_calls(
153-
[
154-
mock.call(p.datapath)
155-
for p in self.ports
156-
],
157-
any_order=True
158-
)
142+
pdp.assert_has_calls([mock.call(p) for p in self.ports],
143+
any_order=True)
159144
lnn.assert_called_once_with()
160145
tdp.assert_called_once_with('3')
161146

162-
def test_get_networks_datapaths(self):
163-
"""Test get_networks_datapaths returns only datapath objects for the
164-
networks containing vif ports of type ''(blank) and 'external'.
147+
def test_get_networks_port_bindings(self):
148+
"""Test get_networks_port_bindings returns only the port binding
149+
objects for ports with VIF type empty ('') or 'external'.
165150
This test simulates that this chassis has the following ports:
166-
* datapath '1': 1 port type '' , 1 port 'external' and
167-
1 port 'unknown'
168-
* datapath '2': 1 port type ''
169-
* datapath '3': 1 port with type 'external'
170-
* datapath '4': 1 port with type 'unknown'
171-
172-
It is expected that only datapaths '1', '2' and '3' are returned
151+
* port0: datapath 1, type ''
152+
* port1: datapath 1, type 'external'
153+
* port2: datapath 1, type 'unknown'
154+
* port3: datapath 2, type ''
155+
* port4: datapath 3, type 'external'
156+
* port5: datapath 4, type 'unknown'
157+
158+
Only port bindings from ports 0, 1, 3, and 4 are expected.
173159
"""
174160

175161
datapath_1 = DatapathInfo(uuid='uuid1',
@@ -192,11 +178,8 @@ def test_get_networks_datapaths(self):
192178

193179
with mock.patch.object(self.agent.sb_idl, 'get_ports_on_chassis',
194180
return_value=ports):
195-
expected_datapaths = set([datapath_1, datapath_2, datapath_3])
196-
self.assertSetEqual(
197-
expected_datapaths,
198-
self.agent.get_networks_datapaths()
199-
)
181+
self.assertEqual([ports[0], ports[1], ports[3], ports[4]],
182+
self.agent.get_networks_port_bindings())
200183

201184
def test_teardown_datapath(self):
202185
"""Test teardown datapath.
@@ -424,7 +407,8 @@ def test_provision_datapath(self):
424407
mock.patch.object(agent.MetadataAgent, '_get_namespace_name',
425408
return_value=nemaspace_name),\
426409
mock.patch.object(ip_link, 'set_up') as link_set_up,\
427-
mock.patch.object(ip_link, 'set_address') as link_set_addr,\
410+
mock.patch.object(ip_link, 'set_address') as link_set_addr, \
411+
mock.patch.object(ip_link, 'set_mtu') as link_set_mtu, \
428412
mock.patch.object(ip_addr, 'list', return_value=[]),\
429413
mock.patch.object(
430414
ip_addr, 'add_multiple') as ip_addr_add_multiple,\
@@ -442,7 +426,11 @@ def test_provision_datapath(self):
442426
# We need to assert that it was deleted first.
443427
self.agent.ovs_idl.list_br.return_value.execute.return_value = (
444428
['br-int', 'br-fake'])
445-
self.agent.provision_datapath('fake_datapath')
429+
mtu = 1500
430+
port_binding = mock.Mock(
431+
datapath='fake_datapath',
432+
external_ids={ovn_const.OVN_NETWORK_MTU_EXT_ID_KEY: str(mtu)})
433+
self.agent.provision_datapath(port_binding)
446434

447435
# Check that the port was deleted from br-fake
448436
self.agent.ovs_idl.del_port.assert_called_once_with(
@@ -452,6 +440,7 @@ def test_provision_datapath(self):
452440
nemaspace_name)
453441
# Make sure that the two ends of the VETH pair have been set as up.
454442
self.assertEqual(2, link_set_up.call_count)
443+
link_set_mtu.assert_has_calls([mock.call(mtu), mock.call(mtu)])
455444
link_set_addr.assert_called_once_with('aa:bb:cc:dd:ee:ff')
456445
# Make sure that the port has been added to OVS.
457446
self.agent.ovs_idl.add_port.assert_called_once_with(

0 commit comments

Comments
 (0)