cache.go 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  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.
  11. type ConntrackCache map[Packet]struct{}
  12. type ConntrackCacheTicker struct {
  13. cacheV uint64
  14. cacheTick atomic.Uint64
  15. l *slog.Logger
  16. cache ConntrackCache
  17. }
  18. func NewConntrackCacheTicker(ctx context.Context, l *slog.Logger, d time.Duration) *ConntrackCacheTicker {
  19. if d == 0 {
  20. return nil
  21. }
  22. c := &ConntrackCacheTicker{
  23. l: l,
  24. cache: ConntrackCache{},
  25. }
  26. go c.tick(ctx, d)
  27. return c
  28. }
  29. func (c *ConntrackCacheTicker) tick(ctx context.Context, d time.Duration) {
  30. t := time.NewTicker(d)
  31. defer t.Stop()
  32. for {
  33. select {
  34. case <-ctx.Done():
  35. return
  36. case <-t.C:
  37. c.cacheTick.Add(1)
  38. }
  39. }
  40. }
  41. // Get checks if the cache ticker has moved to the next version before returning
  42. // the map. If it has moved, we reset the map.
  43. func (c *ConntrackCacheTicker) Get() ConntrackCache {
  44. if c == nil {
  45. return nil
  46. }
  47. if tick := c.cacheTick.Load(); tick != c.cacheV {
  48. c.cacheV = tick
  49. if ll := len(c.cache); ll > 0 {
  50. if c.l.Enabled(context.Background(), logging.LevelTrace) {
  51. c.l.Log(context.Background(), logging.LevelTrace, "resetting conntrack cache", "len", ll)
  52. }
  53. c.cache = make(ConntrackCache, ll)
  54. }
  55. }
  56. return c.cache
  57. }