Skip to content

lbipam: Fix deletion of multi-block IP pool #40013

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

pippolo84
Copy link
Member

Currently, the operator panics when a multi blocks CiliumLoadBalancerIPPool is deleted. To reproduce it, just run Cilium in a local kind cluster and apply and delete the following pool:

apiVersion: "cilium.io/v2alpha1"
kind: CiliumLoadBalancerIPPool
metadata:
  name: "ip-pool-blue"
spec:
  blocks:
  - cidr: 192.0.2.96/32
  - cidr: 2001:DB8:0:700::/124
  - cidr: 10.112.182.48/28
  - cidr: 2001:DB8:0:400::/128
  serviceSelector:
    matchExpressions:
      - {key: color, operator: In, values: [blue]}

The PR fixes the LBIPAM reconciliation following a deletion of a CiliumLoadBalancerIPPool with multiple IP blocks. To do so, rewrite the reconciliation to:

  1. delete all the blocks first, then the pool in the LBIPAM internal status
  2. reconcile all modified services
  3. avoid removing items from the pool ranges slice when iterating on it

Please review commit by commit

LBIPAM: Fix deletion of CiliumLoadBalancerIPPool with multiple IP blocks that led to an operator crash

@pippolo84 pippolo84 added kind/bug This is a bug in the Cilium logic. release-note/bug This PR fixes an issue in a previous release of Cilium. area/operator Impacts the cilium-operator component affects/v1.14 This issue affects v1.14 branch feature/lb-ipam needs-backport/1.15 needs-backport/1.16 This PR / issue needs backporting to the v1.16 branch needs-backport/1.17 This PR / issue needs backporting to the v1.17 branch labels Jun 12, 2025
@pippolo84 pippolo84 marked this pull request as ready for review June 12, 2025 16:00
@pippolo84 pippolo84 requested a review from a team as a code owner June 12, 2025 16:00
@pippolo84 pippolo84 requested a review from aditighag June 12, 2025 16:00
@pippolo84

This comment was marked as outdated.

@pippolo84 pippolo84 force-pushed the pr/pippolo84/fix-lbipam-pool-multi-cidr-del branch from 1273a30 to 8d4743c Compare June 12, 2025 16:06
@pippolo84
Copy link
Member Author

/test

Whenever a pool is deleted, the operator deletes all LB ranges of that
pool and then strip off each address allocation related to the removed
ranges. While doing so, it attempts to immediately reconcile each
service that lost an address, trying to allocating another address from
an alive range. The reason to do so instead of running a full
reconciliation is to improve efficiency: since each k8s object
describing a service that lost an allocation should be patched, a later
change to reallocate another address would lead to an additional update
immediately after.

However, trying to immediately reconcile a service while deleting the
ranges might lead to issues in the allocation. In the case of a
multi-range IP pool, if we try to reconcile a service while deleting the
first range, we might end up allocating an IP from a range that belongs
to the same pool, leading to a further removal and reconciliation in the
next iteration. Moreover, the internal LBIPAM manager status is not
consistent during the loop: while the pool has already been deleted, the
ranges from that pool are being deleting one at a time. Therefore, a
reconciliation attempt in the middle of the ranges deletion, might
allocate an IP from a range with a non-existent parent pool, leading to
spuriuos warnings like the following:

`Bad state detected, store contains lbRange for pool 'pool-a' but
missing the pool`

To solve this the commit breaks the current deleteRangeAllocations in
two parts.  In the first one, we loop over the ranges to remove each of
them alongside any allocation for an address contained in the range.
Each modified service is just collected and returned.  Then, after
deleting the removed pool from the LBIPAM internal status, we finally
reconcile each modified service, trying to reallocate an address
immediately to avoid the double update.

Signed-off-by: Fabio Falzoi <fabio.falzoi@isovalent.com>
When handling a pool deletion event, the LBIPAM manager loops over the
removed pool ranges to strip off each address allocation with an IP
contained in one of the ranges. While doing that, it also updates the
poolToRanges internal map removing the range it is iterating on from the
slice keyed by the deleted pool name.

Removing items from a slice while iterating on them with a for range
loop is incorrect, since the length of the slice is evaluated just once
at the loop start. In case of a pool with multiple ranges, this may lead
to the following panic:

```
$ go test -trimpath -v ./operator/pkg/lbipam/... -run="TestPoolDelete"
=== RUN   TestPoolDelete
--- FAIL: TestPoolDelete (0.00s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x2db94b8]

goroutine 98 [running]:
testing.tRunner.func1.2({0x3203820, 0x61279f0})
	testing/testing.go:1734 +0x21c
testing.tRunner.func1()
	testing/testing.go:1737 +0x35e
panic({0x3203820?, 0x61279f0?})
	runtime/panic.go:792 +0x132
github.com/cilium/cilium/operator/pkg/lbipam.(*rangesStore).Delete(0xc0003b0bf8, 0x0)
	github.com/cilium/cilium/operator/pkg/lbipam/range_store.go:34 +0x1d8
github.com/cilium/cilium/operator/pkg/lbipam.(*LBIPAM).handlePoolDeleted(0xc0003b0b60, {0x3d66d08, 0xc000653540}, 0xc0006e6b00)
	github.com/cilium/cilium/operator/pkg/lbipam/lbipam.go:1763 +0x1df
github.com/cilium/cilium/operator/pkg/lbipam.(*LBIPAM).poolOnDelete(0xc0003b0b60, {0x3d66d08, 0xc000653540}, 0xc0006e6b00)
	github.com/cilium/cilium/operator/pkg/lbipam/lbipam.go:345 +0xe7
github.com/cilium/cilium/operator/pkg/lbipam.(*LBIPAM).handlePoolEvent(0xc0003b0b60, {0x3d66d08?, 0xc000653540?}, {{0x38bfe05, 0x6}, {{0xc00051e6d8, 0x6}, {0x0, 0x0}}, 0xc0006e6b00, ...})
	github.com/cilium/cilium/operator/pkg/lbipam/lbipam.go:262 +0x87
github.com/cilium/cilium/operator/pkg/lbipam.(*newFixture).DeletePool(0xc00008bef0, 0xc0006836c0, 0xc0006e6b00)
	github.com/cilium/cilium/operator/pkg/lbipam/lbipam_fixture_test.go:192 +0x1a5
github.com/cilium/cilium/operator/pkg/lbipam.TestPoolDelete(0xc0006836c0)
	github.com/cilium/cilium/operator/pkg/lbipam/lbipam_test.go:1814 +0x385
testing.tRunner(0xc0006836c0, 0x3a35298)
	testing/testing.go:1792 +0xf4
created by testing.(*T).Run in goroutine 1
	testing/testing.go:1851 +0x413
FAIL	github.com/cilium/cilium/operator/pkg/lbipam	0.031s
FAIL
```

The commit extends the TestDisablePool unit test to have multiple ranges
in the fixture pools and then fixes the issue shallow copying the ranges
slice before starting the iteration.

Signed-off-by: Fabio Falzoi <fabio.falzoi@isovalent.com>
@pippolo84 pippolo84 force-pushed the pr/pippolo84/fix-lbipam-pool-multi-cidr-del branch from 8d4743c to a1d6cc0 Compare June 13, 2025 07:37
Copy link
Member

@dylandreimerink dylandreimerink left a comment

Choose a reason for hiding this comment

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

👍 thank you for the detailed explanation of the issue and its fix

@pippolo84 pippolo84 removed the request for review from aditighag June 13, 2025 12:33
@pippolo84
Copy link
Member Author

/test

@pippolo84
Copy link
Member Author

ci-clustermesh hit #39855, rerunning

@maintainer-s-little-helper maintainer-s-little-helper bot added the ready-to-merge This PR has passed all tests and received consensus from code owners to merge. label Jun 13, 2025
@dylandreimerink dylandreimerink added this pull request to the merge queue Jun 13, 2025
Merged via the queue into cilium:main with commit f4b9b76 Jun 13, 2025
68 checks passed
@joamaki joamaki mentioned this pull request Jun 17, 2025
4 tasks
@joamaki joamaki added backport-pending/1.15 The backport for Cilium 1.15.x for this PR is in progress. and removed needs-backport/1.15 labels Jun 17, 2025
@joamaki joamaki mentioned this pull request Jun 17, 2025
4 tasks
@joamaki joamaki added backport-pending/1.16 The backport for Cilium 1.16.x for this PR is in progress. and removed needs-backport/1.16 This PR / issue needs backporting to the v1.16 branch labels Jun 17, 2025
@joamaki joamaki mentioned this pull request Jun 17, 2025
5 tasks
@joamaki joamaki added backport-pending/1.17 The backport for Cilium 1.17.x for this PR is in progress. and removed needs-backport/1.17 This PR / issue needs backporting to the v1.17 branch labels Jun 17, 2025
@github-actions github-actions bot added backport-done/1.15 The backport for Cilium 1.15.x for this PR is done. backport-done/1.16 The backport for Cilium 1.16.x for this PR is done. backport-done/1.17 The backport for Cilium 1.17.x for this PR is done. and removed backport-pending/1.15 The backport for Cilium 1.15.x for this PR is in progress. backport-pending/1.16 The backport for Cilium 1.16.x for this PR is in progress. backport-pending/1.17 The backport for Cilium 1.17.x for this PR is in progress. labels Jun 19, 2025
@pippolo84 pippolo84 removed the affects/v1.14 This issue affects v1.14 branch label Jul 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/operator Impacts the cilium-operator component backport-done/1.15 The backport for Cilium 1.15.x for this PR is done. backport-done/1.16 The backport for Cilium 1.16.x for this PR is done. backport-done/1.17 The backport for Cilium 1.17.x for this PR is done. feature/lb-ipam kind/bug This is a bug in the Cilium logic. ready-to-merge This PR has passed all tests and received consensus from code owners to merge. release-note/bug This PR fixes an issue in a previous release of Cilium.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants