From 4a7f22a9126e04337d4127b519fa19b259cf4c4e Mon Sep 17 00:00:00 2001 From: Milan Fencik Date: Thu, 16 Jan 2025 16:40:40 +0000 Subject: [PATCH 1/4] add config option for nautobot network node switchport UUID --- python/neutron-understack/neutron_understack/config.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/python/neutron-understack/neutron_understack/config.py b/python/neutron-understack/neutron_understack/config.py index 6d4749d9..4c305570 100644 --- a/python/neutron-understack/neutron_understack/config.py +++ b/python/neutron-understack/neutron_understack/config.py @@ -43,6 +43,13 @@ "prefixes that need to be routable outside of a tenant environment." ), ), + cfg.StrOpt( + "network_node_switchport_uuid", + help=( + "Nautobot UUID of the network node's switchport interface, that " + "is used to trunk all vlans used by a neutron router." + ), + ), ] l3_svc_cisco_asa_opts = [ From 04fdb04bfe254cab906cb5e99448f3806ffce68d Mon Sep 17 00:00:00 2001 From: Milan Fencik Date: Thu, 16 Jan 2025 16:45:08 +0000 Subject: [PATCH 2/4] add vlan_tag and modify_native_vlan params toprep_switch_interface --- .../neutron_understack/nautobot.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/python/neutron-understack/neutron_understack/nautobot.py b/python/neutron-understack/neutron_understack/nautobot.py index 332a3f80..0aa83c58 100644 --- a/python/neutron-understack/neutron_understack/nautobot.py +++ b/python/neutron-understack/neutron_understack/nautobot.py @@ -124,23 +124,29 @@ def subnet_delete(self, subnet_uuid: str) -> dict: return self.make_api_request(url, "delete") def prep_switch_interface( - self, connected_interface_id: str, ucvni_uuid: str - ) -> str: + self, + connected_interface_id: str, + ucvni_uuid: str, + vlan_tag: int, + modify_native_vlan: bool | None = True, + ) -> dict: """Runs a Nautobot Job to update a switch interface for tenant mode. The nautobot job will assign vlans as required and set the interface into the correct mode for "normal" tenant operation. - The vlan group ID is returned. + The dictionary with vlan group ID and vlan tag is returned. """ url = "/api/plugins/undercloud-vni/prep_switch_interface" payload = { "ucvni_id": str(ucvni_uuid), "connected_interface_id": str(connected_interface_id), + "modify_native_vlan": modify_native_vlan, + "vlan_tag": vlan_tag, } resp_data = self.make_api_request(url, "post", payload) - return resp_data["vlan_group_id"] + return resp_data def detach_port(self, connected_interface_id: str, ucvni_uuid: str) -> str: """Runs a Nautobot Job to cleanup a switch interface. From fe2dc753a17a906e1bf24509def2c79b932eaa4b Mon Sep 17 00:00:00 2001 From: Milan Fencik Date: Thu, 16 Jan 2025 16:46:38 +0000 Subject: [PATCH 3/4] adjust UnderstackDriver to create vlan networks --- .../neutron_understack_mech.py | 54 +++++++++++++------ 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/python/neutron-understack/neutron_understack/neutron_understack_mech.py b/python/neutron-understack/neutron_understack/neutron_understack_mech.py index 51e95810..9a46ccc6 100644 --- a/python/neutron-understack/neutron_understack/neutron_understack_mech.py +++ b/python/neutron-understack/neutron_understack/neutron_understack_mech.py @@ -126,17 +126,29 @@ def create_network_postcommit(self, context): provider_type = network.get("provider:network_type") segmentation_id = network.get("provider:segmentation_id") physnet = network.get("provider:physical_network") + conf = cfg.CONF.ml2_understack - if provider_type == p_const.TYPE_VXLAN: - conf = cfg.CONF.ml2_understack - ucvni_group = conf.ucvni_group - self.nb.ucvni_create(network_id, ucvni_group, network_name, segmentation_id) - LOG.info( - "network %(net_id)s has been added on ucvni_group %(ucvni_group)s, " - "physnet %(physnet)s", - {"net_id": network_id, "ucvni_group": ucvni_group, "physnet": physnet}, - ) - self._create_nautobot_namespace(network_id, external) + if provider_type != p_const.TYPE_VLAN: + return + ucvni_group = conf.ucvni_group + self.nb.ucvni_create(network_id, ucvni_group, network_name) + LOG.info( + "network %(net_id)s has been added on ucvni_group %(ucvni_group)s, " + "physnet %(physnet)s", + {"net_id": network_id, "ucvni_group": ucvni_group, "physnet": physnet}, + ) + self._create_nautobot_namespace(network_id, external) + + vlan_group_id_and_vlan_tag = self.nb.prep_switch_interface( + connected_interface_id=conf.network_node_switchport_uuid, + ucvni_uuid=network_id, + modify_native_vlan=False, + vlan_tag=int(segmentation_id), + ) + self.undersync.sync_devices( + vlan_group_uuids=str(vlan_group_id_and_vlan_tag["vlan_group_id"]), + dry_run=cfg.CONF.ml2_understack.undersync_dry_run, + ) def update_network_precommit(self, context): log_call("update_network_precommit", context) @@ -232,8 +244,12 @@ def update_port_postcommit(self, context): return network_id = context.current["network_id"] + + vlan_tag = int(context.network.current.get("provider:segmentation_id")) connected_interface_uuid = self.fetch_connected_interface_uuid(context.current) - nb_vlan_group_id = self.update_nautobot(network_id, connected_interface_uuid) + nb_vlan_group_id = self.update_nautobot( + network_id, connected_interface_uuid, vlan_tag + ) self.undersync.sync_devices( vlan_group_uuids=str(nb_vlan_group_id), @@ -326,7 +342,12 @@ def fetch_connected_interface_uuid(self, context: dict) -> str: raise return connected_interface_uuid - def update_nautobot(self, network_id: str, connected_interface_uuid: str) -> UUID: + def update_nautobot( + self, + network_id: str, + connected_interface_uuid: str, + vlan_tag: int, + ) -> UUID: """Updates Nautobot with the new network ID and connected interface UUID. If the network ID is a provisioning network, sets the interface status to @@ -347,9 +368,12 @@ def update_nautobot(self, network_id: str, connected_interface_uuid: str) -> UUI switch_uuid = configure_port_status_data.get("device", {}).get("id") return UUID(self.nb.fetch_vlan_group_uuid(switch_uuid)) else: - return UUID( - self.nb.prep_switch_interface(connected_interface_uuid, network_id) - ) + vlan_group_id = self.nb.prep_switch_interface( + connected_interface_id=connected_interface_uuid, + ucvni_uuid=network_id, + vlan_tag=vlan_tag, + )["vlan_group_id"] + return UUID(vlan_group_id) def _delete_tenant_port_on_unbound(self, context): """Tenant network port cleanup in the UnderCloud infrastructure. From 28423d7e1010b4ec8648be3bf8ed55dee5f5396f Mon Sep 17 00:00:00 2001 From: Milan Fencik Date: Thu, 16 Jan 2025 16:47:26 +0000 Subject: [PATCH 4/4] change neutron understack mech tests for vlan network creation --- .../tests/test_neutron_understack_mech.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/python/neutron-understack/neutron_understack/tests/test_neutron_understack_mech.py b/python/neutron-understack/neutron_understack/tests/test_neutron_understack_mech.py index b646b965..d6b4b441 100644 --- a/python/neutron-understack/neutron_understack/tests/test_neutron_understack_mech.py +++ b/python/neutron-understack/neutron_understack/tests/test_neutron_understack_mech.py @@ -48,12 +48,16 @@ def test_fail_fetch_connected_interface_uuid(context): def test_update_nautobot_for_tenant_network(nautobot_client): driver.nb = nautobot_client attrs = { - "prep_switch_interface.return_value": "304bd384-338a-4365-9394-0c356ec698ed" + "prep_switch_interface.return_value": { + "vlan_group_id": "304bd384-338a-4365-9394-0c356ec698ed" + } } nautobot_client.configure_mock(**attrs) - driver.update_nautobot("111", "222") + driver.update_nautobot("111", "222", 333) - nautobot_client.prep_switch_interface.assert_called_once_with("222", "111") + nautobot_client.prep_switch_interface.assert_called_once_with( + connected_interface_id="222", ucvni_uuid="111", vlan_tag=333 + ) def test_update_nautobot_for_provisioning_network(nautobot_client): @@ -63,7 +67,7 @@ def test_update_nautobot_for_provisioning_network(nautobot_client): } nautobot_client.configure_mock(**attrs) driver.nb = nautobot_client - driver.update_nautobot("change_me", "333") + driver.update_nautobot("change_me", "333", 123) nautobot_client.configure_port_status.assert_called_once_with( "333", "Provisioning-Interface"