Skip to content

Commit

Permalink
afpacket: Fix support for 32-bit x86 arch
Browse files Browse the repository at this point in the history
afpacket uses syscalls unix.SYS_GETSOCKOPT and unix.SYS_SETSOCKOPT
when it needs to call [gs]etsockopt() passing a raw pointer. This
doesn't work for 32-bit x86 platforms as there's no such syscall,
resulting in:

   setsockopt packet_rx_ring: function not implemented

   unix.Syscall(unix.SYS_GETSOCKOPT[=366],...) = 38 // ENOSYS

The correct way to call [gs]etsockopt() in this platform is to use
the SYS_SOCKETCALL syscall with the right call parameter.

This patch refactors the raw [gs]etsockopt() calls in afpacket to use
unix.GetsockoptString and unix.SetsockoptString so that it relies on
Go runtime to call the appropriate syscall.
  • Loading branch information
adriansr committed Oct 18, 2019
1 parent 0ad7f26 commit a13a1c6
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 34 deletions.
12 changes: 4 additions & 8 deletions afpacket/afpacket.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,20 +337,18 @@ func (h *TPacket) Stats() (Stats, error) {
func (h *TPacket) InitSocketStats() error {
if h.tpVersion == TPacketVersion3 {
socklen := unsafe.Sizeof(h.socketStatsV3)
slt := C.socklen_t(socklen)
var ssv3 SocketStatsV3

err := getsockopt(h.fd, unix.SOL_PACKET, unix.PACKET_STATISTICS, unsafe.Pointer(&ssv3), uintptr(unsafe.Pointer(&slt)))
err := getsockopt(h.fd, unix.SOL_PACKET, unix.PACKET_STATISTICS, unsafe.Pointer(&ssv3), &socklen)
if err != nil {
return err
}
h.socketStatsV3 = SocketStatsV3{}
} else {
socklen := unsafe.Sizeof(h.socketStats)
slt := C.socklen_t(socklen)
var ss SocketStats

err := getsockopt(h.fd, unix.SOL_PACKET, unix.PACKET_STATISTICS, unsafe.Pointer(&ss), uintptr(unsafe.Pointer(&slt)))
err := getsockopt(h.fd, unix.SOL_PACKET, unix.PACKET_STATISTICS, unsafe.Pointer(&ss), &socklen)
if err != nil {
return err
}
Expand All @@ -366,10 +364,9 @@ func (h *TPacket) SocketStats() (SocketStats, SocketStatsV3, error) {
// We need to save the counters since asking for the stats will clear them
if h.tpVersion == TPacketVersion3 {
socklen := unsafe.Sizeof(h.socketStatsV3)
slt := C.socklen_t(socklen)
var ssv3 SocketStatsV3

err := getsockopt(h.fd, unix.SOL_PACKET, unix.PACKET_STATISTICS, unsafe.Pointer(&ssv3), uintptr(unsafe.Pointer(&slt)))
err := getsockopt(h.fd, unix.SOL_PACKET, unix.PACKET_STATISTICS, unsafe.Pointer(&ssv3), &socklen)
if err != nil {
return SocketStats{}, SocketStatsV3{}, err
}
Expand All @@ -380,10 +377,9 @@ func (h *TPacket) SocketStats() (SocketStats, SocketStatsV3, error) {
return h.socketStats, h.socketStatsV3, nil
}
socklen := unsafe.Sizeof(h.socketStats)
slt := C.socklen_t(socklen)
var ss SocketStats

err := getsockopt(h.fd, unix.SOL_PACKET, unix.PACKET_STATISTICS, unsafe.Pointer(&ss), uintptr(unsafe.Pointer(&slt)))
err := getsockopt(h.fd, unix.SOL_PACKET, unix.PACKET_STATISTICS, unsafe.Pointer(&ss), &socklen)
if err != nil {
return SocketStats{}, SocketStatsV3{}, err
}
Expand Down
46 changes: 20 additions & 26 deletions afpacket/sockopt_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,44 +9,38 @@
package afpacket

import (
"errors"
"syscall"
"unsafe"

"golang.org/x/sys/unix"
)

const maxOptSize = 8192

var errSockoptTooBig = errors.New("socket option too big")

// setsockopt provides access to the setsockopt syscall.
func setsockopt(fd, level, name int, val unsafe.Pointer, vallen uintptr) error {
_, _, errno := unix.Syscall6(
unix.SYS_SETSOCKOPT,
uintptr(fd),
uintptr(level),
uintptr(name),
uintptr(val),
vallen,
0,
)
if errno != 0 {
return error(errno)
if vallen > maxOptSize {
return errSockoptTooBig
}

return nil
slice := (*[maxOptSize]byte)(val)[:]
return syscall.SetsockoptString(fd, level, name, string(slice[:vallen]))
}

// getsockopt provides access to the getsockopt syscall.
func getsockopt(fd, level, name int, val unsafe.Pointer, vallen uintptr) error {
_, _, errno := unix.Syscall6(
unix.SYS_GETSOCKOPT,
uintptr(fd),
uintptr(level),
uintptr(name),
uintptr(val),
vallen,
0,
)
if errno != 0 {
return error(errno)
func getsockopt(fd, level, name int, val unsafe.Pointer, vallen *uintptr) error {
s, err := unix.GetsockoptString(fd, level, name)
if err != nil {
return err
}

rcvLen := uintptr(len(s))
if rcvLen > *vallen {
return errSockoptTooBig
}
copy((*[maxOptSize]byte)(val)[:rcvLen], s)
*vallen = rcvLen
return nil
}

Expand Down

0 comments on commit a13a1c6

Please sign in to comment.