10

送信パケット(rawソケットを使用して送信)の正確なタイムスタンプを取得しようとしています。によるとLinux/Documentation/networking/timestamping.txt、「送信タイムスタンプの場合、送信パケットは送信タイムスタンプが添付された状態でソケットのエラーキューにループバックされます。recvmsg(flags = MSG_ERRQUEUE)で受信できます。」

残念ながら、rawソケット(で作成され、withに設定されている)で呼び出されると、recvmsg常に戻ります。私は何が間違っているのですか?発信パケットの正確なタイムスタンプを取得するためのより良い方法はありますか?-1socket(PF_INET, SOCK_RAW, IPPROTO_RAW)SO_TIMESTAMP1setsockopt

補遺(情報):

また、UDPソケット(以下のソースコード)を介して送信されたパケットからタイムスタンプを取得しようとしましたがrecvmsg-1エラーは「リソースが一時的に利用できません」(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;
}
4

4 に答える 4

10

Linuxカーネルのソースコードを調べたところ、パケットのタイムスタンプを含むメッセージをエラーキューに入れる機能はであることがわかりましたskb_tx_timestamp。この関数はNICドライバーによって呼び出されることになっていますが、残念ながら、e1000ドライバーはそれを呼び出しません(ハードウェアのタイムスタンプについても同様の関数がありますが、これは明らかにそれをサポートするNICドライバーに依存します)。

昨年9月のこのNetDevの議論によると、「ドライバーはskb_tx_timestamp()を呼び出さない」、「このTXタイムスタンプで遊ぶにはNICドライバーを微調整する必要がある」とのことです。skb_tx_timestampto e1000_xmit_frameonへの呼び出しを追加した後、e1000_main.c(UDPソケットを介して)発信パケットのタイムスタンプを取得できました。ただし、RAWソケットで送信パケットのタイムスタンプを取得できませんでした(まだ取得していますEAGAIN)。

于 2012-07-31T19:21:48.297 に答える
5

私たちはあなたのコードを見ることができないので、あなたが間違っていることを知るのは難しいです。

ただし、ドキュメントには、これSO_TIMESTAMPは着信パケット用であり、SO_TIMESTAMPINGは発信パケット用であると記載されています。

カーネルのドキュメントには、UDPを使用していますが、ベースとして使用できる完全な例が含まれていますが、RAWソケットを使用するように調整できるはずです。LinuxカーネルのDocumentation/network / timestamping/timestamping.cを参照してください。

編集:送信タイムスタンプは普遍的にサポートされていないようです。たとえば、ここを参照してください。今日でも、ほんの一握りのNICドライバーがソフトウェアサポートを実装しており、ハードウェアサポートを備えているものもあります。

于 2012-07-31T00:34:34.940 に答える
2

sock_tx_timestampは、現在のカーネルコードのSOCK_DGRAMソケットに対してのみ呼び出されます。

ところで、ドキュメントDocumentation / network / timestamping/timestamping.cはあまり正確ではありません。

SO_TIMESTAMP / SO_TIMESTAMPNS / SO_TIMESTAMPING / SIOCGSTAMP/SIOCGSTAMPNSは類似しています。それらのいずれかを使用すると、アプリケーションは受信したパケットのタイムスタンプを取得できます。

SOF_TIMESTAMPING_TX_SOFTWAREを使用すると、上記のフラグのいずれかによって、アプリケーションにMSG_ERRQUEUEのCMSGが提供され、送信されたパケットのタイムスタンプが示されます。

しかし、SOF_TIMESTAMPING_RX_SOFTWAREはまったく役に立ちません。受信したパケットのタイムスタンプのレポートを無効にするために使用することもできません。

于 2014-05-29T06:10:12.503 に答える
0

タイムスタンプフラグについては、次のように言及する必要があると思います。

int timestamp_flags |= SOF_TIMESTAMPING_TX_SOFTWARE;
timestamp_flags |= SOF_TIMESTAMPING_SOFTWARE;

また、メッセージキューエラーからデータを取得する前に、すべてのシステムコールのstrerrorを確認する必要があります。これは、EAGAINメッセージを取り除くのに役立ちます。

于 2015-02-26T11:02:24.627 に答える