Skip to content

pkg/bpf: Synchronize access to map in DumpReliablyWithCallback #38590

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

Merged
merged 3 commits into from
May 12, 2025

Conversation

aditighag
Copy link
Member

@aditighag aditighag commented Mar 28, 2025

The method previously accessed the map construct directly, which could result in race conditions with other operations on the map, such as in the Close method.

One such data race was reported in the ctmap, where the map was closed by a periodically running controller while it was simultaneously accessed in DumpReliablyWithCallback. Currently, callers can invoke map operations in the callback
that acquire the map (write) lock. To allow such callbacks without causing a deadlock, acquire the (write) lock instead
of RLock.

(snippet)

2025-01-30T21:27:22.005325276Z Read at 0x00c0099535a8 by goroutine 6096710:
2025-01-30T21:27:22.005373476Z   github.com/cilium/ebpf/internal/sys.(*FD).Uint()
2025-01-30T21:27:22.005379677Z       /go/src/github.com/cilium/cilium/vendor/github.com/cilium/ebpf/internal/sys/fd.go:71 +0x144
2025-01-30T21:27:22.005446912Z   github.com/cilium/ebpf.(*Map).nextKey()
2025-01-30T21:27:22.005454006Z       /go/src/github.com/cilium/cilium/vendor/github.com/cilium/ebpf/map.go:993 +0x112
2025-01-30T21:27:22.005553101Z   github.com/cilium/ebpf.(*Map).NextKey()
2025-01-30T21:27:22.005560745Z       /go/src/github.com/cilium/cilium/vendor/github.com/cilium/ebpf/map.go:950 +0xae
2025-01-30T21:27:22.005640643Z   github.com/cilium/cilium/pkg/bpf.(*Map).NextKey()
2025-01-30T21:27:22.005647146Z       /go/src/github.com/cilium/cilium/pkg/bpf/map_linux.go:606 +0x11e
2025-01-30T21:27:22.005712027Z   github.com/cilium/cilium/pkg/bpf.(*Map).DumpReliablyWithCallback()
2025-01-30T21:27:22.005718629Z       /go/src/github.com/cilium/cilium/pkg/bpf/map_linux.go:768 +0x71b
2025-01-30T21:27:22.005815760Z   github.com/cilium/cilium/pkg/bpf.(*Map).GetModel()
2025-01-30T21:27:22.005822322Z       /go/src/github.com/cilium/cilium/pkg/bpf/map_linux.go:1413 +0x511
2025-01-30T21:27:22.005880481Z   github.com/cilium/cilium/pkg/bpf.GetOpenMaps()
2025-01-30T21:27:22.005886152Z       /go/src/github.com/cilium/cilium/pkg/bpf/map_register_linux.go:64 +0x2ad
2025-01-30T21:27:22.006024930Z   github.com/cilium/cilium/pkg/maps.(*getMapHandler).Handle()
2025-01-30T21:27:22.006034067Z       /go/src/github.com/cilium/cilium/pkg/maps/api.go:146 +0x24

2025-01-30T21:27:22.006410985Z Previous write at 0x00c0099535a8 by goroutine 4182:
2025-01-30T21:27:22.006418068Z   github.com/cilium/ebpf/internal/sys.(*FD).Disown()
2025-01-30T21:27:22.006423969Z       /go/src/github.com/cilium/cilium/vendor/github.com/cilium/ebpf/internal/sys/fd.go:93 +0x8e
2025-01-30T21:27:22.006429549Z   github.com/cilium/ebpf/internal/sys.(*FD).Close()
2025-01-30T21:27:22.006435180Z       /go/src/github.com/cilium/cilium/vendor/github.com/cilium/ebpf/internal/sys/fd.go:84 +0x47
2025-01-30T21:27:22.006870411Z   github.com/cilium/ebpf.(*Map).Close()
2025-01-30T21:27:22.006879989Z       /go/src/github.com/cilium/cilium/vendor/github.com/cilium/ebpf/map.go:1371 +0x1e6
2025-01-30T21:27:22.006884858Z   github.com/cilium/cilium/pkg/bpf.(*Map).Close()
2025-01-30T21:27:22.006890338Z       /go/src/github.com/cilium/cilium/pkg/bpf/map_linux.go:591 +0x1ac
2025-01-30T21:27:22.006895778Z   github.com/cilium/cilium/pkg/maps/ctmap.CalculateCTMapPressure.func1.deferwrap1()
2025-01-30T21:27:22.006901959Z       /go/src/github.com/cilium/cilium/pkg/maps/ctmap/ctmap.go:858 +0x33
2025-01-30T21:27:22.006907119Z   runtime.deferreturn()
2025-01-30T21:27:22.006957073Z       /usr/local/go/src/runtime/panic.go:605 +0x5d
2025-01-30T21:27:22.006962683Z   github.com/cilium/cilium/pkg/controller.(*controller).runController()
2025-01-30T21:27:22.007064754Z       /go/src/github.com/cilium/cilium/pkg/controller/controller.go:251 +0xa2
2025-01-30T21:27:22.007072437Z   github.com/cilium/cilium/pkg/controller.(*Manager).createControllerLocked.gowrap1()
2025-01-30T21:27:22.007077677Z       /go/src/github.com/cilium/cilium/pkg/controller/manager.go:111 +0xbc

Fixes: #37383

Fix data race involving DumpReliablyWithCallback map operation.

@aditighag aditighag added release-note/bug This PR fixes an issue in a previous release of Cilium. area/datapath Impacts bpf/ or low-level forwarding details, including map management and monitor messages. labels Mar 28, 2025
@aditighag
Copy link
Member Author

/test

@tommyp1ckles
Copy link
Contributor

There's a couple other places we access that directly, such as in the batch iterator: IterateAll function.

@aditighag aditighag force-pushed the pr/aditighag/fix-ctmap-race branch from e39de9c to 113a14e Compare April 22, 2025 17:35
@aditighag
Copy link
Member Author

/test

@aditighag aditighag force-pushed the pr/aditighag/fix-ctmap-race branch from 113a14e to eb0173e Compare April 22, 2025 20:47
@aditighag
Copy link
Member Author

/ci-runtime

@aditighag aditighag force-pushed the pr/aditighag/fix-ctmap-race branch from eb0173e to 3636997 Compare April 22, 2025 21:41
@aditighag
Copy link
Member Author

/test

@aditighag aditighag marked this pull request as ready for review April 22, 2025 22:01
@aditighag aditighag requested review from a team as code owners April 22, 2025 22:01
@aditighag aditighag requested review from jschwinger233 and rgo3 April 22, 2025 22:01
@aditighag
Copy link
Member Author

aditighag commented Apr 23, 2025

The test failures are due to a deadlock where map entries are being deleted while iterating over the map. The tricky thing is that the cilium agent has a common pattern where map entries are deleted while the map is being iterated. The logic is written with the assumption that DumpReliablyWithCallback doesn't acquire the map lock. Do we need some kind of implicit ref counting for map open and close operations as opposed to the current locking approach? The alternative is to introduce a non-locking version of the Delete method.

sync.(*RWMutex).Lock(0xc003cd74c0?)
        /usr/local/go/src/sync/rwmutex.go:155 +0x6a
github.com/cilium/cilium/pkg/bpf.(*Map).Delete(0xc0026276c0, {0x5727130, 0xc00093c9e0})
        ./pkg/bpf/map_linux.go:1283 +0x45
github.com/cilium/cilium/pkg/maps/ctmap.purgeCtEntry(0xc0026276c0?, {0x57704b0, 0xc00093c9e0}, 0xc001f44c00, 0x0, 0xc00147d500, 0x0)
        ./pkg/maps/ctmap/ctmap.go:387 +0x50
github.com/cilium/cilium/pkg/maps/ctmap.doGCForFamily.cleanup.func3({0x5727130?, 0xc00093c9e0}, {0x5727068, 0xc001f44c00})
        ./pkg/maps/ctmap/ctmap.go:463 +0x398
github.com/cilium/cilium/pkg/bpf.(*Map).DumpReliablyWithCallback(0xc0026276c0, 0xc001f171d0, 0xc001f17130)
        ./pkg/bpf/map_linux.go:799 +0x4df
github.com/cilium/cilium/pkg/maps/ctmap.iterate[...](0xc0026276c0, 0xc000ffb580, 0xc001f171d0)
        ./pkg/maps/ctmap/ctmap.go:415 +0x6c
github.com/cilium/cilium/pkg/maps/ctmap.doGCForFamily(0xc0026276c0, {0x0?, 0xc0?, 0x0?, 0xc00074d230?}, 0xc00147d500, 0xc00147d540, 0x0)
        ./pkg/maps/ctmap/ctmap.go:375 +0xa05
github.com/cilium/cilium/pkg/maps/ctmap.doGC(0xc000e7dc30?, {0x90?, 0xc0?, 0x0?, 0xc00074d230?}, 0x479ef60?, 0xc002627710?)
        ./pkg/maps/ctmap/ctmap.go:503 +0x65

@aditighag aditighag force-pushed the pr/aditighag/fix-ctmap-race branch from 3636997 to d0f0563 Compare April 24, 2025 01:35
@aditighag
Copy link
Member Author

/test

@aditighag aditighag marked this pull request as draft April 25, 2025 15:29
@aditighag aditighag force-pushed the pr/aditighag/fix-ctmap-race branch from d0f0563 to c2795bd Compare May 1, 2025 19:24
@aditighag
Copy link
Member Author

/test

@aditighag aditighag marked this pull request as ready for review May 1, 2025 19:27
@aditighag aditighag force-pushed the pr/aditighag/fix-ctmap-race branch from c2795bd to 9fccc7b Compare May 1, 2025 19:43
@aditighag
Copy link
Member Author

/test

Copy link
Contributor

@rgo3 rgo3 left a comment

Choose a reason for hiding this comment

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

I see other functions that call m.Delete, e.g. doFlush4/6, which are passed as a callback to DumpReliablyWithCallback. Shouldn't those call m.DeleteLocked instead?

As a nit, there is a typo in the second commit message, referring to nat as "nap".

@aditighag aditighag force-pushed the pr/aditighag/fix-ctmap-race branch 2 times, most recently from 0373c4d to 7f198b3 Compare May 5, 2025 21:50
@aditighag
Copy link
Member Author

/test

@aditighag
Copy link
Member Author

I see other functions that call m.Delete, e.g. doFlush4/6, which are passed as a callback to DumpReliablyWithCallback. Shouldn't those call m.DeleteLocked instead?

As a nit, there is a typo in the second commit message, referring to nat as "nap".

Thanks, fixed. I also added a unit test for the doFlush{4,6} functions.

@aditighag
Copy link
Member Author

/test

@rgo3
Copy link
Contributor

rgo3 commented May 7, 2025

ci-e2e-upgrade shows a failure/flake when deleting CT entries on the first run. Is that an existing flake or are we potentially creating a new one here?

@aditighag
Copy link
Member Author

ci-e2e-upgrade shows a failure/flake when deleting CT entries on the first run. Is that an existing flake or are we potentially creating a new one here?

It's similar to this one - #38498. @tommyp1ckles We could have similar error reports during ct flush operation as LRU might've kicked some keys.

@tommyp1ckles
Copy link
Contributor

@aditighag @rgo3 The ctmap flush command uses the same underlying code (i.e. doGCForFamily) as the general GC. So that should be captured by the same recent fix: https://github.com/cilium/cilium/blob/main/pkg/maps/ctmap/ctmap.go#L462

aditighag added 3 commits May 9, 2025 15:41
Add a Delete method that can be called
with the map lock acquired. This allows
synchronizing access to the map attributes
in DumpReliablyWithCallback where the callback
invokes map key delete operation.

Signed-off-by: Aditi Ghag <aditi@cilium.io>
PurgeOrphanNATEntries previously iterated the nat map
via DumpReliablyWithCallback, and provided a callback
function that also deleted entries in the nat map.
The previous commit synchronized access to the Map
construct by acquiring the Map lock, and would
lead to a deadlock in PurgeOrphanNATEntries.
Hence, move the orphan entries deletion logic outside
the nat map iteration.

Signed-off-by: Aditi Ghag <aditi@cilium.io>
The method previously accessed the map construct directly, which
could result in race conditions with other operations on the map,
such as in the `Close` method.

One such data race was reported in the ctmap, where the map was closed
by a periodically running controller while it was simultaneously
accessed in `DumpReliablyWithCallback` -
Currently, callers can invoke map operations in the callback
that acquire the map (write) lock. To allow such callbacks
without causing a deadlock, acquire the (write) lock instead
of RLock.

(snippet)

```
2025-01-30T21:27:22.005325276Z Read at 0x00c0099535a8 by goroutine 6096710:
2025-01-30T21:27:22.005373476Z   github.com/cilium/ebpf/internal/sys.(*FD).Uint()
2025-01-30T21:27:22.005379677Z       /go/src/github.com/cilium/cilium/vendor/github.com/cilium/ebpf/internal/sys/fd.go:71 +0x144
2025-01-30T21:27:22.005446912Z   github.com/cilium/ebpf.(*Map).nextKey()
2025-01-30T21:27:22.005454006Z       /go/src/github.com/cilium/cilium/vendor/github.com/cilium/ebpf/map.go:993 +0x112
2025-01-30T21:27:22.005553101Z   github.com/cilium/ebpf.(*Map).NextKey()
2025-01-30T21:27:22.005560745Z       /go/src/github.com/cilium/cilium/vendor/github.com/cilium/ebpf/map.go:950 +0xae
2025-01-30T21:27:22.005640643Z   github.com/cilium/cilium/pkg/bpf.(*Map).NextKey()
2025-01-30T21:27:22.005647146Z       /go/src/github.com/cilium/cilium/pkg/bpf/map_linux.go:606 +0x11e
2025-01-30T21:27:22.005712027Z   github.com/cilium/cilium/pkg/bpf.(*Map).DumpReliablyWithCallback()
2025-01-30T21:27:22.005718629Z       /go/src/github.com/cilium/cilium/pkg/bpf/map_linux.go:768 +0x71b
2025-01-30T21:27:22.005815760Z   github.com/cilium/cilium/pkg/bpf.(*Map).GetModel()
2025-01-30T21:27:22.005822322Z       /go/src/github.com/cilium/cilium/pkg/bpf/map_linux.go:1413 +0x511
2025-01-30T21:27:22.005880481Z   github.com/cilium/cilium/pkg/bpf.GetOpenMaps()
2025-01-30T21:27:22.005886152Z       /go/src/github.com/cilium/cilium/pkg/bpf/map_register_linux.go:64 +0x2ad
2025-01-30T21:27:22.006024930Z   github.com/cilium/cilium/pkg/maps.(*getMapHandler).Handle()
2025-01-30T21:27:22.006034067Z       /go/src/github.com/cilium/cilium/pkg/maps/api.go:146 +0x24

```

```
2025-01-30T21:27:22.006410985Z Previous write at 0x00c0099535a8 by goroutine 4182:
2025-01-30T21:27:22.006418068Z   github.com/cilium/ebpf/internal/sys.(*FD).Disown()
2025-01-30T21:27:22.006423969Z       /go/src/github.com/cilium/cilium/vendor/github.com/cilium/ebpf/internal/sys/fd.go:93 +0x8e
2025-01-30T21:27:22.006429549Z   github.com/cilium/ebpf/internal/sys.(*FD).Close()
2025-01-30T21:27:22.006435180Z       /go/src/github.com/cilium/cilium/vendor/github.com/cilium/ebpf/internal/sys/fd.go:84 +0x47
2025-01-30T21:27:22.006870411Z   github.com/cilium/ebpf.(*Map).Close()
2025-01-30T21:27:22.006879989Z       /go/src/github.com/cilium/cilium/vendor/github.com/cilium/ebpf/map.go:1371 +0x1e6
2025-01-30T21:27:22.006884858Z   github.com/cilium/cilium/pkg/bpf.(*Map).Close()
2025-01-30T21:27:22.006890338Z       /go/src/github.com/cilium/cilium/pkg/bpf/map_linux.go:591 +0x1ac
2025-01-30T21:27:22.006895778Z   github.com/cilium/cilium/pkg/maps/ctmap.CalculateCTMapPressure.func1.deferwrap1()
2025-01-30T21:27:22.006901959Z       /go/src/github.com/cilium/cilium/pkg/maps/ctmap/ctmap.go:858 +0x33
2025-01-30T21:27:22.006907119Z   runtime.deferreturn()
2025-01-30T21:27:22.006957073Z       /usr/local/go/src/runtime/panic.go:605 +0x5d
2025-01-30T21:27:22.006962683Z   github.com/cilium/cilium/pkg/controller.(*controller).runController()
2025-01-30T21:27:22.007064754Z       /go/src/github.com/cilium/cilium/pkg/controller/controller.go:251 +0xa2
2025-01-30T21:27:22.007072437Z   github.com/cilium/cilium/pkg/controller.(*Manager).createControllerLocked.gowrap1()
2025-01-30T21:27:22.007077677Z       /go/src/github.com/cilium/cilium/pkg/controller/manager.go:111 +0xbc
```

Consequently, call DeleteLocked in callbacks passed to
DumpReliablyWithCallback.

Signed-off-by: Aditi Ghag <aditi@cilium.io>
@aditighag aditighag force-pushed the pr/aditighag/fix-ctmap-race branch from 1b0d99f to 26b4ba1 Compare May 9, 2025 22:41
@aditighag aditighag requested a review from tommyp1ckles May 9, 2025 22:41
@aditighag
Copy link
Member Author

/test

@aditighag aditighag added this pull request to the merge queue May 12, 2025
Merged via the queue into cilium:main with commit bfba0eb May 12, 2025
68 checks passed
@aditighag aditighag deleted the pr/aditighag/fix-ctmap-race branch May 12, 2025 14:29
@julianwiedmann
Copy link
Member

@aditighag given this is release-note/bug, should the fix also go back into v1.17? Or is the severity low enough that we can skip the backport?

@aditighag aditighag added needs-backport/1.17 This PR / issue needs backporting to the v1.17 branch backport/1.17 This PR represents a backport for Cilium 1.17.x of a PR that was merged to main. and removed backport/1.17 This PR represents a backport for Cilium 1.17.x of a PR that was merged to main. labels Jun 10, 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.17 The backport for Cilium 1.17.x for this PR is done. and removed backport-pending/1.17 The backport for Cilium 1.17.x for this PR is in progress. labels Jun 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/datapath Impacts bpf/ or low-level forwarding details, including map management and monitor messages. backport-done/1.17 The backport for Cilium 1.17.x for this PR is done. 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.

Concurrent access of CT map might lead to early closure of CT map while doing GC?
5 participants