udp_linux.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. //go:build !android && !e2e_testing
  2. // +build !android,!e2e_testing
  3. package udp
  4. import (
  5. "context"
  6. "encoding/binary"
  7. "fmt"
  8. "log/slog"
  9. "net"
  10. "net/netip"
  11. "syscall"
  12. "unsafe"
  13. "github.com/rcrowley/go-metrics"
  14. "github.com/slackhq/nebula/config"
  15. "golang.org/x/sys/unix"
  16. )
  17. type StdConn struct {
  18. udpConn *net.UDPConn
  19. rawConn syscall.RawConn
  20. isV4 bool
  21. l *slog.Logger
  22. batch int
  23. // sendmmsg scratch. Each queue has its own StdConn, so no locking is
  24. // needed. Sized to MaxWriteBatch at construction; WriteBatch chunks
  25. // larger inputs.
  26. writeMsgs []rawMessage
  27. writeIovs []iovec
  28. writeNames [][]byte
  29. // sendmmsg(2) callback state. sendmmsgCB is bound once in NewListener
  30. // to the sendmmsgRun method value so passing it to rawConn.Write does
  31. // not allocate a fresh closure per send; sendmmsgN/Sent/Errno carry
  32. // the inputs and outputs across the call without escaping locals.
  33. sendmmsgCB func(fd uintptr) bool
  34. sendmmsgN int
  35. sendmmsgSent int
  36. sendmmsgErrno syscall.Errno
  37. }
  38. func setReusePort(network, address string, c syscall.RawConn) error {
  39. var opErr error
  40. err := c.Control(func(fd uintptr) {
  41. opErr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
  42. //CloseOnExec already set by the runtime
  43. })
  44. if err != nil {
  45. return err
  46. }
  47. return opErr
  48. }
  49. func NewListener(l *slog.Logger, ip netip.Addr, port int, multi bool, batch int) (Conn, error) {
  50. listen := netip.AddrPortFrom(ip, uint16(port))
  51. lc := net.ListenConfig{}
  52. if multi {
  53. lc.Control = setReusePort
  54. }
  55. //this context is only used during the bind operation, you can't cancel it to kill the socket
  56. pc, err := lc.ListenPacket(context.Background(), "udp", listen.String())
  57. if err != nil {
  58. return nil, fmt.Errorf("unable to open socket: %s", err)
  59. }
  60. udpConn := pc.(*net.UDPConn)
  61. rawConn, err := udpConn.SyscallConn()
  62. if err != nil {
  63. _ = udpConn.Close()
  64. return nil, err
  65. }
  66. //gotta find out if we got an AF_INET6 socket or not:
  67. out := &StdConn{
  68. udpConn: udpConn,
  69. rawConn: rawConn,
  70. l: l,
  71. batch: batch,
  72. }
  73. af, err := out.getSockOptInt(unix.SO_DOMAIN)
  74. if err != nil {
  75. _ = out.Close()
  76. return nil, err
  77. }
  78. out.isV4 = af == unix.AF_INET
  79. out.prepareWriteMessages(MaxWriteBatch)
  80. out.sendmmsgCB = out.sendmmsgRun
  81. return out, nil
  82. }
  83. func (u *StdConn) prepareWriteMessages(n int) {
  84. u.writeMsgs = make([]rawMessage, n)
  85. u.writeIovs = make([]iovec, n)
  86. u.writeNames = make([][]byte, n)
  87. for i := range u.writeMsgs {
  88. u.writeNames[i] = make([]byte, unix.SizeofSockaddrInet6)
  89. u.writeMsgs[i].Hdr.Name = &u.writeNames[i][0]
  90. }
  91. }
  92. func (u *StdConn) SupportsMultipleReaders() bool {
  93. return true
  94. }
  95. func (u *StdConn) Rebind() error {
  96. return nil
  97. }
  98. func (u *StdConn) getSockOptInt(opt int) (int, error) {
  99. if u.rawConn == nil {
  100. return 0, fmt.Errorf("no UDP connection")
  101. }
  102. var out int
  103. var opErr error
  104. err := u.rawConn.Control(func(fd uintptr) {
  105. out, opErr = unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, opt)
  106. })
  107. if err != nil {
  108. return 0, err
  109. }
  110. return out, opErr
  111. }
  112. func (u *StdConn) setSockOptInt(opt int, n int) error {
  113. if u.rawConn == nil {
  114. return fmt.Errorf("no UDP connection")
  115. }
  116. var opErr error
  117. err := u.rawConn.Control(func(fd uintptr) {
  118. opErr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, opt, n)
  119. })
  120. if err != nil {
  121. return err
  122. }
  123. return opErr
  124. }
  125. func (u *StdConn) SetRecvBuffer(n int) error {
  126. return u.setSockOptInt(unix.SO_RCVBUFFORCE, n)
  127. }
  128. func (u *StdConn) SetSendBuffer(n int) error {
  129. return u.setSockOptInt(unix.SO_SNDBUFFORCE, n)
  130. }
  131. func (u *StdConn) SetSoMark(mark int) error {
  132. return u.setSockOptInt(unix.SO_MARK, mark)
  133. }
  134. func (u *StdConn) GetRecvBuffer() (int, error) {
  135. return u.getSockOptInt(unix.SO_RCVBUF)
  136. }
  137. func (u *StdConn) GetSendBuffer() (int, error) {
  138. return u.getSockOptInt(unix.SO_SNDBUF)
  139. }
  140. func (u *StdConn) GetSoMark() (int, error) {
  141. return u.getSockOptInt(unix.SO_MARK)
  142. }
  143. func (u *StdConn) LocalAddr() (netip.AddrPort, error) {
  144. a := u.udpConn.LocalAddr()
  145. switch v := a.(type) {
  146. case *net.UDPAddr:
  147. addr, ok := netip.AddrFromSlice(v.IP)
  148. if !ok {
  149. return netip.AddrPort{}, fmt.Errorf("LocalAddr returned invalid IP address: %s", v.IP)
  150. }
  151. return netip.AddrPortFrom(addr, uint16(v.Port)), nil
  152. default:
  153. return netip.AddrPort{}, fmt.Errorf("LocalAddr returned: %#v", a)
  154. }
  155. }
  156. func recvmmsg(fd uintptr, msgs []rawMessage) (int, bool, error) {
  157. var errno syscall.Errno
  158. n, _, errno := unix.Syscall6(
  159. unix.SYS_RECVMMSG,
  160. fd,
  161. uintptr(unsafe.Pointer(&msgs[0])),
  162. uintptr(len(msgs)),
  163. unix.MSG_WAITFORONE,
  164. 0,
  165. 0,
  166. )
  167. if errno == syscall.EAGAIN || errno == syscall.EWOULDBLOCK {
  168. // No data available, block for I/O and try again.
  169. return int(n), false, nil
  170. }
  171. if errno != 0 {
  172. return int(n), true, &net.OpError{Op: "recvmmsg", Err: errno}
  173. }
  174. return int(n), true, nil
  175. }
  176. func (u *StdConn) listenOutSingle(r EncReader, flush func()) error {
  177. var err error
  178. var n int
  179. var from netip.AddrPort
  180. buffer := make([]byte, MTU)
  181. for {
  182. n, from, err = u.udpConn.ReadFromUDPAddrPort(buffer)
  183. if err != nil {
  184. return err
  185. }
  186. from = netip.AddrPortFrom(from.Addr().Unmap(), from.Port())
  187. // listenOutSingle uses ReadFromUDPAddrPort which discards cmsgs,
  188. // so the outer ECN field is not visible on this path. Zero RxMeta
  189. // (Not-ECT) means RFC 6040 combine is a no-op.
  190. r(from, buffer[:n], RxMeta{})
  191. flush()
  192. }
  193. }
  194. // readSockaddr decodes the source address out of a recvmmsg name buffer
  195. func (u *StdConn) readSockaddr(name []byte) netip.AddrPort {
  196. var ip netip.Addr
  197. // It's ok to skip the ok check here, the slicing is the only error that can occur and it will panic
  198. if u.isV4 {
  199. ip, _ = netip.AddrFromSlice(name[4:8])
  200. } else {
  201. ip, _ = netip.AddrFromSlice(name[8:24])
  202. }
  203. return netip.AddrPortFrom(ip.Unmap(), binary.BigEndian.Uint16(name[2:4]))
  204. }
  205. func (u *StdConn) listenOutBatch(r EncReader, flush func()) error {
  206. var n int
  207. var operr error
  208. bufSize := MTU
  209. cmsgSpace := 0
  210. msgs, buffers, names, _ := u.PrepareRawMessages(u.batch, bufSize, cmsgSpace)
  211. //reader needs to capture variables from this function, since it's used as a lambda with rawConn.Read
  212. //defining it outside the loop so it gets re-used
  213. reader := func(fd uintptr) (done bool) {
  214. n, done, operr = recvmmsg(fd, msgs)
  215. return done
  216. }
  217. for {
  218. err := u.rawConn.Read(reader)
  219. if err != nil {
  220. return err
  221. }
  222. if operr != nil {
  223. return operr
  224. }
  225. for i := 0; i < n; i++ {
  226. r(u.readSockaddr(names[i]), buffers[i][:msgs[i].Len], RxMeta{})
  227. }
  228. flush()
  229. }
  230. }
  231. func (u *StdConn) ListenOut(r EncReader, flush func()) error {
  232. if u.batch == 1 {
  233. return u.listenOutSingle(r, flush)
  234. } else {
  235. return u.listenOutBatch(r, flush)
  236. }
  237. }
  238. func (u *StdConn) WriteTo(b []byte, ip netip.AddrPort) error {
  239. _, err := u.udpConn.WriteToUDPAddrPort(b, ip)
  240. return err
  241. }
  242. // WriteBatch sends bufs via sendmmsg(2) using the preallocated scratch on
  243. // StdConn. If supported, consecutive packets to the same destination with
  244. // matching segment sizes (all but possibly the last) are coalesced into a
  245. // single mmsghdr entry
  246. //
  247. // If sendmmsg returns an error and zero entries went out, we fall back to
  248. // per-packet WriteTo for that chunk so the caller still gets best-effort
  249. // delivery. On a partial send we resume at the first un-acked entry on
  250. // the next iteration.
  251. func (u *StdConn) WriteBatch(bufs [][]byte, addrs []netip.AddrPort, _ []byte) error {
  252. for i := 0; i < len(bufs); {
  253. chunk := min(len(bufs)-i, len(u.writeMsgs))
  254. for k := 0; k < chunk; k++ {
  255. u.writeIovs[k].Base = &bufs[i+k][0]
  256. setIovLen(&u.writeIovs[k], len(bufs[i+k]))
  257. nlen, err := writeSockaddr(u.writeNames[k], addrs[i+k], u.isV4)
  258. if err != nil {
  259. return err
  260. }
  261. hdr := &u.writeMsgs[k].Hdr
  262. hdr.Iov = &u.writeIovs[k]
  263. setMsgIovlen(hdr, 1)
  264. hdr.Namelen = uint32(nlen)
  265. }
  266. sent, serr := u.sendmmsg(chunk)
  267. if serr != nil && sent <= 0 {
  268. // sendmmsg returns -1 / sent=0 when entry 0 itself failed; log
  269. // that entry's destination and fall back to per-packet WriteTo
  270. // for the whole chunk so the caller still gets best-effort
  271. // delivery without duplicating packets the kernel accepted.
  272. u.l.Warn("sendmmsg failed, falling back to per-packet WriteTo",
  273. "err", serr,
  274. "entries", chunk,
  275. "entry0_dst", addrs[i],
  276. "isV4", u.isV4,
  277. )
  278. for k := 0; k < chunk; k++ {
  279. if werr := u.WriteTo(bufs[i+k], addrs[i+k]); werr != nil {
  280. return werr
  281. }
  282. }
  283. i += chunk
  284. continue
  285. }
  286. i += sent
  287. }
  288. return nil
  289. }
  290. // sendmmsg issues sendmmsg(2) against the first n entries of u.writeMsgs.
  291. // The bound u.sendmmsgCB is passed to rawConn.Write so no closure is
  292. // allocated per call; inputs and outputs ride on the StdConn fields.
  293. func (u *StdConn) sendmmsg(n int) (int, error) {
  294. u.sendmmsgN = n
  295. u.sendmmsgSent = 0
  296. u.sendmmsgErrno = 0
  297. if err := u.rawConn.Write(u.sendmmsgCB); err != nil {
  298. return u.sendmmsgSent, err
  299. }
  300. if u.sendmmsgErrno != 0 {
  301. return u.sendmmsgSent, &net.OpError{Op: "sendmmsg", Err: u.sendmmsgErrno}
  302. }
  303. return u.sendmmsgSent, nil
  304. }
  305. // sendmmsgRun is the rawConn.Write callback. It is bound once into
  306. // u.sendmmsgCB at construction so it stays alloc-free in the hot path;
  307. // inputs (sendmmsgN) and outputs (sendmmsgSent, sendmmsgErrno) ride on
  308. // the receiver rather than escaping locals.
  309. func (u *StdConn) sendmmsgRun(fd uintptr) bool {
  310. r1, _, errno := unix.Syscall6(unix.SYS_SENDMMSG, fd,
  311. uintptr(unsafe.Pointer(&u.writeMsgs[0])), uintptr(u.sendmmsgN),
  312. 0, 0, 0,
  313. )
  314. if errno == syscall.EAGAIN || errno == syscall.EWOULDBLOCK {
  315. return false
  316. }
  317. u.sendmmsgSent = int(r1)
  318. u.sendmmsgErrno = errno
  319. return true
  320. }
  321. // writeSockaddr encodes addr into buf (which must be at least
  322. // SizeofSockaddrInet6 bytes). Returns the number of bytes used. If isV4 is
  323. // true and addr is not a v4 (or v4-in-v6) address, returns an error.
  324. func writeSockaddr(buf []byte, addr netip.AddrPort, isV4 bool) (int, error) {
  325. ap := addr.Addr().Unmap()
  326. if isV4 {
  327. if !ap.Is4() {
  328. return 0, ErrInvalidIPv6RemoteForSocket
  329. }
  330. // struct sockaddr_in: { sa_family_t(2), in_port_t(2, BE), in_addr(4), zero(8) }
  331. // sa_family is host endian.
  332. binary.NativeEndian.PutUint16(buf[0:2], unix.AF_INET)
  333. binary.BigEndian.PutUint16(buf[2:4], addr.Port())
  334. ip4 := ap.As4()
  335. copy(buf[4:8], ip4[:])
  336. clear(buf[8:16])
  337. return unix.SizeofSockaddrInet4, nil
  338. }
  339. // struct sockaddr_in6: { sa_family_t(2), in_port_t(2, BE), flowinfo(4), in6_addr(16), scope_id(4) }
  340. binary.NativeEndian.PutUint16(buf[0:2], unix.AF_INET6)
  341. binary.BigEndian.PutUint16(buf[2:4], addr.Port())
  342. binary.NativeEndian.PutUint32(buf[4:8], 0)
  343. ip6 := addr.Addr().As16()
  344. copy(buf[8:24], ip6[:])
  345. binary.NativeEndian.PutUint32(buf[24:28], 0)
  346. return unix.SizeofSockaddrInet6, nil
  347. }
  348. func (u *StdConn) ReloadConfig(c *config.C) {
  349. b := c.GetInt("listen.read_buffer", 0)
  350. if b > 0 {
  351. err := u.SetRecvBuffer(b)
  352. if err == nil {
  353. s, err := u.GetRecvBuffer()
  354. if err == nil {
  355. u.l.Info("listen.read_buffer was set", "size", s)
  356. } else {
  357. u.l.Warn("Failed to get listen.read_buffer", "error", err)
  358. }
  359. } else {
  360. u.l.Error("Failed to set listen.read_buffer", "error", err)
  361. }
  362. }
  363. b = c.GetInt("listen.write_buffer", 0)
  364. if b > 0 {
  365. err := u.SetSendBuffer(b)
  366. if err == nil {
  367. s, err := u.GetSendBuffer()
  368. if err == nil {
  369. u.l.Info("listen.write_buffer was set", "size", s)
  370. } else {
  371. u.l.Warn("Failed to get listen.write_buffer", "error", err)
  372. }
  373. } else {
  374. u.l.Error("Failed to set listen.write_buffer", "error", err)
  375. }
  376. }
  377. b = c.GetInt("listen.so_mark", 0)
  378. s, err := u.GetSoMark()
  379. if b > 0 || (err == nil && s != 0) {
  380. err := u.SetSoMark(b)
  381. if err == nil {
  382. s, err := u.GetSoMark()
  383. if err == nil {
  384. u.l.Info("listen.so_mark was set", "mark", s)
  385. } else {
  386. u.l.Warn("Failed to get listen.so_mark", "error", err)
  387. }
  388. } else {
  389. u.l.Error("Failed to set listen.so_mark", "error", err)
  390. }
  391. }
  392. }
  393. func (u *StdConn) getMemInfo(meminfo *[unix.SK_MEMINFO_VARS]uint32) error {
  394. var vallen uint32 = 4 * unix.SK_MEMINFO_VARS
  395. if u.rawConn == nil {
  396. return fmt.Errorf("no UDP connection")
  397. }
  398. var opErr error
  399. err := u.rawConn.Control(func(fd uintptr) {
  400. _, _, syserr := unix.Syscall6(unix.SYS_GETSOCKOPT, fd, uintptr(unix.SOL_SOCKET), uintptr(unix.SO_MEMINFO), uintptr(unsafe.Pointer(meminfo)), uintptr(unsafe.Pointer(&vallen)), 0)
  401. if syserr != 0 {
  402. opErr = syserr
  403. }
  404. })
  405. if err != nil {
  406. return err
  407. }
  408. return opErr
  409. }
  410. func (u *StdConn) Close() error {
  411. if u.udpConn != nil {
  412. return u.udpConn.Close()
  413. }
  414. return nil
  415. }
  416. func NewUDPStatsEmitter(udpConns []Conn) func() {
  417. // Check if our kernel supports SO_MEMINFO before registering the gauges
  418. var udpGauges [][unix.SK_MEMINFO_VARS]metrics.Gauge
  419. var meminfo [unix.SK_MEMINFO_VARS]uint32
  420. if err := udpConns[0].(*StdConn).getMemInfo(&meminfo); err == nil {
  421. udpGauges = make([][unix.SK_MEMINFO_VARS]metrics.Gauge, len(udpConns))
  422. for i := range udpConns {
  423. udpGauges[i] = [unix.SK_MEMINFO_VARS]metrics.Gauge{
  424. metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.rmem_alloc", i), nil),
  425. metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.rcvbuf", i), nil),
  426. metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.wmem_alloc", i), nil),
  427. metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.sndbuf", i), nil),
  428. metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.fwd_alloc", i), nil),
  429. metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.wmem_queued", i), nil),
  430. metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.optmem", i), nil),
  431. metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.backlog", i), nil),
  432. metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.drops", i), nil),
  433. }
  434. }
  435. }
  436. return func() {
  437. for i, gauges := range udpGauges {
  438. if err := udpConns[i].(*StdConn).getMemInfo(&meminfo); err == nil {
  439. for j := 0; j < unix.SK_MEMINFO_VARS; j++ {
  440. gauges[j].Update(int64(meminfo[j]))
  441. }
  442. }
  443. }
  444. }
  445. }