时间戳输出数据包 [英] Timestamp outgoing packets
问题描述
我正在尝试为传出数据包(使用原始套接字发送)获取准确的时间戳.根据 Linux/Documentation/networking/timestamping.txt
,对于发送时间戳,传出的数据包将在附加了发送时间戳的情况下循环回到套接字的错误队列.可以使用recvmsg(flags = MSG_ERRQUEUE)进行接收.".
I'm trying to get accurate timestamps for outgoing packets (sent using raw sockets). According to Linux/Documentation/networking/timestamping.txt
, "For send time stamps the outgoing packet is looped back to the socket's error queue with the send time stamp(s) attached. It can be received with recvmsg(flags=MSG_ERRQUEUE).".
不幸的是,在原始套接字上调用时,recvmsg
总是返回-1
(使用socket(PF_INET, SOCK_RAW, IPPROTO_RAW)
创建,并且将SO_TIMESTAMP
设置为1
并使用setsockopt
创建).我究竟做错了什么?是否有更好的方法来获取传出数据包的准确时间戳?
Unfortunately, recvmsg
is always returning -1
when called on a raw socket (created with socket(PF_INET, SOCK_RAW, IPPROTO_RAW)
and with SO_TIMESTAMP
set to 1
with setsockopt
). What am I doing wrong? Is there a better way of getting an accurate timestamp for an outgoing packet?
附录(信息):
我还尝试从通过UDP套接字发送的数据包中获取时间戳(以下源代码),并且recvmsg
返回-1
:错误是资源暂时不可用"(EAGAIN
).
I also tried getting the timestamp from a packet sent through an UDP socket (source code below) and recvmsg
returns -1
: the error is "Resource temporarily unavailable" (EAGAIN
).
附录(源代码):
#include <arpa/inet.h>
#include <linux/net_tstamp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
void die(char* s)
{
perror(s);
exit(1);
}
int main(int argc, char* argv[])
{
char* destination_ip = "10.0.0.1";
int destination_port = 1234;
int sock;
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
die("socket()");
}
int timestamp_flags = SOF_TIMESTAMPING_TX_SOFTWARE;
if (setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, ×tamp_flags, sizeof(timestamp_flags)) < 0) {
die("setsockopt()");
}
struct sockaddr_in si_server;
memset(&si_server, 0, sizeof(si_server));
si_server.sin_family = AF_INET;
si_server.sin_port = htons(destination_port);
if (inet_aton(destination_ip, &si_server.sin_addr) == 0) {
die("inet_aton()");
}
const int buffer_len = 256;
char buffer[buffer_len];
const int n_packets = 10;
for (int i = 0; i < n_packets; ++i) {
sprintf(buffer, "Packet %d", i);
if (sendto(sock, buffer, buffer_len, 0, (const sockaddr*) &si_server, sizeof(si_server)) < 0) {
die("sendto()");
}
// Obtain the sent packet timestamp.
char data[256];
struct msghdr msg;
struct iovec entry;
struct sockaddr_in from_addr;
struct {
struct cmsghdr cm;
char control[512];
} control;
int res;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &entry;
msg.msg_iovlen = 1;
entry.iov_base = data;
entry.iov_len = sizeof(data);
msg.msg_name = (caddr_t)&from_addr;
msg.msg_namelen = sizeof(from_addr);
msg.msg_control = &control;
msg.msg_controllen = sizeof(control);
if (recvmsg(sock, &msg, MSG_ERRQUEUE) < 0) {
die("recvmsg()");
}
}
return 0;
}
推荐答案
查看Linux内核源代码,我发现负责将包含数据包时间戳的消息放入错误队列的函数为skb_tx_timestamp
.该功能应该由NIC驱动程序调用,但不幸的是,e1000
驱动程序没有调用它(硬件时间戳的功能与此类似,但这显然取决于支持它的NIC驱动程序).
Looking into the Linux kernel source code, I found that the function responsible for putting the message containing the timestamp of the packet on the error queue is skb_tx_timestamp
. This function is supposed to be called by the NIC driver and unfortunately, the e1000
driver doesn't call it (there's a similar function for hardware timestamping, but this is obviously dependent on the NIC driver supporting it).
根据去年9月的此NetDev讨论,没有驱动程序调用skb_tx_timestamp()"和您需要调整NIC驱动程序以使用此TX时间戳记."将对skb_tx_timestamp
的调用添加到e1000_main.c
上的e1000_xmit_frame
之后,我能够获取传出数据包的时间戳(通过UDP套接字).但是,我无法获得RAW套接字上传出数据包的时间戳(我仍然会得到EAGAIN
).
According to this NetDev discussion from last September, "no driver calls skb_tx_timestamp()" and "You'll need to tweak your NIC driver to play with this TX timestamps". After adding a call to skb_tx_timestamp
to e1000_xmit_frame
on e1000_main.c
, I was able to obtain timestamps for outgoing packets (through an UDP socket). I wasn't able to obtain timestamps for outgoing packets on a RAW socket, though (I still get EAGAIN
).
这篇关于时间戳输出数据包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!