I am exercising Linux timestamping functionality (TX part): https://docs.kernel.org/networking/timestamping.html
It looks like there is no easy way to understand that the system will never provide me with TX timestamps at runtime. It means that I can enable TX timestamping via setsockopt
without an error:
int val = SOF_TIMESTAMPING_TX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_OPT_ID; int rc = setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &val, sizeof(val)); assert(rc == 0);
even on a system which does not support TX timestamps at all.
And then I can recheck that these options are applied:
int val = 0; socklen_t len = sizeof(val); int rc = getsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &val, &len); assert(rc == 0); assert(val == SOF_TIMESTAMPING_TX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_OPT_ID);
But the real behavior is that no messages are generated for MSG_ERRQUEUE
(TX timestamps are reported via this mechanism).
I know that the only way to understand if a system is capable of particular kind of timestamping is to execute sudo ethtool -T IFNAME
.
For example, for one of my system the result is:
Time stamping parameters for lo: Capabilities: software-receive (SOF_TIMESTAMPING_RX_SOFTWARE) software-system-clock (SOF_TIMESTAMPING_SOFTWARE) PTP Hardware Clock: none Hardware Transmit Timestamp Modes: none Hardware Receive Filter Modes: none
But I cannot rely on ethtool
in my code as it’s a separate utility which requires sudo
priveleges.
Any idea how to learn that TX timestamps are not available?
Advertisement
Answer
You should be able to do this through the SIOCETHTOOL
ioctl, using the ETHTOOL_GET_TS_INFO
command, which does not require root privileges. The socket to run the ioctl
on can be any kind of network socket.
There is also a netlink interface for this, but that’s more complex and I am not familiar with it.
The ethtool
command line tool uses one of the above two options depending on what is available on your kernel, and AFAICT it does not require privileges (runs fine on my machine without sudo
).
Here’s a working example:
#include <stdio.h> #include <stdint.h> #include <string.h> #include <err.h> #include <sys/ioctl.h> #include <net/if.h> #include <linux/ethtool.h> #include <linux/sockios.h> #include <linux/net_tstamp.h> int main(int argc, char **argv) { struct ethtool_ts_info info = { .cmd = ETHTOOL_GET_TS_INFO }; struct ifreq ifr = { .ifr_data = (void *)&info }; if (argc != 2) { fprintf(stderr, "Usage: %s INTERFACEn", argv[0] ? argv[0] : "tool"); return 1; } if (strlen(argv[1]) >= IF_NAMESIZE) { fputs("Interface name too long!n", stderr); return 1; } strcpy(ifr.ifr_name, argv[1]); int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) err(1, "socket"); if (ioctl(fd, SIOCETHTOOL, &ifr) != 0) err(1, "ioctl"); uint32_t ts = info.so_timestamping; if (ts & SOF_TIMESTAMPING_TX_HARDWARE) printf("Hardware TX timestamping available on %s.n", ifr.ifr_name); if (ts & SOF_TIMESTAMPING_TX_SOFTWARE) printf("Software TX timestamping available on %s.n", ifr.ifr_name); return 0; }
Output on my machine:
$ ./tool enp4s0 Hardware TX timestamping available on enp4s0. Software TX timestamping available on enp4s0.