tio_poll_linux.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package tio
  2. import (
  3. "fmt"
  4. "os"
  5. "sync/atomic"
  6. "golang.org/x/sys/unix"
  7. )
  8. // Maximum size we accept for a single read from a TUN with IFF_VNET_HDR. A
  9. // TSO superpacket can be up to 64KiB of payload plus a single L2/L3/L4 header
  10. // prefix plus the virtio header.
  11. const tunReadBufSize = 65535
  12. type Poll struct {
  13. fd int
  14. readPoll [2]unix.PollFd
  15. writePoll [2]unix.PollFd
  16. closed atomic.Bool
  17. readBuf []byte
  18. batchRet [1]Packet
  19. }
  20. func newPoll(fd int, shutdownFd int) (*Poll, error) {
  21. if err := unix.SetNonblock(fd, true); err != nil {
  22. _ = unix.Close(fd)
  23. return nil, fmt.Errorf("failed to set Poll device as nonblocking: %w", err)
  24. }
  25. out := &Poll{
  26. fd: fd,
  27. readBuf: make([]byte, tunReadBufSize),
  28. readPoll: [2]unix.PollFd{
  29. {Fd: int32(fd), Events: unix.POLLIN},
  30. {Fd: int32(shutdownFd), Events: unix.POLLIN},
  31. },
  32. writePoll: [2]unix.PollFd{
  33. {Fd: int32(fd), Events: unix.POLLOUT},
  34. {Fd: int32(shutdownFd), Events: unix.POLLIN},
  35. },
  36. }
  37. return out, nil
  38. }
  39. // blockOnRead waits until the Poll fd is readable or shutdown has been signaled.
  40. // Returns os.ErrClosed if Close was called.
  41. func (t *Poll) blockOnRead() error {
  42. const problemFlags = unix.POLLHUP | unix.POLLNVAL | unix.POLLERR
  43. var err error
  44. for {
  45. _, err = unix.Poll(t.readPoll[:], -1)
  46. if err != unix.EINTR {
  47. break
  48. }
  49. }
  50. tunEvents := t.readPoll[0].Revents
  51. shutdownEvents := t.readPoll[1].Revents
  52. t.readPoll[0].Revents = 0
  53. t.readPoll[1].Revents = 0
  54. if err != nil {
  55. return err
  56. }
  57. if shutdownEvents&(unix.POLLIN|problemFlags) != 0 {
  58. return os.ErrClosed
  59. }
  60. if tunEvents&problemFlags != 0 {
  61. return os.ErrClosed
  62. }
  63. return nil
  64. }
  65. func (t *Poll) blockOnWrite() error {
  66. const problemFlags = unix.POLLHUP | unix.POLLNVAL | unix.POLLERR
  67. var err error
  68. for {
  69. _, err = unix.Poll(t.writePoll[:], -1)
  70. if err != unix.EINTR {
  71. break
  72. }
  73. }
  74. tunEvents := t.writePoll[0].Revents
  75. shutdownEvents := t.writePoll[1].Revents
  76. t.writePoll[0].Revents = 0
  77. t.writePoll[1].Revents = 0
  78. if err != nil {
  79. return err
  80. }
  81. if shutdownEvents&(unix.POLLIN|problemFlags) != 0 {
  82. return os.ErrClosed
  83. }
  84. if tunEvents&problemFlags != 0 {
  85. return os.ErrClosed
  86. }
  87. return nil
  88. }
  89. func (t *Poll) Read() ([]Packet, error) {
  90. n, err := t.readOne(t.readBuf)
  91. if err != nil {
  92. return nil, err
  93. }
  94. t.batchRet[0] = Packet{Bytes: t.readBuf[:n]}
  95. return t.batchRet[:], nil
  96. }
  97. func (t *Poll) readOne(to []byte) (int, error) {
  98. for {
  99. n, errno := unix.Read(t.fd, to)
  100. if errno == nil {
  101. return n, nil
  102. }
  103. switch errno {
  104. case unix.EAGAIN:
  105. if err := t.blockOnRead(); err != nil {
  106. return 0, err
  107. }
  108. case unix.EINTR:
  109. // retry
  110. case unix.EBADF:
  111. return 0, os.ErrClosed
  112. default:
  113. return 0, errno
  114. }
  115. }
  116. }
  117. // Write is only valid for single threaded use
  118. func (t *Poll) Write(from []byte) (int, error) {
  119. for {
  120. n, errno := unix.Write(t.fd, from)
  121. if errno == nil {
  122. return n, nil
  123. }
  124. switch errno {
  125. case unix.EAGAIN:
  126. if err := t.blockOnWrite(); err != nil {
  127. return 0, err
  128. }
  129. case unix.EINTR:
  130. // retry
  131. case unix.EBADF:
  132. return 0, os.ErrClosed
  133. default:
  134. return 0, errno
  135. }
  136. }
  137. }
  138. func (t *Poll) Close() error {
  139. if t.closed.Swap(true) {
  140. return nil
  141. }
  142. //shutdownFd is owned by the container, so we should not close it
  143. var err error
  144. if t.fd >= 0 {
  145. err = unix.Close(t.fd)
  146. t.fd = -1
  147. }
  148. return err
  149. }