Skip to content

FloatingIP creation can leak orphaned Neutron floating IPs, permanently blocking Subnet/Network deletion #889

Description

@mandre

Description

On the Flamingo E2E environment, the floatingip-update KUTTL test failed because namespace teardown timed out (4 min) waiting for the Subnet to delete. The Subnet's DELETE request repeatedly got 409 SubnetInUse because a port still held an IP allocation from it — a port belonging to an orphaned FloatingIP that ORC never recorded in status.

Evidence

From neutron-api.log, four POST /networking/v2.0/floatingips requests were made against the test's Network (988f35a2-...) within ~2 seconds:

time req-id result
13:55:20 req-3f560adf 400 (malformed)
13:55:20 req-482b9a27 400 (malformed)
13:55:21 req-b1cef117 201 → FloatingIP 477f8a6e-65d5-4f2d-b235-287a342e39d4, port 0f5a67e7-437f-460d-bccb-deb50c361675 (192.168.155.171)
13:55:22 req-f6905d58 201 → FloatingIP b656ccd3-7d81-4ea3-85b0-37b2868c9eba, port 3e7a2d04-... (192.168.155.114)

b656ccd3 is the one the test/ORC actually tracked (it gets tagged, untagged, and cleanly DELETEd at 13:55:25). 477f8a6e is never deleted anywhere in the log — it's a leaked floating IP, and its port (0f5a67e7) is the one neutron-api.log reports as blocking every subsequent subnet-delete retry:

INFO neutron.db.db_base_plugin_v2 [...] Found port (0f5a67e7-437f-460d-bccb-deb50c361675,
192.168.155.171) having IP allocation on subnet ef7f078a-..., cannot delete

This 409 repeats on every ORC retry from 13:55:25 through 13:58:19 (the last attempt visible before KUTTL's 4-minute timeout at ~13:59:25):

orc-pod.log (13:58:19Z):
ERROR Reconciler error {"controller": "subnet", ... "Subnet": {"name":"floatingip-update","namespace":"kuttl-frank-octopus-lxtf"}, ...
"error": "Expected HTTP response code [202 204] when accessing [DELETE http://10.1.0.32/networking/v2.0/subnets/ef7f078a-b15b-461b-8894-928425555fa0],
but got 409 instead: {\"NeutronError\": {\"type\": \"SubnetInUse\", \"message\": \"Unable to complete operation on subnet
ef7f078a-b15b-461b-8894-928425555fa0: One or more ports have an IP allocation from this subnet.\", \"detail\": \"\"}}"}

Root cause

internal/controllers/floatingip/actuator.go, ListOSResourcesForAdoption:

// we only support adoption of floatingips by IP as they don't have name
if resource.FloatingIP == nil {
    return nil, false
}

When no explicit floatingIP address is requested (as in this test — the common/default case), adoption is a no-op. So if a CreateResource call succeeds in Neutron but the reconcile that made the call doesn't end up persisting status.id (e.g. an error/retry happens between the successful POST and the Status().Patch() that records the ID), the next reconcile has status.id == nil, cannot discover the already-created floating IP, and creates a second one — permanently orphaning the first.

I wasn't able to pin down exactly why the first create's status write didn't stick: orc-pod.log in the collected CI artifact only covers 13:58:00 onward, missing the 13:55:19–13:55:25 window where the duplicate creation happened (hack/collectlogs appears to only retain the tail of the controller log).

Impact

  • Silent, permanent leak of an OpenStack FloatingIP + its port.
  • Can permanently deadlock deletion of any Subnet/Network sharing that port's allocation (as seen here — KUTTL/ORC retried for 4+ minutes with no progress, failing the test).
  • Only reproducible when a FloatingIP is created without a specific floatingIP address, since that's what disables adoption.

Suggested fix directions

  • Make FloatingIP creation idempotent/discoverable even without a fixed IP, e.g. by tagging created floating IPs with the ORC object's UID and using that tag as an adoption key.
  • And/or ensure "create in OpenStack" + "persist ID to status" happens as a unit that can't silently retry into a duplicate create (e.g. list-by-tag before create).

Environment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions