diff --git a/cmd/ptpcheck/cmd/map.go b/cmd/ptpcheck/cmd/map.go index 85d0bab2..aaa61b6a 100644 --- a/cmd/ptpcheck/cmd/map.go +++ b/cmd/ptpcheck/cmd/map.go @@ -24,10 +24,9 @@ import ( "strings" "unicode" + "github.com/facebook/time/phc/unix" // a temporary shim for "golang.org/x/sys/unix" until v0.27.0 is cut log "github.com/sirupsen/logrus" "github.com/spf13/cobra" - - "github.com/facebook/time/phc" ) func ptpDeviceNum(ptpPath string) (int, error) { @@ -46,25 +45,32 @@ func ptpDeviceNum(ptpPath string) (int, error) { })) } -func printIfaceData(ifname string, tsinfo *phc.EthtoolTSinfo, reverse bool) { - if tsinfo.PHCIndex < 0 { +func printIfaceData(ifname string, tsinfo *unix.EthtoolTsInfo, reverse bool) { + if tsinfo.Phc_index < 0 { fmt.Printf("No PHC support for %s\n", ifname) return } - attrs := fmt.Sprintf("cap-tx-types %x cap-rx-filters %x", tsinfo.TXTypes, tsinfo.RXFilters) + + var attrs string + if tscfg, err := unix.IoctlGetHwTstamp(iofd, ifname); err == nil { + attrs = fmt.Sprintf("tx-type %d rx-filter %d", tscfg.Tx_type, tscfg.Rx_filter) + } else { + log.Warningf("%s: IoctlGetHwTstamp: %v", ifname, err) + } + if reverse { - fmt.Printf("/dev/ptp%d -> %s\t%s\n", tsinfo.PHCIndex, ifname, attrs) - return + fmt.Printf("/dev/ptp%d -> %s\t%s\n", tsinfo.Phc_index, ifname, attrs) + } else { + fmt.Printf("%s -> /dev/ptp%d\t%s\n", ifname, tsinfo.Phc_index, attrs) } - fmt.Printf("%s -> /dev/ptp%d\t%s\n", ifname, tsinfo.PHCIndex, attrs) } -func getDevice(iface string) error { - tsinfo, err := phc.IfaceInfo(iface) +func getDevice(ifname string) error { + tsinfo, err := unix.IoctlGetEthtoolTsInfo(iofd, ifname) if err != nil { - return err + return fmt.Errorf("%v: IoctlGetEthtoolTsInfo: %w", ifname, err) } - printIfaceData(iface, tsinfo, false) + printIfaceData(ifname, tsinfo, false) return nil } @@ -75,21 +81,23 @@ func getIface(ptpDevice int) error { } n := 0 for _, iface := range ifaces { - tsinfo, err := phc.IfaceInfo(iface.Name) + tsinfo, err := unix.IoctlGetEthtoolTsInfo(iofd, iface.Name) if err != nil { + log.Errorf("%v: IoctlGetEthtoolTsInfo: %v", iface.Name, err) continue } - if int(tsinfo.PHCIndex) == ptpDevice || ptpDevice < 0 { + if int(tsinfo.Phc_index) == ptpDevice || ptpDevice < 0 { printIfaceData(iface.Name, tsinfo, true) n++ } } - if n == 0 { + if ptpDevice >= 0 && n == 0 { return fmt.Errorf("no nic found for /dev/ptp%d", ptpDevice) } return nil } +var iofd int var mapIfaceFlag bool func init() { @@ -101,7 +109,16 @@ var mapCmd = &cobra.Command{ Use: "map [ptp device/network interface]...", Short: "Find network interfaces for ptp devices and vice versa", Run: func(_ *cobra.Command, args []string) { + var err error ConfigureVerbosity() + + iofd, err = unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0) + if err != nil { + log.Error(err) + return + } + defer unix.Close(iofd) + // no args - just print map of all ptp devices to all interfaces if len(args) == 0 { if err := getIface(-1); err != nil { diff --git a/phc/unix/README.md b/phc/unix/README.md new file mode 100644 index 00000000..a5e40c51 --- /dev/null +++ b/phc/unix/README.md @@ -0,0 +1,5 @@ +A temporary shim for "golang.org/x/sys/unix" until v0.27.0 is cut. + +We can't simply update go.mod with pre-release version of the package +because of the dependency management approach Fedora has for building +RPMs from Go sources. diff --git a/phc/unix/ifreq_linux.go b/phc/unix/ifreq_linux.go new file mode 100644 index 00000000..57494c4d --- /dev/null +++ b/phc/unix/ifreq_linux.go @@ -0,0 +1,67 @@ +//go:build linux + +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unix + +import ( + "unsafe" +) + +// An Ifreq is a type-safe wrapper around the raw ifreq struct. An Ifreq +// contains an interface name and a union of arbitrary data which can be +// accessed using the Ifreq's methods. To create an Ifreq, use the NewIfreq +// function. +type Ifreq struct{ raw ifreq } + +// NewIfreq creates an Ifreq with the input network interface name +func NewIfreq(name string) (*Ifreq, error) { + if len(name) >= IFNAMSIZ { + return nil, EINVAL + } + + var ifr ifreq + copy(ifr.Ifrn[:], name) + + return &Ifreq{raw: ifr}, nil +} + +// Name returns the interface name associated with the Ifreq. +func (ifr *Ifreq) Name() string { + return ByteSliceToString(ifr.raw.Ifrn[:]) +} + +// An ifreqData is an Ifreq which carries pointer data. +// To produce an ifreqData, use the Ifreq.withData method. +type ifreqData struct { + name [IFNAMSIZ]byte + // A type separate from ifreq is required in order to comply with the + // unsafe.Pointer rules since the "pointer-ness" of data would not be + // preserved if it were cast into the byte array of a raw ifreq. + data unsafe.Pointer + // Pad to the same size as ifreq. + _ [len(ifreq{}.Ifru) - SizeofPtr]byte +} + +// withData produces an ifreqData with the pointer p set for ioctls which require +// arbitrary pointer data. +func (ifr Ifreq) withData(p unsafe.Pointer) ifreqData { + return ifreqData{ + name: ifr.raw.Ifrn, + data: p, + } +} diff --git a/phc/unix/linux.go b/phc/unix/linux.go new file mode 100644 index 00000000..39c039f7 --- /dev/null +++ b/phc/unix/linux.go @@ -0,0 +1,139 @@ +// @generated +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//go:build linux + +package unix + +import ( + "syscall" + "unsafe" + + "golang.org/x/sys/unix" +) + +// https://go-review.googlesource.com/c/sys/+/620376 + +type HwTstampConfig struct { + Flags int32 + Tx_type int32 + Rx_filter int32 +} + +// IoctlGetHwTstamp retrieves the hardware timestamping configuration +// for the network device specified by ifname. +func IoctlGetHwTstamp(fd int, ifname string) (*HwTstampConfig, error) { + ifr, err := NewIfreq(ifname) + if err != nil { + return nil, err + } + + value := HwTstampConfig{} + ifrd := ifr.withData(unsafe.Pointer(&value)) + + err = ioctlIfreqData(fd, SIOCGHWTSTAMP, &ifrd) + return &value, err +} + +// https://go-review.googlesource.com/c/sys/+/619335 + +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 +} + +// 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 +} + +// bridging to upstream + +type Errno = unix.Errno +type RawSockaddrInet4 = unix.RawSockaddrInet4 +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) } + +const ( + AF_INET = unix.AF_INET //nolint:staticcheck + ETHTOOL_GET_TS_INFO = unix.ETHTOOL_GET_TS_INFO + SIOCETHTOOL = unix.SIOCETHTOOL + SIOCGHWTSTAMP = unix.SIOCGHWTSTAMP + SOCK_DGRAM = unix.SOCK_DGRAM + SYS_IOCTL = unix.SYS_IOCTL + EAGAIN = unix.EAGAIN + EINVAL = unix.EINVAL + ENOENT = unix.ENOENT + IFNAMSIZ = unix.IFNAMSIZ + SizeofSockaddrInet4 = unix.SizeofSockaddrInet4 + SizeofPtr = unix.SizeofPtr +) + +var ( + errEAGAIN error = syscall.EAGAIN + errEINVAL error = syscall.EINVAL + errENOENT error = syscall.ENOENT +) + +// ioctlIfreqData performs an ioctl using an ifreqData structure for input +// and/or output. See the netdevice(7) man page for details. +func ioctlIfreqData(fd int, req uint, value *ifreqData) error { + // The memory layout of IfreqData (type-safe) and ifreq (not type-safe) are + // identical so pass *IfreqData directly. + return ioctlPtr(fd, req, unsafe.Pointer(value)) +} + +func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) { + _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// errnoErr returns common boxed Errno values, to prevent +// allocations at runtime. +func errnoErr(e syscall.Errno) error { + switch e { + case 0: + return nil + case EAGAIN: + return errEAGAIN + case EINVAL: + return errEINVAL + case ENOENT: + return errENOENT + } + return e +} diff --git a/phc/unix/linux_386.go b/phc/unix/linux_386.go new file mode 100644 index 00000000..38e50cee --- /dev/null +++ b/phc/unix/linux_386.go @@ -0,0 +1,24 @@ +//go:build 386 && linux + +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unix + +type ifreq struct { + Ifrn [16]byte + Ifru [16]byte +} diff --git a/phc/unix/linux_amd64.go b/phc/unix/linux_amd64.go new file mode 100644 index 00000000..9ca05368 --- /dev/null +++ b/phc/unix/linux_amd64.go @@ -0,0 +1,24 @@ +//go:build amd64 && linux + +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unix + +type ifreq struct { + Ifrn [16]byte + Ifru [24]byte +} diff --git a/phc/unix/linux_arm.go b/phc/unix/linux_arm.go new file mode 100644 index 00000000..e7636189 --- /dev/null +++ b/phc/unix/linux_arm.go @@ -0,0 +1,24 @@ +//go:build arm && linux + +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unix + +type ifreq struct { + Ifrn [16]byte + Ifru [16]byte +} diff --git a/phc/unix/linux_arm64.go b/phc/unix/linux_arm64.go new file mode 100644 index 00000000..cc64ff77 --- /dev/null +++ b/phc/unix/linux_arm64.go @@ -0,0 +1,24 @@ +//go:build arm64 && linux + +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unix + +type ifreq struct { + Ifrn [16]byte + Ifru [24]byte +} diff --git a/phc/unix/linux_loong64.go b/phc/unix/linux_loong64.go new file mode 100644 index 00000000..dae50dd2 --- /dev/null +++ b/phc/unix/linux_loong64.go @@ -0,0 +1,24 @@ +//go:build loong64 && linux + +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unix + +type ifreq struct { + Ifrn [16]byte + Ifru [24]byte +} diff --git a/phc/unix/linux_mips.go b/phc/unix/linux_mips.go new file mode 100644 index 00000000..16d511af --- /dev/null +++ b/phc/unix/linux_mips.go @@ -0,0 +1,24 @@ +//go:build mips && linux + +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unix + +type ifreq struct { + Ifrn [16]byte + Ifru [16]byte +} diff --git a/phc/unix/linux_mips64.go b/phc/unix/linux_mips64.go new file mode 100644 index 00000000..8c3993fe --- /dev/null +++ b/phc/unix/linux_mips64.go @@ -0,0 +1,24 @@ +//go:build mips64 && linux + +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unix + +type ifreq struct { + Ifrn [16]byte + Ifru [24]byte +} diff --git a/phc/unix/linux_mips64le.go b/phc/unix/linux_mips64le.go new file mode 100644 index 00000000..65c33156 --- /dev/null +++ b/phc/unix/linux_mips64le.go @@ -0,0 +1,24 @@ +//go:build mips64le && linux + +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unix + +type ifreq struct { + Ifrn [16]byte + Ifru [24]byte +} diff --git a/phc/unix/linux_mipsle.go b/phc/unix/linux_mipsle.go new file mode 100644 index 00000000..e91627fa --- /dev/null +++ b/phc/unix/linux_mipsle.go @@ -0,0 +1,24 @@ +//go:build mipsle && linux + +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unix + +type ifreq struct { + Ifrn [16]byte + Ifru [16]byte +} diff --git a/phc/unix/linux_ppc.go b/phc/unix/linux_ppc.go new file mode 100644 index 00000000..f130592f --- /dev/null +++ b/phc/unix/linux_ppc.go @@ -0,0 +1,24 @@ +//go:build ppc && linux + +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unix + +type ifreq struct { + Ifrn [16]byte + Ifru [16]byte +} diff --git a/phc/unix/linux_ppc64.go b/phc/unix/linux_ppc64.go new file mode 100644 index 00000000..5c70ef95 --- /dev/null +++ b/phc/unix/linux_ppc64.go @@ -0,0 +1,24 @@ +//go:build ppc64 && linux + +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unix + +type ifreq struct { + Ifrn [16]byte + Ifru [24]byte +} diff --git a/phc/unix/linux_ppc64le.go b/phc/unix/linux_ppc64le.go new file mode 100644 index 00000000..b7339e6c --- /dev/null +++ b/phc/unix/linux_ppc64le.go @@ -0,0 +1,24 @@ +//go:build ppc64le && linux + +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unix + +type ifreq struct { + Ifrn [16]byte + Ifru [24]byte +} diff --git a/phc/unix/linux_riscv64.go b/phc/unix/linux_riscv64.go new file mode 100644 index 00000000..89a33b81 --- /dev/null +++ b/phc/unix/linux_riscv64.go @@ -0,0 +1,24 @@ +//go:build riscv64 && linux + +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unix + +type ifreq struct { + Ifrn [16]byte + Ifru [24]byte +} diff --git a/phc/unix/linux_s390x.go b/phc/unix/linux_s390x.go new file mode 100644 index 00000000..37d1a444 --- /dev/null +++ b/phc/unix/linux_s390x.go @@ -0,0 +1,24 @@ +//go:build s390x && linux + +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unix + +type ifreq struct { + Ifrn [16]byte + Ifru [24]byte +} diff --git a/phc/unix/linux_sparc64.go b/phc/unix/linux_sparc64.go new file mode 100644 index 00000000..c69b7839 --- /dev/null +++ b/phc/unix/linux_sparc64.go @@ -0,0 +1,24 @@ +//go:build sparc64 && linux + +/* +Copyright (c) Facebook, Inc. and its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unix + +type ifreq struct { + Ifrn [16]byte + Ifru [24]byte +}