Skip to content

feat(neutron): split UnderstackDriver into L2 and Undersync mechanism drivers#2043

Open
nidzrai wants to merge 1 commit into
mainfrom
split_mechanism
Open

feat(neutron): split UnderstackDriver into L2 and Undersync mechanism drivers#2043
nidzrai wants to merge 1 commit into
mainfrom
split_mechanism

Conversation

@nidzrai
Copy link
Copy Markdown
Contributor

@nidzrai nidzrai commented May 18, 2026

Split the existing UnderstackDriver into two hierarchical ML2 mechanism drivers:

  • UnderstackDriver (level 0): handles VLAN allocation, trunk config, calls
    continue_binding() to pass the VLAN segment to the next driver
  • UnderstackUndersyncDriver (level 1): receives the VLAN segment and calls
    set_binding() to finalise the port as ACTIVE

Also fixes bind_port() to use context.segments_to_bind instead of
context.network.network_segments so the driver only sees segments for the
current binding level.

tested On dev stack, following are the logs to confirm the split working correctly.

May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: DEBUG neutron.plugins.ml2.managers [None req-364601f8-bb7c-4884-81b9-2f72dd2714eb admin admin] Attempting to bind port 5cac0409-5180-454c-9a0c-c6e5f8a31acb by drivers understack,understack_undersync,ovn on host nidhi-os-dev at level 0 using segments [{'id': '4c314e71-f663-4551-98db-5a03606761d7', 'network_type': 'vxlan', 'physical_network': None, 'segmentation_id': 2, 'network_id': '261e3aa7-37e5-4918-b31d-ea974bd772b1'}] {{(pid=308862) _bind_port_level /opt/stack/neutron/neutron/plugins/ml2/managers.py:877}}
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: DEBUG neutron_understack.neutron_understack_mech [None req-364601f8-bb7c-4884-81b9-2f72dd2714eb admin admin] Attempting to bind port 5cac0409-5180-454c-9a0c-c6e5f8a31acb on network 261e3aa7-37e5-4918-b31d-ea974bd772b1 {{(pid=308862) bind_port /opt/stack/devstack/understack/python/neutron-understack/neutron_understack/neutron_understack_mech.py:272}}
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: DEBUG neutron_understack.neutron_understack_mech [None req-364601f8-bb7c-4884-81b9-2f72dd2714eb admin admin] bind_port_segment: interface network 261e3aa7-37e5-4918-b31d-ea974bd772b1 vlan group public {{(pid=308862) _bind_port_segment /opt/stack/devstack/understack/python/neutron-understack/neutron_understack/neutron_understack_mech.py:310}}
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: DEBUG neutron.db.segments_db [None req-364601f8-bb7c-4884-81b9-2f72dd2714eb admin admin] No dynamic segment found for Network:261e3aa7-37e5-4918-b31d-ea974bd772b1, Physical network:public, segmentation_id:None {{(pid=308862) get_dynamic_segment /opt/stack/neutron/neutron/db/segments_db.py:151}}
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: DEBUG neutron_understack.neutron_understack_mech [None req-364601f8-bb7c-4884-81b9-2f72dd2714eb admin admin] bind_port_segment: Native VLAN segment {'network_type': 'vlan', 'physical_network': 'public', 'segmentation_id': 1, 'mtu': 1500, 'id': 'f2e3a11f-13cb-4f72-aa97-6d2b8f8fa456'} {{(pid=308862) _bind_port_segment /opt/stack/devstack/understack/python/neutron-understack/neutron_understack/neutron_understack_mech.py:331}}
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: DEBUG neutron_understack.neutron_understack_mech [None req-364601f8-bb7c-4884-81b9-2f72dd2714eb admin admin] continue_binding for segment: {'id': '4c314e71-f663-4551-98db-5a03606761d7', 'network_type': 'vxlan', 'physical_network': None, 'segmentation_id': 2, 'network_id': '261e3aa7-37e5-4918-b31d-ea974bd772b1'} {{(pid=308862) _bind_port_segment /opt/stack/devstack/understack/python/neutron-understack/neutron_understack/neutron_understack_mech.py:338}}
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: DEBUG neutron.plugins.ml2.managers [None req-364601f8-bb7c-4884-81b9-2f72dd2714eb admin admin] Attempting to bind port 5cac0409-5180-454c-9a0c-c6e5f8a31acb by drivers understack,understack_undersync,ovn on host nidhi-os-dev at level 1 using segments [{'network_type': 'vlan', 'physical_network': 'public', 'segmentation_id': 1, 'mtu': 1500, 'id': 'f2e3a11f-13cb-4f72-aa97-6d2b8f8fa456'}] {{(pid=308862) _bind_port_level /opt/stack/neutron/neutron/plugins/ml2/managers.py:877}}
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: DEBUG neutron_understack.neutron_understack_mech [None req-364601f8-bb7c-4884-81b9-2f72dd2714eb admin admin] Attempting to bind port 5cac0409-5180-454c-9a0c-c6e5f8a31acb on network 261e3aa7-37e5-4918-b31d-ea974bd772b1 {{(pid=308862) bind_port /opt/stack/devstack/understack/python/neutron-understack/neutron_understack/neutron_understack_mech.py:272}}
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: DEBUG neutron.plugins.ml2.managers [None req-364601f8-bb7c-4884-81b9-2f72dd2714eb admin admin] Bound port: 5cac0409-5180-454c-9a0c-c6e5f8a31acb, host: nidhi-os-dev, vif_type: other, vif_details: {}, binding_levels: [{'bound_driver': 'understack', 'bound_segment': {'id': '4c314e71-f663-4551-98db-5a03606761d7', 'network_type': 'vxlan', 'physical_network': None, 'segmentation_id': 2, 'network_id': '261e3aa7-37e5-4918-b31d-ea974bd772b1'}}, {'bound_driver': 'understack_undersync', 'bound_segment': {'id': 'f2e3a11f-13cb-4f72-aa97-6d2b8f8fa456', 'network_type': 'vlan', 'physical_network': 'public', 'segmentation_id': 1, 'network_id': '261e3aa7-37e5-4918-b31d-ea974bd772b1'}}] {{(pid=308862) _bind_port_level /opt/stack/neutron/neutron/plugins/ml2/managers.py:988}}
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: DEBUG neutron.plugins.ml2.db [None req-364601f8-bb7c-4884-81b9-2f72dd2714eb admin admin] For port 5cac0409-5180-454c-9a0c-c6e5f8a31acb, host nidhi-os-dev, set binding levels [PortBindingLevel(driver='understack',host='nidhi-os-dev',level=0,port_id=5cac0409-5180-454c-9a0c-c6e5f8a31acb,segment=NetworkSegment(4c314e71-f663-4551-98db-5a03606761d7),segment_id=4c314e71-f663-4551-98db-5a03606761d7), PortBindingLevel(driver='understack_undersync',host='nidhi-os-dev',level=1,port_id=5cac0409-5180-454c-9a0c-c6e5f8a31acb,segment=NetworkSegment(f2e3a11f-13cb-4f72-aa97-6d2b8f8fa456),segment_id=f2e3a11f-13cb-4f72-aa97-6d2b8f8fa456)] {{(pid=308862) set_binding_levels /opt/stack/neutron/neutron/plugins/ml2/db.py:59}}
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: ERROR neutron.plugins.ml2.managers [None req-364601f8-bb7c-4884-81b9-2f72dd2714eb admin admin] Mechanism driver 'understack' failed in update_port_postcommit: requests.exceptions.ConnectionError: HTTPConnectionPool(host='undersync.undersync.svc.cluster.local', port=8080): Max retries exceeded with url: /v1/vlan-group/public/dry-run (Caused by NameResolutionError("HTTPConnection(host='undersync.undersync.svc.cluster.local', port=8080): Failed to resolve 'undersync.undersync.svc.cluster.local' ([Errno -2] Name or service not known)"))
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: ERROR neutron.plugins.ml2.managers   File "/opt/stack/devstack/understack/python/neutron-understack/neutron_understack/neutron_understack_mech.py", line 160, in update_port_postcommit
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: ERROR neutron.plugins.ml2.managers   File "/opt/stack/devstack/understack/python/neutron-understack/neutron_understack/neutron_understack_mech.py", line 186, in _update_port_baremetal
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: ERROR neutron.plugins.ml2.managers     self.invoke_undersync(vlan_group_name)
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: ERROR neutron.plugins.ml2.managers   File "/opt/stack/devstack/understack/python/neutron-understack/neutron_understack/neutron_understack_mech.py", line 345, in invoke_undersync
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: ERROR neutron.plugins.ml2.managers   File "/opt/stack/devstack/understack/python/neutron-understack/neutron_understack/undersync.py", line 64, in sync_devices
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: ERROR neutron.plugins.ml2.managers     return self.dry_run(vlan_group)
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: ERROR neutron.plugins.ml2.managers   File "/opt/stack/devstack/understack/python/neutron-understack/neutron_understack/undersync.py", line 103, in dry_run
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: ERROR neutron.plugins.ml2.managers     return self._undersync_post("dry-run", vlan_group)
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: ERROR neutron.plugins.ml2.managers   File "/opt/stack/devstack/understack/python/neutron-understack/neutron_understack/undersync.py", line 89, in _undersync_post
May 19 14:52:38 nidhi-os-dev devstack@neutron-api.service[308862]: DEBUG ovsdbapp.backend.ovs_idl.transaction [None req-7f7b052b-fe0b-4037-8dda-dbfb5c9ff9ab None None] Running txn n=1 command(idx=0): CheckRevisionNumberCommand(_result=None, name=5cac0409-5180-454c-9a0c-c6e5f8a31acb, resource={'id': '5cac0409-5180-454c-9a0c-c6e5f8a31acb', 'name': 'test-bm-vxlan-port', 'network_id': '261e3aa7-37e5-4918-b31d-ea974bd772b1', 'project_id': '901618ec41f340b2be6d78598fb50874', 'mac_address': 'fa:16:3e:d3:04:78', 'admin_state_up': True, 'status': 'ACTIVE', 'device_id': '', 'device_owner': '', 'standard_attr_id': 64, 'fixed_ips': [{'subnet_id': '68eb6a09-2dc8-4aeb-a331-280489f95543', 'ip_address': '10.10.20.85'}], 'allowed_address_pairs': [], 'extra_dhcp_opts': [], 'security_groups': [], 'description': '', 'binding:vnic_type': 'baremetal', 'binding:profile': {'physical_network': 'public'}, 'binding:host_id': 'nidhi-os-dev', 'binding:vif_type': 'other', 'binding:vif_details': {'bound_drivers': {'0': 'understack', '1': 'understack_undersync'}}, 'port_security_enabled': True, 'ip_allocation': 'immediate', 'tags': [], 'created_at': '2026-05-19T14:52:31Z', 'updated_at': '2026-05-19T14:52:38Z', 'revision_number': 4, 'tenant_id': '901618ec41f340b2be6d78598fb50874', 'network': {'id': '261e3aa7-37e5-4918-b31d-ea974bd772b1', 'name': 'test-vxlan-1', 'tenant_id': '901618ec41f340b2be6d78598fb50874', 'project_id': '901618ec41f340b2be6d78598fb50874', 'admin_state_up': True, 'mtu': 1450, 'status': 'ACTIVE', 'subnets': ['68eb6a09-2dc8-4aeb-a331-280489f95543'], 'standard_attr_id': 60, 'shared': False, 'availability_zone_hints': [], 'availability_zones': [], 'ipv4_address_scope': None, 'ipv6_address_scope': None, 'router:external': False, 'qinq': False, 'vlan_transparent': False, 'description': '', 'port_security_enabled': True, 'l2_adjacency': True, 'tags': [], 'created_at': '2026-05-19T14:52:19Z', 'updated_at': '2026-05-19T14:52:26Z', 'revision_number': 2, 'provider:network_type': 'vxlan', 'provider:physical_network': None, 'provider:segmentation_id': 2}}, resource_type=ports, if_exists=True) {{(pid=308862) do_commit /opt/stack/data/venv/lib/python3.12/site-packages/ovsdbapp/backend/ovs_idl/transaction.py:89}}
Read from remote host 66.70.103.144: Operation timed out
Connection to 66.70.103.144 closed.
openstack port show test-bm-vxlan-port
+-------------------------+----------------------------------------------------------------------------+
| Field                   | Value                                                                      |
+-------------------------+----------------------------------------------------------------------------+
| admin_state_up          | UP                                                                         |
| allowed_address_pairs   |                                                                            |
| binding_host_id         | nidhi-os-dev                                                               |
| binding_profile         | physical_network='public'                                                  |
| binding_vif_details     | bound_drivers.0='understack', bound_drivers.1='understack_undersync'       |
| binding_vif_type        | other                                                                      |
| binding_vnic_type       | baremetal                                                                  |
| created_at              | 2026-05-19T14:52:31Z                                                       |
| data_plane_status       | None                                                                       |
| description             |                                                                            |
| device_id               |                                                                            |
| device_owner            |                                                                            |
| device_profile          | None                                                                       |
| dns_assignment          |                                                                            |
| dns_domain              | None                                                                       |
| dns_name                | None                                                                       |
| extra_dhcp_opts         |                                                                            |
| fixed_ips               | ip_address='10.10.20.85', subnet_id='68eb6a09-2dc8-4aeb-a331-280489f95543' |
| hardware_offload_type   | None                                                                       |
| hints                   |                                                                            |
| id                      | 5cac0409-5180-454c-9a0c-c6e5f8a31acb                                       |
| ip_allocation           | immediate                                                                  |
| mac_address             | fa:16:3e:d3:04:78                                                          |
| name                    | test-bm-vxlan-port                                                         |
| network_id              | 261e3aa7-37e5-4918-b31d-ea974bd772b1                                       |
| numa_affinity_policy    | None                                                                       |
| port_security_enabled   | True                                                                       |
| project_id              | 901618ec41f340b2be6d78598fb50874                                           |
| propagate_uplink_status | None                                                                       |
| resource_request        | None                                                                       |
| revision_number         | 4                                                                          |
| qos_network_policy_id   | None                                                                       |
| qos_policy_id           | None                                                                       |
| security_group_ids      |                                                                            |
| status                  | ACTIVE                                                                     |
| tags                    |                                                                            |
| trunk_details           | None                                                                       |
| trusted                 | None                                                                       |
| updated_at              | 2026-05-19T14:52:38Z                                                       |
+-------------------------+----------------------------------------------------------------------------+
stack@nidhi-os-dev:~$

Comment thread python/neutron-understack/neutron_understack/tests/test_undersync_mech.py Outdated
@nidzrai nidzrai force-pushed the split_mechanism branch from 43bfc35 to f1ae04f Compare May 19, 2026 15:28
@nidzrai nidzrai force-pushed the split_mechanism branch from f1ae04f to 3a46594 Compare May 19, 2026 15:36
Copy link
Copy Markdown
Collaborator

@skrobul skrobul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@mfencik - can you please have a look at this too?

understack_driver.trunk_driver = understack_trunk_driver

port_context.allocate_dynamic_segment.assert_called_once()
port_context.continue_binding.assert_called_once()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good, but I think it would be valuable to assert that correct arguments were given (segmentation_id and next_segment_to_bind), something like this:

def test_with_no_trunk(
    self,
    mocker,
    port_context,
    understack_driver,
    understack_trunk_driver,
    vlan_network_segment,
):
    mocker.patch.object(
        port_context, "allocate_dynamic_segment", return_value=vlan_network_segment
    )
    mocker.patch.object(port_context, "continue_binding")
    type(port_context).segments_to_bind = mocker.PropertyMock(
        return_value=port_context.network.network_segments
    )
    understack_driver.bind_port(port_context)
    understack_driver.trunk_driver = understack_trunk_driver
    port_context.allocate_dynamic_segment.assert_called_once()
    # Find the VXLAN segment that should be used as parent segment_id
    vxlan_segment = next(
        s for s in port_context.segments_to_bind
        if s[api.NETWORK_TYPE] == "vxlan"
    )
    port_context.continue_binding.assert_called_once_with(
        segment_id=vxlan_segment[api.ID],
        next_segments_to_bind=[vlan_network_segment],
    )

Copy link
Copy Markdown
Contributor

@mfencik mfencik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good, as I understand this is the first step in many as we want to separate all undersync operations to the understackundersync driver.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants