flow.go 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940
  1. package nebula
  2. import (
  3. "log/slog"
  4. "runtime"
  5. "github.com/slackhq/nebula/config"
  6. )
  7. // Staged receive (tun.staged.workers) moves decryption off each udp listener onto worker goroutines, behind which an
  8. // ordered writer commits every batch in arrival order. It reuses the inline packet handlers: staging changes ownership
  9. // and scheduling, not policy. Each routine has its own workers and writer, so order is per routine. Full queues block
  10. // the listener. A read error drains the batches in flight, while shutdown waits for the workers and then drops what
  11. // is left. Each routine keeps six batches; at listen.batch=64 with GRO their buffers take about 24 MiB per routine.
  12. //
  13. // Metrics are registered only for active pipelines. flow.rx.batches counts batches handed to the writer and
  14. // flow.rx.inline those an idle listener handled itself; their rates show whether staging is used.
  15. // stagedConfig is tun.staged. workers is per routine; zero keeps receive inline.
  16. type stagedConfig struct {
  17. workers int
  18. // inlineBelow is the packet count below which an idle listener skips the worker handoff
  19. inlineBelow int
  20. }
  21. // parseStagedConfig enables staging on Linux only; conns that cannot hand off batches also stay inline.
  22. func parseStagedConfig(c *config.C, l *slog.Logger) stagedConfig {
  23. sc := stagedConfig{workers: c.GetInt("tun.staged.workers", 0)}
  24. if sc.workers <= 0 {
  25. return stagedConfig{}
  26. }
  27. if runtime.GOOS != "linux" {
  28. l.Warn("tun.staged is only supported on Linux; packet processing stays inline")
  29. return stagedConfig{}
  30. }
  31. // 256 is the measured crossover
  32. sc.inlineBelow = 256
  33. l.Info("Staged receive processing enabled", "workers", sc.workers)
  34. return sc
  35. }