From 516483e44293456657028b606b1162e2f0909c8f Mon Sep 17 00:00:00 2001 From: Yaroslav Kolomiiets Date: Fri, 18 Oct 2024 04:35:41 -0700 Subject: [PATCH] time/timestamp: switch to use the upstreamed funcs in sys/unix (#411) Summary: Simplify the code by switching to use the upstreamed functions/structures. Reviewed By: abulimov Differential Revision: D64542033 --- phc/unix/linux.go | 95 ++++++++++++++++++++++++++++-------- timestamp/timestamp.go | 43 +--------------- timestamp/timestamp_linux.go | 55 +++++++++------------ 3 files changed, 99 insertions(+), 94 deletions(-) diff --git a/phc/unix/linux.go b/phc/unix/linux.go index aeb8d4d7..f7ceb315 100644 --- a/phc/unix/linux.go +++ b/phc/unix/linux.go @@ -51,6 +51,33 @@ func IoctlGetHwTstamp(fd int, ifname string) (*HwTstampConfig, error) { return &value, err } +// IoctlSetHwTstamp updates the hardware timestamping configuration for +// the network device specified by ifname. +func IoctlSetHwTstamp(fd int, ifname string, cfg *HwTstampConfig) error { + ifr, err := NewIfreq(ifname) + if err != nil { + return err + } + ifrd := ifr.withData(unsafe.Pointer(cfg)) + return ioctlIfreqData(fd, SIOCSHWTSTAMP, &ifrd) +} + +const ( + HWTSTAMP_FILTER_NONE = 0x0 //nolint:revive + HWTSTAMP_FILTER_ALL = 0x1 //nolint:revive + HWTSTAMP_FILTER_SOME = 0x2 //nolint:revive + HWTSTAMP_FILTER_PTP_V1_L4_EVENT = 0x3 //nolint:revive + HWTSTAMP_FILTER_PTP_V2_L4_EVENT = 0x6 //nolint:revive + HWTSTAMP_FILTER_PTP_V2_L2_EVENT = 0x9 //nolint:revive + HWTSTAMP_FILTER_PTP_V2_EVENT = 0xc //nolint:revive +) + +const ( + HWTSTAMP_TX_OFF = 0x0 //nolint:revive + HWTSTAMP_TX_ON = 0x1 //nolint:revive + HWTSTAMP_TX_ONESTEP_SYNC = 0x2 //nolint:revive +) + // https://go-review.googlesource.com/c/sys/+/619335 // EthtoolTsInfo a struct returned by ETHTOOL_GET_TS_INFO function of @@ -93,33 +120,63 @@ func ClockSettime(clockid int32, time *Timespec) (err error) { // bridging to upstream +type Cmsghdr = unix.Cmsghdr type Errno = unix.Errno +type Msghdr = unix.Msghdr +type PollFd = unix.PollFd type RawSockaddrInet4 = unix.RawSockaddrInet4 -type Timex = unix.Timex +type SockaddrInet4 = unix.SockaddrInet4 +type SockaddrInet6 = unix.SockaddrInet6 +type Sockaddr = unix.Sockaddr type Timespec = unix.Timespec - +type Timex = unix.Timex +type Utsname = unix.Utsname + +func ByteSliceToString(b []byte) string { return unix.ByteSliceToString(b) } +func ClockAdjtime(c int32, t *Timex) (int, error) { return unix.ClockAdjtime(c, t) } +func Close(fd int) (err error) { return unix.Close(fd) } +func ErrnoName(e syscall.Errno) string { return unix.ErrnoName(e) } +func Poll(f []PollFd, t int) (int, error) { return unix.Poll(f, t) } +func Recvmsg(a int, b, c []byte, d int) (int, int, int, Sockaddr, error) { + return unix.Recvmsg(a, b, c, d) +} +func SetsockoptInt(a, b, c, d int) error { return unix.SetsockoptInt(a, b, c, d) } func Socket(domain, typ, proto int) (fd int, err error) { return unix.Socket(domain, typ, proto) } -func Close(fd int) (err error) { return unix.Close(fd) } func Syscall(a, b, c, d uintptr) (uintptr, uintptr, Errno) { return unix.Syscall(a, b, c, d) } -func ByteSliceToString(b []byte) string { return unix.ByteSliceToString(b) } -func ClockAdjtime(c int32, t *Timex) (int, error) { return unix.ClockAdjtime(c, t) } func TimeToTimespec(t time.Time) (Timespec, error) { return unix.TimeToTimespec(t) } +func Uname(s *Utsname) error { return unix.Uname(s) } const ( - AF_INET = unix.AF_INET //nolint:revive - EAGAIN = unix.EAGAIN //nolint:revive - EINVAL = unix.EINVAL //nolint:revive - ENOENT = unix.ENOENT //nolint:revive - ETHTOOL_GET_TS_INFO = unix.ETHTOOL_GET_TS_INFO //nolint:revive - IFNAMSIZ = unix.IFNAMSIZ //nolint:revive - SIOCETHTOOL = unix.SIOCETHTOOL //nolint:revive - SIOCGHWTSTAMP = unix.SIOCGHWTSTAMP //nolint:revive - SizeofPtr = unix.SizeofPtr - SizeofSockaddrInet4 = unix.SizeofSockaddrInet4 - SOCK_DGRAM = unix.SOCK_DGRAM //nolint:revive - SYS_CLOCK_SETTIME = unix.SYS_CLOCK_SETTIME //nolint:revive - SYS_IOCTL = unix.SYS_IOCTL //nolint:revive - TIME_OK = unix.TIME_OK //nolint:revive + AF_INET = unix.AF_INET //nolint:revive + EAGAIN = unix.EAGAIN //nolint:revive + EINVAL = unix.EINVAL //nolint:revive + ENOENT = unix.ENOENT //nolint:revive + ENOTSUP = unix.ENOTSUP //nolint:revive + ETHTOOL_GET_TS_INFO = unix.ETHTOOL_GET_TS_INFO //nolint:revive + IFNAMSIZ = unix.IFNAMSIZ //nolint:revive + MSG_ERRQUEUE = unix.MSG_ERRQUEUE //nolint:revive + POLLERR = unix.POLLERR //nolint:revive + SIOCETHTOOL = unix.SIOCETHTOOL //nolint:revive + SIOCGHWTSTAMP = unix.SIOCGHWTSTAMP //nolint:revive + SIOCSHWTSTAMP = unix.SIOCSHWTSTAMP //nolint:revive + SizeofPtr = unix.SizeofPtr + SizeofSockaddrInet4 = unix.SizeofSockaddrInet4 + SOCK_DGRAM = unix.SOCK_DGRAM //nolint:revive + SOF_TIMESTAMPING_OPT_TSONLY = unix.SOF_TIMESTAMPING_OPT_TSONLY //nolint:revive + SOF_TIMESTAMPING_RAW_HARDWARE = unix.SOF_TIMESTAMPING_RAW_HARDWARE //nolint:revive + SOF_TIMESTAMPING_RX_HARDWARE = unix.SOF_TIMESTAMPING_RX_HARDWARE //nolint:revive + SOF_TIMESTAMPING_RX_SOFTWARE = unix.SOF_TIMESTAMPING_RX_SOFTWARE //nolint:revive + SOF_TIMESTAMPING_SOFTWARE = unix.SOF_TIMESTAMPING_SOFTWARE //nolint:revive + SOF_TIMESTAMPING_TX_HARDWARE = unix.SOF_TIMESTAMPING_TX_HARDWARE //nolint:revive + SOF_TIMESTAMPING_TX_SOFTWARE = unix.SOF_TIMESTAMPING_TX_SOFTWARE //nolint:revive + SOL_SOCKET = unix.SOL_SOCKET //nolint:revive + SO_SELECT_ERR_QUEUE = unix.SO_SELECT_ERR_QUEUE //nolint:revive + SO_TIMESTAMPING_NEW = unix.SO_TIMESTAMPING_NEW //nolint:revive + SO_TIMESTAMPING = unix.SO_TIMESTAMPING //nolint:revive + SYS_CLOCK_SETTIME = unix.SYS_CLOCK_SETTIME //nolint:revive + SYS_IOCTL = unix.SYS_IOCTL //nolint:revive + SYS_RECVMSG = unix.SYS_RECVMSG //nolint:revive + TIME_OK = unix.TIME_OK //nolint:revive ) var ( diff --git a/timestamp/timestamp.go b/timestamp/timestamp.go index 32d084c3..f71f0c49 100644 --- a/timestamp/timestamp.go +++ b/timestamp/timestamp.go @@ -24,17 +24,7 @@ import ( "net/netip" "time" - "golang.org/x/sys/unix" -) - -// from include/uapi/linux/net_tstamp.h -const ( - // HWTSTAMP_TX_ON int 1 - hwtstampTXON int32 = 0x00000001 - // HWTSTAMP_FILTER_ALL int 1 - hwtstampFilterAll int32 = 0x00000001 - //HWTSTAMP_FILTER_PTP_V2_L4_EVENT int 6 - hwtstampFilterPTPv2L4Event int32 = 0x00000006 + "github.com/facebook/time/phc/unix" // a temporary shim for "golang.org/x/sys/unix" until v0.27.0 is cut ) const ( @@ -122,37 +112,6 @@ func (t *Timestamp) Type() string { return "timestamp" } -// EthtoolGetTSInfo is get time stamping and PHC info command -const EthtoolGetTSInfo uint32 = 0x00000041 - -// Ifreq is a struct for ioctl ethernet manipulation syscalls. -type ifreq struct { - name [unix.IFNAMSIZ]byte - data uintptr -} - -// from include/uapi/linux/net_tstamp.h -type hwtstampConfig struct { - flags int32 - txType int32 - rxFilter int32 -} - -// from include/uapi/linux/ethtool.h struct ethtool_ts_info -type hwtstampCaps struct { - cmd uint32 - sofTimestamping uint32 /* SOF_TIMESTAMPING_* bitmask */ - phcIndex int32 - txTypes uint32 /* HWTSTAMP_TX_* */ - txReserved0 uint32 - txReserved1 uint32 - txReserved2 uint32 - rxFilters uint32 /* HWTSTAMP_FILTER_ */ - rxReserved0 uint32 - rxReserved1 uint32 - rxReserved2 uint32 -} - // AttemptsTXTS is configured amount of attempts to read TX timestamp var AttemptsTXTS = defaultTXTS diff --git a/timestamp/timestamp_linux.go b/timestamp/timestamp_linux.go index f8d8ef9a..53cadb83 100644 --- a/timestamp/timestamp_linux.go +++ b/timestamp/timestamp_linux.go @@ -24,7 +24,7 @@ import ( "time" "unsafe" - "golang.org/x/sys/unix" + "github.com/facebook/time/phc/unix" // a temporary shim for "golang.org/x/sys/unix" until v0.27.0 is cut ) // unix.Cmsghdr size differs depending on platform @@ -85,27 +85,21 @@ func byteToTime(data []byte) (time.Time, error) { } func ioctlHWTimestampCaps(fd int, ifname string) (int32, int32, error) { - // empty config, will be populated after we call SIOCETHTOOL - hw := &hwtstampCaps{ - cmd: EthtoolGetTSInfo, - } - var rxFilter int32 - var txFilter int32 + var rxFilter, txFilter int32 - i := &ifreq{data: uintptr(unsafe.Pointer(hw))} - copy(i.name[:unix.IFNAMSIZ-1], ifname) - if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), unix.SIOCETHTOOL, uintptr(unsafe.Pointer(i))); errno != 0 { - return rxFilter, txFilter, fmt.Errorf("failed to run ioctl SIOCETHTOOL to see what is supported: %s (%w)", unix.ErrnoName(errno), errno) + hw, err := unix.IoctlGetEthtoolTsInfo(fd, ifname) + if err != nil { + return 0, 0, fmt.Errorf("failed to run ioctl SIOCETHTOOL to see what is supported: (%w)", err) } - if hw.txTypes&(1< 0 { - txFilter = hwtstampTXON + if hw.Tx_types&(1< 0 { + txFilter = unix.HWTSTAMP_TX_ON } - if hw.rxFilters&(1< 0 { - rxFilter = hwtstampFilterPTPv2L4Event - } else if hw.rxFilters&(1< 0 { - rxFilter = hwtstampFilterAll + if hw.Rx_filters&(1< 0 { + rxFilter = unix.HWTSTAMP_FILTER_PTP_V2_L4_EVENT + } else if hw.Rx_filters&(1< 0 { + rxFilter = unix.HWTSTAMP_FILTER_ALL } if txFilter == 0 || rxFilter == 0 { @@ -115,28 +109,23 @@ func ioctlHWTimestampCaps(fd int, ifname string) (int32, int32, error) { } func ioctlTimestamp(fd int, ifname string, filter int32) error { - // empty config, will be populated after we call SIOCGHWTSTAMP - hw := &hwtstampConfig{ - flags: 0, - txType: 0, - rxFilter: 0, - } - - i := &ifreq{data: uintptr(unsafe.Pointer(hw))} - copy(i.name[:unix.IFNAMSIZ-1], ifname) - if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), unix.SIOCGHWTSTAMP, uintptr(unsafe.Pointer(i))); errno != 0 && errno != unix.ENOTSUP { - return fmt.Errorf("failed to run ioctl SIOCGHWTSTAMP to see what is enabled: %s (%w)", unix.ErrnoName(errno), errno) + hw, err := unix.IoctlGetHwTstamp(fd, ifname) + if errors.Is(err, unix.ENOTSUP) { + // for the loopback interface + hw = &unix.HwTstampConfig{} + } else if err != nil { + return fmt.Errorf("failed to run ioctl SIOCGHWTSTAMP to see what is enabled: %w", err) } // now check if it matches what we want - if hw.txType == hwtstampTXON && hw.rxFilter == filter { + if hw.Tx_type == unix.HWTSTAMP_TX_ON && hw.Rx_filter == filter { return nil } // set to desired values - hw.txType = hwtstampTXON - hw.rxFilter = filter - if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), unix.SIOCSHWTSTAMP, uintptr(unsafe.Pointer(i))); errno != 0 { - return fmt.Errorf("failed to run ioctl SIOCSHWTSTAMP to set timestamps enabled: %s (%w)", unix.ErrnoName(errno), errno) + hw.Tx_type = unix.HWTSTAMP_TX_ON + hw.Rx_filter = filter + if err := unix.IoctlSetHwTstamp(fd, ifname, hw); err != nil { + return fmt.Errorf("failed to run ioctl SIOCSHWTSTAMP to set timestamps enabled: %w", err) } return nil }