cache.go 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. package firewall
  2. import (
  3. "context"
  4. "log/slog"
  5. "sync/atomic"
  6. "time"
  7. "github.com/slackhq/nebula/logging"
  8. )
  9. // ConntrackCache is used as a local routine cache to know if a given flow
  10. // has been seen in the conntrack table. Keyed on PacketKey (dense form)
  11. // rather than Packet so the lookup hashes raw bytes instead of the
  12. // unique.Handle each netip.Addr in Packet carries.
  13. type ConntrackCache map[PacketKey]struct{}
  14. type ConntrackCacheTicker struct {
  15. cacheV uint64
  16. cacheTick atomic.Uint64
  17. l *slog.Logger
  18. cache ConntrackCache
  19. }
  20. func NewConntrackCacheTicker(ctx context.Context, l *slog.Logger, d time.Duration) *ConntrackCacheTicker {
  21. if d == 0 {
  22. return nil
  23. }
  24. c := &ConntrackCacheTicker{
  25. l: l,
  26. cache: ConntrackCache{},
  27. }
  28. go c.tick(ctx, d)
  29. return c
  30. }
  31. func (c *ConntrackCacheTicker) tick(ctx context.Context, d time.Duration) {
  32. t := time.NewTicker(d)
  33. defer t.Stop()
  34. for {
  35. select {
  36. case <-ctx.Done():
  37. return
  38. case <-t.C:
  39. c.cacheTick.Add(1)
  40. }
  41. }
  42. }
  43. // Get checks if the cache ticker has moved to the next version before returning
  44. // the map. If it has moved, we reset the map.
  45. func (c *ConntrackCacheTicker) Get() ConntrackCache {
  46. if c == nil {
  47. return nil
  48. }
  49. if tick := c.cacheTick.Load(); tick != c.cacheV {
  50. c.cacheV = tick
  51. if ll := len(c.cache); ll > 0 {
  52. if c.l.Enabled(context.Background(), logging.LevelTrace) {
  53. c.l.Log(context.Background(), logging.LevelTrace, "resetting conntrack cache", "len", ll)
  54. }
  55. c.cache = make(ConntrackCache, ll)
  56. }
  57. }
  58. return c.cache
  59. }