diff --git a/kayobe/plugins/filter/nmstate.py b/kayobe/plugins/filter/nmstate.py index 7fae395f1..78d55cccf 100644 --- a/kayobe/plugins/filter/nmstate.py +++ b/kayobe/plugins/filter/nmstate.py @@ -519,6 +519,8 @@ def get_iface(name): # _port_type_. for port in br_ports or []: port_iface = get_iface(port) + if mtu: + port_iface.setdefault("mtu", mtu) if "type" not in port_iface: # Check for explicit type configuration port_type = networks.net_attr( @@ -586,6 +588,22 @@ def get_iface(name): parent = re.sub( r'\.{}$'.format(vlan_id), '', iface_name) + # NOTE(bbezak): Do not pass MTU for VLAN interfaces on bridges when + # it is identical to the parent bridge, to work around a + # NetworkManager bug. + bridge_mtus = {} + for bridge in networks.net_select_bridges( + context, names, inventory_hostname): + bridge_interface = networks.net_interface( + context, bridge, inventory_hostname) + bridge_mtus[bridge_interface] = networks.net_mtu( + context, bridge, inventory_hostname) + + if parent in bridge_mtus: + parent_mtu = bridge_mtus[parent] + if mtu and mtu == parent_mtu: + del iface["mtu"] + iface["vlan"] = { "base-iface": parent, "id": int(vlan_id) diff --git a/kayobe/tests/unit/plugins/filter/test_nmstate.py b/kayobe/tests/unit/plugins/filter/test_nmstate.py index da1fef140..b3b5efe1e 100644 --- a/kayobe/tests/unit/plugins/filter/test_nmstate.py +++ b/kayobe/tests/unit/plugins/filter/test_nmstate.py @@ -44,6 +44,7 @@ class TestNMStateFilter(unittest.TestCase): "net3_interface": "br0", "net3_bridge_ports": ['eth1'], "net3_bridge_stp": True, + "net3_mtu": 9000, # net4: bond on bond0 with slaves eth2 and eth3. "net4_interface": "bond0", "net4_bond_slaves": ['eth2', 'eth3'], @@ -123,6 +124,7 @@ def test_nmstate_config_bridge(self): result = nmstate.nmstate_config(self.context, ["net3"]) br_iface = next(i for i in result["interfaces"] if i["name"] == "br0") self.assertEqual(br_iface["type"], "linux-bridge") + self.assertEqual(br_iface["mtu"], 9000) self.assertEqual(br_iface["bridge"]["port"], [{"name": "eth1"}]) self.assertTrue(br_iface["bridge"]["options"]["stp"]["enabled"]) @@ -130,6 +132,7 @@ def test_nmstate_config_bridge(self): eth1_iface = next(i for i in result["interfaces"] if i["name"] == "eth1") self.assertEqual(eth1_iface["type"], "ethernet") + self.assertEqual(eth1_iface["mtu"], 9000) def test_nmstate_config_bond(self): result = nmstate.nmstate_config(self.context, ["net4"]) @@ -434,6 +437,44 @@ def test_vlan_interface_explicit_vlan_and_parent(self): self.assertEqual(vlan_iface["vlan"]["base-iface"], "eth0") self.assertEqual(vlan_iface["vlan"]["id"], 100) + def test_vlan_on_bridge_inherits_matching_mtu(self): + variables = { + "inventory_hostname": "test-host", + "ansible_facts": {"os_family": "RedHat"}, + "vlan_interface": "br0.6", + "vlan_vlan": 6, + "vlan_mtu": 9150, + "bridge_interface": "br0", + "bridge_bridge_ports": ["eth0"], + "bridge_mtu": 9150, + } + context = self._make_context(variables) + result = nmstate.nmstate_config(context, ["vlan", "bridge"]) + + vlan_iface = next( + i for i in result["interfaces"] + if i["name"] == "br0.6") + self.assertNotIn("mtu", vlan_iface) + + def test_vlan_on_bridge_keeps_different_mtu(self): + variables = { + "inventory_hostname": "test-host", + "ansible_facts": {"os_family": "RedHat"}, + "vlan_interface": "br0.6", + "vlan_vlan": 6, + "vlan_mtu": 9000, + "bridge_interface": "br0", + "bridge_bridge_ports": ["eth0"], + "bridge_mtu": 9150, + } + context = self._make_context(variables) + result = nmstate.nmstate_config(context, ["vlan", "bridge"]) + + vlan_iface = next( + i for i in result["interfaces"] + if i["name"] == "br0.6") + self.assertEqual(vlan_iface["mtu"], 9000) + def test_vlan_interface_invalid_name(self): """Test VLAN with invalid interface name is skipped gracefully.""" variables = {