fix(routers/ovn): leftover uplink ports#2093
Open
skrobul wants to merge 4 commits into
Open
Conversation
Prior to this change, we have not been cleaning up `uplink-*` ports in all of the cases. For example, they are not being removed when the subnet is detached from the router, but we do clean it up when the router is deleted altogether.
Explains the event-driven machinery behind router interface attach/detach: what the uplink port is and why its VLAN tag is leaf-local, the creation flow, why two deletion handlers are needed (PORT PRECOMMIT_DELETE for router delete, ROUTER_INTERFACE AFTER_DELETE for subnet detach), and why the "last port" count threshold differs between them.
Two bugs prevented full cleanup when the last router subnet was detached: 1. _do_uplink_cleanup depended on fetch_router_network_segment, but Neutron releases the dynamic VLAN segment before ROUTER_INTERFACE AFTER_DELETE fires. The lookup returned None and the entire cleanup was skipped. Fix: anchor cleanup to the shared Neutron port (uplink-<seg_id>) by scanning ports on the network for the uplink- prefix — that port survives until we delete it. Remove the now-dead fetch_router_network_segment and its misleading error log. 2. shared_port.delete() (OVO) only removed the DB row; the OVN LSP was never deleted because OVO bypasses the ML2 mechanism manager. Fix: add delete_shared_port_lsp() that calls delete_lswitch_port by port UUID, mirroring the existing delete_uplink_port pattern. Both fixes apply to the subnet-detachment path (ROUTER_INTERFACE AFTER_DELETE) and the router-deletion path (PORT PRECOMMIT_DELETE).
The uplink Neutron port has two OVN LSPs, not one: the localnet LSP (uplink-<segment_id>, created explicitly by understack) and a regular port LSP (named by port UUID, created automatically by the OVN mech driver). Document both and add the delete_shared_port_lsp step to the _do_uplink_cleanup flowchart, which was missing from the diagram.
c079c96 to
fffb872
Compare
stevekeay
reviewed
Jun 23, 2026
stevekeay
left a comment
Contributor
There was a problem hiding this comment.
LGTM but Milan should look at this because he is way more familiar with that code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix OVN uplink LSP leak on router subnet detachment
When the last subnet is detached from a router (
openstack router remove subnet), the ML2 driver is supposed to clean up the uplink it created — remove the trunk subport, delete the OVN localnet LSP, and delete the shared Neutron port. In practice the shared Neutron port and its OVN LSP (<port-uuid>) were left behind.Root causes
Two independent bugs combined to cause the leak:
1. Cleanup anchored to a segment that no longer exists
_do_uplink_cleanupstarted by looking up the dynamic VLAN segment for the network. On subnet detachment, Neutron releases that segment before theROUTER_INTERFACE AFTER_DELETEevent fires. The lookup returnedNoneand the entire cleanup was skipped, including the shared port deletion.Fix: anchor cleanup on the shared Neutron port (
uplink-<segment_id>) instead — it persists until we delete it. The segment ID is derived from the port's name, eliminating the dependency on a live segment.2. OVO
.delete()leaves the OVN LSP behindshared_port.delete()is an OpenStack Versioned Objects call that only removes the database row. It bypasses the ML2 mechanism manager, so the OVN mechanism driver'sdelete_port_postcommitnever runs and the port's LSP (named by port UUID) is never removed.Fix: added
delete_shared_port_lsp()which explicitly callsdelete_lswitch_port(port_id, ...)on the OVN NB IDL before the OVO delete, mirroring the existingdelete_uplink_portpattern for the localnet LSP.Both fixes apply to both deletion paths: subnet detachment (
ROUTER_INTERFACE AFTER_DELETE) and router deletion (PORT PRECOMMIT_DELETE).Also included
neutron-networking.md, covering the uplink port concept, the two OVN LSPs it produces, the creation flow, and why two event handlers are needed with different port-count thresholds.