2021-10-21 15:24:11 -06:00
|
|
|
//go:build !android && !e2e_testing
|
|
|
|
// +build !android,!e2e_testing
|
2020-06-30 12:48:58 -06:00
|
|
|
|
2021-11-03 19:54:04 -06:00
|
|
|
package udp
|
2019-11-19 10:00:20 -07:00
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"syscall"
|
|
|
|
"unsafe"
|
|
|
|
|
2021-03-01 17:51:33 -07:00
|
|
|
"github.com/rcrowley/go-metrics"
|
2021-03-26 08:46:30 -06:00
|
|
|
"github.com/sirupsen/logrus"
|
2021-11-03 19:54:04 -06:00
|
|
|
"github.com/slackhq/nebula/config"
|
|
|
|
"github.com/slackhq/nebula/firewall"
|
|
|
|
"github.com/slackhq/nebula/header"
|
2019-11-19 10:00:20 -07:00
|
|
|
"golang.org/x/sys/unix"
|
|
|
|
)
|
|
|
|
|
|
|
|
//TODO: make it support reload as best you can!
|
|
|
|
|
2023-06-14 09:48:52 -06:00
|
|
|
type StdConn struct {
|
2019-11-19 10:00:20 -07:00
|
|
|
sysFd int
|
2024-01-30 13:08:14 -07:00
|
|
|
isV4 bool
|
2021-03-26 08:46:30 -06:00
|
|
|
l *logrus.Logger
|
2021-11-03 19:54:04 -06:00
|
|
|
batch int
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
var x int
|
|
|
|
|
2021-03-01 17:51:33 -07:00
|
|
|
// From linux/sock_diag.h
|
|
|
|
const (
|
|
|
|
_SK_MEMINFO_RMEM_ALLOC = iota
|
|
|
|
_SK_MEMINFO_RCVBUF
|
|
|
|
_SK_MEMINFO_WMEM_ALLOC
|
|
|
|
_SK_MEMINFO_SNDBUF
|
|
|
|
_SK_MEMINFO_FWD_ALLOC
|
|
|
|
_SK_MEMINFO_WMEM_QUEUED
|
|
|
|
_SK_MEMINFO_OPTMEM
|
|
|
|
_SK_MEMINFO_BACKLOG
|
|
|
|
_SK_MEMINFO_DROPS
|
|
|
|
|
|
|
|
_SK_MEMINFO_VARS
|
|
|
|
)
|
|
|
|
|
|
|
|
type _SK_MEMINFO [_SK_MEMINFO_VARS]uint32
|
|
|
|
|
2024-01-30 13:08:14 -07:00
|
|
|
func maybeIPV4(ip net.IP) (net.IP, bool) {
|
|
|
|
ip4 := ip.To4()
|
|
|
|
if ip4 != nil {
|
|
|
|
return ip4, true
|
|
|
|
}
|
|
|
|
return ip, false
|
|
|
|
}
|
|
|
|
|
2023-06-14 09:48:52 -06:00
|
|
|
func NewListener(l *logrus.Logger, ip net.IP, port int, multi bool, batch int) (Conn, error) {
|
2024-01-30 13:08:14 -07:00
|
|
|
ipV4, isV4 := maybeIPV4(ip)
|
|
|
|
af := unix.AF_INET6
|
|
|
|
if isV4 {
|
|
|
|
af = unix.AF_INET
|
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
syscall.ForkLock.RLock()
|
2024-01-30 13:08:14 -07:00
|
|
|
fd, err := unix.Socket(af, unix.SOCK_DGRAM, unix.IPPROTO_UDP)
|
2019-11-19 10:00:20 -07:00
|
|
|
if err == nil {
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
unix.CloseOnExec(fd)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
syscall.ForkLock.RUnlock()
|
|
|
|
|
|
|
|
if err != nil {
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
unix.Close(fd)
|
2019-11-22 16:22:31 -07:00
|
|
|
return nil, fmt.Errorf("unable to open socket: %s", err)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2020-08-12 16:24:05 -06:00
|
|
|
if multi {
|
|
|
|
if err = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {
|
|
|
|
return nil, fmt.Errorf("unable to set SO_REUSEPORT: %s", err)
|
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2021-03-18 19:37:24 -06:00
|
|
|
//TODO: support multiple listening IPs (for limiting ipv6)
|
2024-01-30 13:08:14 -07:00
|
|
|
var sa unix.Sockaddr
|
|
|
|
if isV4 {
|
|
|
|
sa4 := &unix.SockaddrInet4{Port: port}
|
|
|
|
copy(sa4.Addr[:], ipV4)
|
|
|
|
sa = sa4
|
|
|
|
} else {
|
|
|
|
sa6 := &unix.SockaddrInet6{Port: port}
|
|
|
|
copy(sa6.Addr[:], ip.To16())
|
|
|
|
sa = sa6
|
|
|
|
}
|
|
|
|
if err = unix.Bind(fd, sa); err != nil {
|
2019-11-22 16:22:31 -07:00
|
|
|
return nil, fmt.Errorf("unable to bind to socket: %s", err)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//TODO: this may be useful for forcing threads into specific cores
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
//unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_INCOMING_CPU, x)
|
|
|
|
//v, err := unix.GetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_INCOMING_CPU)
|
2019-11-19 10:00:20 -07:00
|
|
|
//l.Println(v, err)
|
|
|
|
|
2024-01-30 13:08:14 -07:00
|
|
|
return &StdConn{sysFd: fd, isV4: isV4, l: l, batch: batch}, err
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2023-06-14 09:48:52 -06:00
|
|
|
func (u *StdConn) Rebind() error {
|
2020-09-18 08:20:09 -06:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-06-14 09:48:52 -06:00
|
|
|
func (u *StdConn) SetRecvBuffer(n int) error {
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
return unix.SetsockoptInt(u.sysFd, unix.SOL_SOCKET, unix.SO_RCVBUFFORCE, n)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2023-06-14 09:48:52 -06:00
|
|
|
func (u *StdConn) SetSendBuffer(n int) error {
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
return unix.SetsockoptInt(u.sysFd, unix.SOL_SOCKET, unix.SO_SNDBUFFORCE, n)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2023-06-14 09:48:52 -06:00
|
|
|
func (u *StdConn) GetRecvBuffer() (int, error) {
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
return unix.GetsockoptInt(int(u.sysFd), unix.SOL_SOCKET, unix.SO_RCVBUF)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2023-06-14 09:48:52 -06:00
|
|
|
func (u *StdConn) GetSendBuffer() (int, error) {
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
return unix.GetsockoptInt(int(u.sysFd), unix.SOL_SOCKET, unix.SO_SNDBUF)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2023-06-14 09:48:52 -06:00
|
|
|
func (u *StdConn) LocalAddr() (*Addr, error) {
|
2021-04-14 12:50:09 -06:00
|
|
|
sa, err := unix.Getsockname(u.sysFd)
|
|
|
|
if err != nil {
|
2019-11-19 10:00:20 -07:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-11-03 19:54:04 -06:00
|
|
|
addr := &Addr{}
|
2021-04-14 12:50:09 -06:00
|
|
|
switch sa := sa.(type) {
|
|
|
|
case *unix.SockaddrInet4:
|
|
|
|
addr.IP = net.IP{sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]}.To16()
|
|
|
|
addr.Port = uint16(sa.Port)
|
|
|
|
case *unix.SockaddrInet6:
|
|
|
|
addr.IP = sa.Addr[0:]
|
|
|
|
addr.Port = uint16(sa.Port)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
2021-03-18 19:37:24 -06:00
|
|
|
|
2019-11-19 10:00:20 -07:00
|
|
|
return addr, nil
|
|
|
|
}
|
|
|
|
|
2023-06-14 09:48:52 -06:00
|
|
|
func (u *StdConn) ListenOut(r EncReader, lhf LightHouseHandlerFunc, cache *firewall.ConntrackCacheTicker, q int) {
|
2021-11-03 19:54:04 -06:00
|
|
|
plaintext := make([]byte, MTU)
|
|
|
|
h := &header.H{}
|
|
|
|
fwPacket := &firewall.Packet{}
|
|
|
|
udpAddr := &Addr{}
|
2019-11-19 10:00:20 -07:00
|
|
|
nb := make([]byte, 12, 12)
|
|
|
|
|
|
|
|
//TODO: should we track this?
|
|
|
|
//metric := metrics.GetOrRegisterHistogram("test.batch_read", nil, metrics.NewExpDecaySample(1028, 0.015))
|
2021-11-03 19:54:04 -06:00
|
|
|
msgs, buffers, names := u.PrepareRawMessages(u.batch)
|
2020-08-12 16:24:05 -06:00
|
|
|
read := u.ReadMulti
|
2021-11-03 19:54:04 -06:00
|
|
|
if u.batch == 1 {
|
2020-08-12 16:24:05 -06:00
|
|
|
read = u.ReadSingle
|
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
|
|
|
|
for {
|
2020-08-12 16:24:05 -06:00
|
|
|
n, err := read(msgs)
|
2019-11-19 10:00:20 -07:00
|
|
|
if err != nil {
|
2023-07-10 11:43:48 -06:00
|
|
|
u.l.WithError(err).Debug("udp socket is closed, exiting read loop")
|
|
|
|
return
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//metric.Update(int64(n))
|
|
|
|
for i := 0; i < n; i++ {
|
2024-01-30 13:08:14 -07:00
|
|
|
if u.isV4 {
|
|
|
|
udpAddr.IP = names[i][4:8]
|
|
|
|
} else {
|
|
|
|
udpAddr.IP = names[i][8:24]
|
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
udpAddr.Port = binary.BigEndian.Uint16(names[i][2:4])
|
2023-04-07 12:28:37 -06:00
|
|
|
r(udpAddr, plaintext[:0], buffers[i][:msgs[i].Len], h, fwPacket, lhf, nb, q, cache.Get(u.l))
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-14 09:48:52 -06:00
|
|
|
func (u *StdConn) ReadSingle(msgs []rawMessage) (int, error) {
|
2019-11-19 10:00:20 -07:00
|
|
|
for {
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
n, _, err := unix.Syscall6(
|
2020-08-12 16:24:05 -06:00
|
|
|
unix.SYS_RECVMSG,
|
2019-11-19 10:00:20 -07:00
|
|
|
uintptr(u.sysFd),
|
2020-08-12 16:24:05 -06:00
|
|
|
uintptr(unsafe.Pointer(&(msgs[0].Hdr))),
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
2019-11-19 10:00:20 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
if err != 0 {
|
2020-08-12 16:24:05 -06:00
|
|
|
return 0, &net.OpError{Op: "recvmsg", Err: err}
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2020-08-12 16:24:05 -06:00
|
|
|
msgs[0].Len = uint32(n)
|
|
|
|
return 1, nil
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-14 09:48:52 -06:00
|
|
|
func (u *StdConn) ReadMulti(msgs []rawMessage) (int, error) {
|
2019-11-19 10:00:20 -07:00
|
|
|
for {
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
n, _, err := unix.Syscall6(
|
|
|
|
unix.SYS_RECVMMSG,
|
2019-11-19 10:00:20 -07:00
|
|
|
uintptr(u.sysFd),
|
|
|
|
uintptr(unsafe.Pointer(&msgs[0])),
|
|
|
|
uintptr(len(msgs)),
|
|
|
|
unix.MSG_WAITFORONE,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
)
|
|
|
|
|
|
|
|
if err != 0 {
|
|
|
|
return 0, &net.OpError{Op: "recvmmsg", Err: err}
|
|
|
|
}
|
|
|
|
|
|
|
|
return int(n), nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-14 09:48:52 -06:00
|
|
|
func (u *StdConn) WriteTo(b []byte, addr *Addr) error {
|
2024-01-30 13:08:14 -07:00
|
|
|
if u.isV4 {
|
|
|
|
return u.writeTo4(b, addr)
|
|
|
|
}
|
|
|
|
return u.writeTo6(b, addr)
|
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2024-01-30 13:08:14 -07:00
|
|
|
func (u *StdConn) writeTo6(b []byte, addr *Addr) error {
|
2021-03-18 19:37:24 -06:00
|
|
|
var rsa unix.RawSockaddrInet6
|
|
|
|
rsa.Family = unix.AF_INET6
|
2024-01-30 13:08:14 -07:00
|
|
|
// Little Endian -> Network Endian
|
|
|
|
rsa.Port = (addr.Port >> 8) | ((addr.Port & 0xff) << 8)
|
|
|
|
copy(rsa.Addr[:], addr.IP.To16())
|
2019-11-19 10:00:20 -07:00
|
|
|
|
|
|
|
for {
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
_, _, err := unix.Syscall6(
|
|
|
|
unix.SYS_SENDTO,
|
2019-11-19 10:00:20 -07:00
|
|
|
uintptr(u.sysFd),
|
|
|
|
uintptr(unsafe.Pointer(&b[0])),
|
|
|
|
uintptr(len(b)),
|
|
|
|
uintptr(0),
|
|
|
|
uintptr(unsafe.Pointer(&rsa)),
|
2021-03-18 19:37:24 -06:00
|
|
|
uintptr(unix.SizeofSockaddrInet6),
|
2019-11-19 10:00:20 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
if err != 0 {
|
|
|
|
return &net.OpError{Op: "sendto", Err: err}
|
|
|
|
}
|
|
|
|
|
|
|
|
//TODO: handle incomplete writes
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-30 13:08:14 -07:00
|
|
|
func (u *StdConn) writeTo4(b []byte, addr *Addr) error {
|
|
|
|
addrV4, isAddrV4 := maybeIPV4(addr.IP)
|
|
|
|
if !isAddrV4 {
|
|
|
|
return fmt.Errorf("Listener is IPv4, but writing to IPv6 remote")
|
|
|
|
}
|
|
|
|
|
|
|
|
var rsa unix.RawSockaddrInet4
|
|
|
|
rsa.Family = unix.AF_INET
|
|
|
|
// Little Endian -> Network Endian
|
|
|
|
rsa.Port = (addr.Port >> 8) | ((addr.Port & 0xff) << 8)
|
|
|
|
copy(rsa.Addr[:], addrV4)
|
|
|
|
|
|
|
|
for {
|
|
|
|
_, _, err := unix.Syscall6(
|
|
|
|
unix.SYS_SENDTO,
|
|
|
|
uintptr(u.sysFd),
|
|
|
|
uintptr(unsafe.Pointer(&b[0])),
|
|
|
|
uintptr(len(b)),
|
|
|
|
uintptr(0),
|
|
|
|
uintptr(unsafe.Pointer(&rsa)),
|
|
|
|
uintptr(unix.SizeofSockaddrInet4),
|
|
|
|
)
|
|
|
|
|
|
|
|
if err != 0 {
|
|
|
|
return &net.OpError{Op: "sendto", Err: err}
|
|
|
|
}
|
|
|
|
|
|
|
|
//TODO: handle incomplete writes
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-14 09:48:52 -06:00
|
|
|
func (u *StdConn) ReloadConfig(c *config.C) {
|
2019-11-19 10:00:20 -07:00
|
|
|
b := c.GetInt("listen.read_buffer", 0)
|
|
|
|
if b > 0 {
|
|
|
|
err := u.SetRecvBuffer(b)
|
|
|
|
if err == nil {
|
|
|
|
s, err := u.GetRecvBuffer()
|
|
|
|
if err == nil {
|
2021-03-26 08:46:30 -06:00
|
|
|
u.l.WithField("size", s).Info("listen.read_buffer was set")
|
2019-11-19 10:00:20 -07:00
|
|
|
} else {
|
2021-03-26 08:46:30 -06:00
|
|
|
u.l.WithError(err).Warn("Failed to get listen.read_buffer")
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
} else {
|
2021-03-26 08:46:30 -06:00
|
|
|
u.l.WithError(err).Error("Failed to set listen.read_buffer")
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
b = c.GetInt("listen.write_buffer", 0)
|
|
|
|
if b > 0 {
|
|
|
|
err := u.SetSendBuffer(b)
|
|
|
|
if err == nil {
|
|
|
|
s, err := u.GetSendBuffer()
|
|
|
|
if err == nil {
|
2021-03-26 08:46:30 -06:00
|
|
|
u.l.WithField("size", s).Info("listen.write_buffer was set")
|
2019-11-19 10:00:20 -07:00
|
|
|
} else {
|
2021-03-26 08:46:30 -06:00
|
|
|
u.l.WithError(err).Warn("Failed to get listen.write_buffer")
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
} else {
|
2021-03-26 08:46:30 -06:00
|
|
|
u.l.WithError(err).Error("Failed to set listen.write_buffer")
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-14 09:48:52 -06:00
|
|
|
func (u *StdConn) getMemInfo(meminfo *_SK_MEMINFO) error {
|
2021-03-01 17:51:33 -07:00
|
|
|
var vallen uint32 = 4 * _SK_MEMINFO_VARS
|
|
|
|
_, _, err := unix.Syscall6(unix.SYS_GETSOCKOPT, uintptr(u.sysFd), uintptr(unix.SOL_SOCKET), uintptr(unix.SO_MEMINFO), uintptr(unsafe.Pointer(meminfo)), uintptr(unsafe.Pointer(&vallen)), 0)
|
|
|
|
if err != 0 {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-07-10 11:43:48 -06:00
|
|
|
func (u *StdConn) Close() error {
|
|
|
|
//TODO: this will not interrupt the read loop
|
|
|
|
return syscall.Close(u.sysFd)
|
|
|
|
}
|
|
|
|
|
2023-06-14 09:48:52 -06:00
|
|
|
func NewUDPStatsEmitter(udpConns []Conn) func() {
|
2021-03-01 17:51:33 -07:00
|
|
|
// Check if our kernel supports SO_MEMINFO before registering the gauges
|
|
|
|
var udpGauges [][_SK_MEMINFO_VARS]metrics.Gauge
|
|
|
|
var meminfo _SK_MEMINFO
|
2023-06-14 09:48:52 -06:00
|
|
|
if err := udpConns[0].(*StdConn).getMemInfo(&meminfo); err == nil {
|
2021-03-01 17:51:33 -07:00
|
|
|
udpGauges = make([][_SK_MEMINFO_VARS]metrics.Gauge, len(udpConns))
|
|
|
|
for i := range udpConns {
|
|
|
|
udpGauges[i] = [_SK_MEMINFO_VARS]metrics.Gauge{
|
|
|
|
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.rmem_alloc", i), nil),
|
|
|
|
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.rcvbuf", i), nil),
|
|
|
|
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.wmem_alloc", i), nil),
|
|
|
|
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.sndbuf", i), nil),
|
|
|
|
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.fwd_alloc", i), nil),
|
|
|
|
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.wmem_queued", i), nil),
|
|
|
|
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.optmem", i), nil),
|
|
|
|
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.backlog", i), nil),
|
|
|
|
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.drops", i), nil),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return func() {
|
|
|
|
for i, gauges := range udpGauges {
|
2023-06-14 09:48:52 -06:00
|
|
|
if err := udpConns[i].(*StdConn).getMemInfo(&meminfo); err == nil {
|
2021-03-01 17:51:33 -07:00
|
|
|
for j := 0; j < _SK_MEMINFO_VARS; j++ {
|
|
|
|
gauges[j].Update(int64(meminfo[j]))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|