![Linux 内核如何存储硬件 TX 和 RX 过滤模式?](https://linux22.com/image/230235/Linux%20%E5%86%85%E6%A0%B8%E5%A6%82%E4%BD%95%E5%AD%98%E5%82%A8%E7%A1%AC%E4%BB%B6%20TX%20%E5%92%8C%20RX%20%E8%BF%87%E6%BB%A4%E6%A8%A1%E5%BC%8F%EF%BC%9F.png)
我正在开发一个 C 程序,它获取给定网络接口的时间戳信息,就像我自己的 ethtool 版本一样。我的目标是获得打印的信息$ ethtool -T myNetIf
。就像是:
Time stamping parameters for myNetIf:
Capabilities:
hardware-transmit (SOF_TIMESTAMPING_TX_HARDWARE)
software-transmit (SOF_TIMESTAMPING_TX_SOFTWARE)
hardware-receive (SOF_TIMESTAMPING_RX_HARDWARE)
software-receive (SOF_TIMESTAMPING_RX_SOFTWARE)
software-system-clock (SOF_TIMESTAMPING_SOFTWARE)
hardware-raw-clock (SOF_TIMESTAMPING_RAW_HARDWARE)
PTP Hardware Clock: 0
Hardware Transmit Timestamp Modes:
off (HWTSTAMP_TX_OFF)
on (HWTSTAMP_TX_ON)
Hardware Receive Filter Modes:
none (HWTSTAMP_FILTER_NONE)
all (HWTSTAMP_FILTER_ALL)
由于我不想只抓取命令行输出,因此我发现可以使用调用ioctl
从 ethtool 查询此信息,并将我的标志作为无符号整数取回。
struct ifreq ifr;
memset(&ifr, 0, sizeof(struct ifreq));
struct ethtool_ts_info etsi;
memset(&etsi, 0, sizeof(struct ethtool_ts_info));
etsi.cmd = ETHTOOL_GET_TS_INFO;
strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); // dev is read from stdin
ifr.ifr_data = (void *)&etsi;
ioctl(sock, SIOCETHTOOL, &ifr); // sock is an AF_INET socket
ethtool_ts_info
(我相信)包含我想要的数据的结构已定义这里。具体来说,我抓取so_timestamping
、tx_types
和rx_filters
字段。
so_timestamping
使用相同的示例界面,的值为0x5f
, 或0101 1111
。一看net_tstamp.h
证实这些是预期的标志。
然而,我的问题是解释tx_types
和的值rx_filters
。我假设 的值tx_types
类似于0x3
( 0011
,其中第三位是 HWTSTAMP_TX_ON,第四位是 HWTSTAMP_TX_OFF)。或者,由于可能的传输模式定义在一个枚举如果有 4 个值,结果可能是0100
,其中每个int
枚举值都是 2 位。
不是这种情况。tx_types
的实际值为0x7fdd
。我究竟应该如何从 获得“HW_TX_OFF 和 ON” 0x7fdd
?我发现rx_filters
更令人困惑的价值。应该是什么0x664758eb
意思?
除了内核源代码本身之外,我还没有找到太多有用的信息。我认为我做的一切都是正确的,我只是需要一些帮助来理解我的结果。
答案1
这很尴尬:我检查了我的代码,发现我确实未能正确初始化结构,只是与我预期的方式不同。我也没有提供解决问题所需的完整上下文,因为我认为我已经排除了分配之前留下的垃圾值的可能性。
我发布的示例代码是函数的一部分,该函数填充我定义的包含ethtool_ts_info
.
typedef struct {
unsigned int soTimestamping;
unsigned int txTypes;
unsigned int rxFilters;
} tsCapsFilters_t;
函数的用户自己初始化这个结构,函数只是填充它。所以预期的用法如下:
tsCapsFilters_t tsInfo; // struct full of junk
if(getTsInfo(nameOfNetIf, &tsInfo, errMsgBuf, ERR_BUF_SZ) < 0) {
// handle errors in here
}
printf("%x\n", tsInfo.soTimestamping); // struct filled out by getTsInfo
然而,我犯的错误是我忘记将tx_types
andrx_filters
从ethtool_ts_info
结构(我的函数内部)复制到tsCapsFilters_t
结构(提供给用户)。所以我的程序很好地获取了所有字段,但它只so_timestamping
在应该返回所有 3 个值时才返回功能。
printf("%x\n", tsInfo.soTimestamping); // printed the expected values
printf("%x\n", tsInfo.txTypes); // printed junk
printf("%x\n", tsInfo.rxFilters); // printed junk
就像我说的,尴尬。我将给予赏金,并在未来更加小心我的结构。
答案2
struct ethtool_ts_info etsi;
…
ifr.ifr_data = (void *)&etsi;
来自网络时间戳的内核文档,我知道您的程序调用的 ioctl(SIOCSHWTSTAMP) 应该填充该类型的某些结构hwtstamp_config
被struct hwtstamp_config
定义为:
struct hwtstamp_config {
int flags; /* no flags defined right now, must be zero */
int tx_type; /* HWTSTAMP_TX_* */
int rx_filter; /* HWTSTAMP_FILTER_* */
};
通过使用指向 struct ifreq 的指针调用 ioctl(SIOCSHWTSTAMP),将所需的行为传递到内核和特定设备其 ifr_data 指向 struct hwtstamp_config...任何进程都可以通过以相同的方式将此结构传递给 ioctl(SIOCGHWTSTAMP) 来读取实际配置。
当您的程序使用返回的数据时,就好像它被struct ethtool_ts_info
定义为:
struct ethtool_ts_info {
__u32 cmd;
__u32 so_timestamping;
__s32 phc_index;
__u32 tx_types;
__u32 tx_reserved[3];
__u32 rx_filters;
__u32 rx_reserved[3];
};
这意味着您的程序将提取超出第三个 int 的值(特别是交易类型和rx_filters您感兴趣的)只是,正如您所报告的那样,……无意义的。
这 (配置即不是能力)值交易类型和rx_filters应分别从 ifr.ifr_data 地址开始在第二个和第三个 int 处获取。
在这种情况下,配置值不是您想要的,ioctl-ing(SIOCGHWTSTAMP) 不是合适的方法。