From e5eee7e480879ddfd1d2c3df4c3d97656c7a2d80 Mon Sep 17 00:00:00 2001 From: Yaroslav Kolomiiets Date: Fri, 11 Oct 2024 00:30:15 +0000 Subject: [PATCH] unix: add IoctlGetEthtoolTsInfo on Linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function fetches ethtool timestamping and PHC association for a network interface. Its primary usage is to query the mapping between the interface and its corresponding PTP clock number in /dev/ptp𝑛. Change-Id: Id09466b3b43056c628593d4d2e05d77ec8d8082b GitHub-Last-Rev: 3743a3a6504e6926031b8f2ece331078ae543b25 GitHub-Pull-Request: golang/sys#222 Reviewed-on: https://go-review.googlesource.com/c/sys/+/619335 LUCI-TryBot-Result: Go LUCI Reviewed-by: Tobias Klauser Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor Reviewed-by: Cherry Mui --- unix/ioctl_linux.go | 15 +++++++++++++++ unix/linux/types.go | 2 ++ unix/syscall_linux_test.go | 38 ++++++++++++++++++++++++++++++++++++++ unix/ztypes_linux.go | 10 ++++++++++ 4 files changed, 65 insertions(+) diff --git a/unix/ioctl_linux.go b/unix/ioctl_linux.go index dbe680ea..e605abd1 100644 --- a/unix/ioctl_linux.go +++ b/unix/ioctl_linux.go @@ -58,6 +58,21 @@ func IoctlGetEthtoolDrvinfo(fd int, ifname string) (*EthtoolDrvinfo, error) { return &value, err } +// IoctlGetEthtoolTsInfo fetches ethtool timestamping and PHC +// association for the network device specified by ifname. +func IoctlGetEthtoolTsInfo(fd int, ifname string) (*EthtoolTsInfo, error) { + ifr, err := NewIfreq(ifname) + if err != nil { + return nil, err + } + + value := EthtoolTsInfo{Cmd: ETHTOOL_GET_TS_INFO} + ifrd := ifr.withData(unsafe.Pointer(&value)) + + err = ioctlIfreqData(fd, SIOCETHTOOL, &ifrd) + return &value, err +} + // IoctlGetWatchdogInfo fetches information about a watchdog device from the // Linux watchdog API. For more information, see: // https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html. diff --git a/unix/linux/types.go b/unix/linux/types.go index 0ba570fe..61e82e5b 100644 --- a/unix/linux/types.go +++ b/unix/linux/types.go @@ -4090,6 +4090,8 @@ const SPEED_UNKNOWN = C.SPEED_UNKNOWN type EthtoolDrvinfo C.struct_ethtool_drvinfo +type EthtoolTsInfo C.struct_ethtool_ts_info + type ( HIDRawReportDescriptor C.struct_hidraw_report_descriptor HIDRawDevInfo C.struct_hidraw_devinfo diff --git a/unix/syscall_linux_test.go b/unix/syscall_linux_test.go index 53e64458..eca3b7aa 100644 --- a/unix/syscall_linux_test.go +++ b/unix/syscall_linux_test.go @@ -68,6 +68,44 @@ func TestIoctlGetEthtoolDrvinfo(t *testing.T) { } } +func TestIoctlGetEthtoolTsInfo(t *testing.T) { + if runtime.GOOS == "android" { + t.Skip("ethtool driver info is not available on android, skipping test") + } + + s, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0) + if err != nil { + t.Fatalf("failed to open socket: %v", err) + } + defer unix.Close(s) + + ifis, err := net.Interfaces() + if err != nil { + t.Fatalf("failed to get network interfaces: %v", err) + } + + // Print the interface name and associated PHC information for each + // network interface supported by ethtool. + for _, ifi := range ifis { + tsi, err := unix.IoctlGetEthtoolTsInfo(s, ifi.Name) + if err != nil { + if err == unix.EOPNOTSUPP { + continue + } + + if err == unix.EBUSY { + // See https://go.dev/issues/67350 + t.Logf("%s: ethtool driver busy, possible kernel bug", ifi.Name) + continue + } + + t.Fatalf("failed to get ethtool PHC info for %q: %v", ifi.Name, err) + } + + t.Logf("%s: ptp%d", ifi.Name, tsi.Phc_index) + } +} + func TestIoctlGetInt(t *testing.T) { f, err := os.Open("/dev/random") if err != nil { diff --git a/unix/ztypes_linux.go b/unix/ztypes_linux.go index 3a69e454..232c3798 100644 --- a/unix/ztypes_linux.go +++ b/unix/ztypes_linux.go @@ -4110,6 +4110,16 @@ type EthtoolDrvinfo struct { Regdump_len uint32 } +type EthtoolTsInfo struct { + Cmd uint32 + So_timestamping uint32 + Phc_index int32 + Tx_types uint32 + Tx_reserved [3]uint32 + Rx_filters uint32 + Rx_reserved [3]uint32 +} + type ( HIDRawReportDescriptor struct { Size uint32