时间戳传出数据包 [英] Timestamp outgoing packets

查看:16
本文介绍了时间戳传出数据包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试获取传出数据包的准确时间戳(使用原始套接字发送).根据 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 在原始套接字(使用 socket(PF_INET, SOCK_RAW, IPPROTO_RAW)SO_TIMESTAMP 设置为 1setsockopt).我究竟做错了什么?有没有更好的方法来获取传出数据包的准确时间戳?

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, &timestamp_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.这个函数应该是由网卡驱动调用的,不幸的是,e1000 驱动没有调用它(硬件时间戳也有类似的函数,但这显然取决于支持它的网卡驱动).

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 时间戳".在 e1000_main.c 上添加对 skb_tx_timestampe1000_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆