From ee2963d1ee18ce4a7ce7e6d404b7bbe5ea624704 Mon Sep 17 00:00:00 2001 From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 21:41:33 +0100 Subject: [PATCH] [PR #11182/76589bd9 backport][stable-12] nmcli: allow VxLan multicast and bridge port (#11251) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nmcli: allow VxLan multicast and bridge port (#11182) VxLan virtual devices can be added to bridge ports, like any other devices. And when using multicast remote addresses, NetworkManager need to know the parent device as well. (cherry picked from commit 76589bd97a746f000f6bfc2d12061f6b91e4ae05) Co-authored-by: Tiziano Müller Co-authored-by: Felix Fontein --- .../fragments/11182-vxlan-parent-bridging.yml | 2 + plugins/modules/nmcli.py | 20 +++++ tests/unit/plugins/modules/test_nmcli.py | 73 +++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 changelogs/fragments/11182-vxlan-parent-bridging.yml diff --git a/changelogs/fragments/11182-vxlan-parent-bridging.yml b/changelogs/fragments/11182-vxlan-parent-bridging.yml new file mode 100644 index 0000000000..8a33f678e5 --- /dev/null +++ b/changelogs/fragments/11182-vxlan-parent-bridging.yml @@ -0,0 +1,2 @@ +minor_changes: + - nmcli module - add ``vxlan_parent`` option required for multicast ``vxlan_remote`` addresses; add ``vxlan`` to list of bridgeable devices (https://github.com/ansible-collections/community.general/pull/11182). diff --git a/plugins/modules/nmcli.py b/plugins/modules/nmcli.py index f8c464e28a..3abd6e0618 100644 --- a/plugins/modules/nmcli.py +++ b/plugins/modules/nmcli.py @@ -530,6 +530,11 @@ options: description: - This is only used with VXLAN - VXLAN destination IP address. type: str + vxlan_parent: + description: + - This is only used with VXLAN - VXLAN parent device (required when using a multicast remote address). + type: str + version_added: 12.2.0 vxlan_local: description: - This is only used with VXLAN - VXLAN local IP address. @@ -1454,6 +1459,17 @@ EXAMPLES = r""" vxlan_local: 192.168.1.2 vxlan_remote: 192.168.1.5 + - name: Add VxLan via multicast on a bridge + community.general.nmcli: + type: vxlan + conn_name: vxlan_test2 + vxlan_id: 17 + vxlan_parent: eth1 + vxlan_local: 192.168.1.2 + vxlan_remote: 239.192.0.17 + slave_type: bridge + master: br0 + - name: Add gre community.general.nmcli: type: gre @@ -1784,6 +1800,7 @@ class Nmcli: self.ingress = module.params["ingress"] self.egress = module.params["egress"] self.vxlan_id = module.params["vxlan_id"] + self.vxlan_parent = module.params["vxlan_parent"] self.vxlan_local = module.params["vxlan_local"] self.vxlan_remote = module.params["vxlan_remote"] self.ip_tunnel_dev = module.params["ip_tunnel_dev"] @@ -2041,6 +2058,7 @@ class Nmcli: options.update( { "vxlan.id": self.vxlan_id, + "vxlan.parent": self.vxlan_parent, "vxlan.local": self.vxlan_local, "vxlan.remote": self.vxlan_remote, } @@ -2256,6 +2274,7 @@ class Nmcli: "infiniband", "ovs-port", "ovs-interface", + "vxlan", ) @property @@ -2825,6 +2844,7 @@ def create_module() -> AnsibleModule: egress=dict(type="str"), # vxlan specific vars vxlan_id=dict(type="int"), + vxlan_parent=dict(type="str"), vxlan_local=dict(type="str"), vxlan_remote=dict(type="str"), # ip-tunnel specific vars diff --git a/tests/unit/plugins/modules/test_nmcli.py b/tests/unit/plugins/modules/test_nmcli.py index c0c4ff4ca8..29a3cb85b0 100644 --- a/tests/unit/plugins/modules/test_nmcli.py +++ b/tests/unit/plugins/modules/test_nmcli.py @@ -843,6 +843,34 @@ vxlan.local: 192.168.225.5 vxlan.remote: 192.168.225.6 """ +TESTCASE_VXLAN_MULTICAST = [ + { + "type": "vxlan", + "conn_name": "vxlan_multicast_test", + "ifname": "vxlan-device", + "vxlan_id": 17, + "vxlan_parent": "eth1", + "vxlan_local": "192.168.1.2", + "vxlan_remote": "239.192.0.17", + "slave_type": "bridge", + "master": "br0", + "state": "present", + "_ansible_check_mode": False, + } +] + +TESTCASE_VXLAN_MULTICAST_SHOW_OUTPUT = """\ +connection.id: vxlan_multicast_test +connection.interface-name: vxlan-device +connection.autoconnect: yes +connection.slave-type: bridge +connection.master: br0 +vxlan.id: 17 +vxlan.parent: eth1 +vxlan.local: 192.168.1.2 +vxlan.remote: 239.192.0.17 +""" + TESTCASE_GRE = [ { "type": "gre", @@ -2912,6 +2940,51 @@ def test_vxlan_connection_unchanged(mocked_vxlan_connection_unchanged, capfd): assert not results["changed"] +@pytest.mark.parametrize("patch_ansible_module", TESTCASE_VXLAN_MULTICAST, indirect=["patch_ansible_module"]) +def test_create_vxlan_multicast(mocked_generic_connection_create, capfd): + """ + Test if vxlan with multicast and parent device created + """ + with pytest.raises(SystemExit): + nmcli.main() + + assert nmcli.Nmcli.execute_command.call_count == 1 + arg_list = nmcli.Nmcli.execute_command.call_args_list + args, kwargs = arg_list[0] + + assert args[0][0] == "/usr/bin/nmcli" + assert args[0][1] == "con" + assert args[0][2] == "add" + assert args[0][3] == "type" + assert args[0][4] == "vxlan" + assert args[0][5] == "con-name" + assert args[0][6] == "vxlan_multicast_test" + + args_text = list(map(to_text, args[0])) + for param in [ + "connection.interface-name", + "vxlan-device", + "vxlan.local", + "192.168.1.2", + "vxlan.remote", + "239.192.0.17", + "vxlan.id", + "17", + "vxlan.parent", + "eth1", + "connection.slave-type", + "bridge", + "connection.master", + "br0", + ]: + assert param in args_text + + out, err = capfd.readouterr() + results = json.loads(out) + assert not results.get("failed") + assert results["changed"] + + @pytest.mark.parametrize("patch_ansible_module", TESTCASE_IPIP, indirect=["patch_ansible_module"]) def test_create_ipip(mocked_generic_connection_create, capfd): """