wireguard_tun_linux.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. //go:build linux && !android && !e2e_testing
  2. package overlay
  3. import (
  4. "fmt"
  5. "sync"
  6. wgtun "github.com/slackhq/nebula/wgstack/tun"
  7. )
  8. type wireguardTunIO struct {
  9. dev wgtun.Device
  10. mtu int
  11. batchSize int
  12. readMu sync.Mutex
  13. readBufs [][]byte
  14. readLens []int
  15. pending [][]byte
  16. pendIdx int
  17. writeMu sync.Mutex
  18. writeBuf []byte
  19. writeWrap [][]byte
  20. }
  21. func newWireguardTunIO(dev wgtun.Device, mtu int) *wireguardTunIO {
  22. batch := dev.BatchSize()
  23. if batch <= 0 {
  24. batch = 1
  25. }
  26. if mtu <= 0 {
  27. mtu = DefaultMTU
  28. }
  29. bufs := make([][]byte, batch)
  30. for i := range bufs {
  31. bufs[i] = make([]byte, wgtun.VirtioNetHdrLen+mtu)
  32. }
  33. return &wireguardTunIO{
  34. dev: dev,
  35. mtu: mtu,
  36. batchSize: batch,
  37. readBufs: bufs,
  38. readLens: make([]int, batch),
  39. pending: make([][]byte, 0, batch),
  40. writeBuf: make([]byte, wgtun.VirtioNetHdrLen+mtu),
  41. writeWrap: make([][]byte, 1),
  42. }
  43. }
  44. func (w *wireguardTunIO) Read(p []byte) (int, error) {
  45. w.readMu.Lock()
  46. defer w.readMu.Unlock()
  47. for {
  48. if w.pendIdx < len(w.pending) {
  49. segment := w.pending[w.pendIdx]
  50. w.pendIdx++
  51. n := copy(p, segment)
  52. return n, nil
  53. }
  54. n, err := w.dev.Read(w.readBufs, w.readLens, wgtun.VirtioNetHdrLen)
  55. if err != nil {
  56. return 0, err
  57. }
  58. w.pending = w.pending[:0]
  59. w.pendIdx = 0
  60. for i := 0; i < n; i++ {
  61. length := w.readLens[i]
  62. if length == 0 {
  63. continue
  64. }
  65. segment := w.readBufs[i][wgtun.VirtioNetHdrLen : wgtun.VirtioNetHdrLen+length]
  66. w.pending = append(w.pending, segment)
  67. }
  68. }
  69. }
  70. func (w *wireguardTunIO) Write(p []byte) (int, error) {
  71. if len(p) > w.mtu {
  72. return 0, fmt.Errorf("wireguard tun: payload exceeds MTU (%d > %d)", len(p), w.mtu)
  73. }
  74. w.writeMu.Lock()
  75. defer w.writeMu.Unlock()
  76. buf := w.writeBuf[:wgtun.VirtioNetHdrLen+len(p)]
  77. for i := 0; i < wgtun.VirtioNetHdrLen; i++ {
  78. buf[i] = 0
  79. }
  80. copy(buf[wgtun.VirtioNetHdrLen:], p)
  81. w.writeWrap[0] = buf
  82. n, err := w.dev.Write(w.writeWrap, wgtun.VirtioNetHdrLen)
  83. if err != nil {
  84. return n, err
  85. }
  86. return len(p), nil
  87. }
  88. func (w *wireguardTunIO) Close() error {
  89. return nil
  90. }