Timestamp ausgehende Pakete
Ich versuche, präzise Zeitstempel für die ausgehenden Pakete (gesendet mit raw-sockets). Nach Linux/Documentation/networking/timestamping.txt
, "Für sende-Zeitstempel des ausgehenden Pakete werden geloopt zurück an den socket error-queue mit dem sende-Zeitstempel(s) befestigt ist. Es kann empfangen werden, mit recvmsg(flags=MSG_ERRQUEUE).".
Leider recvmsg
ist immer wiederkehrenden -1
wenn man auf einem raw-socket (erstellt mit socket(PF_INET, SOCK_RAW, IPPROTO_RAW)
und mit SO_TIMESTAMP
eingestellt 1
mit setsockopt
). Was mache ich falsch? Gibt es einen besseren Weg, um eine genaue Zeitstempel für eine ausgehende Paket?
Nachtrag (Informationen):
Ich auch versucht, immer den timestamp aus aus einem gesendeten Paket durch einen UDP-socket (Quellcode unten) und recvmsg
zurück -1
: der Fehler "Resource temporarily unavailable" (EAGAIN
).
Nachtrag (source-code):
#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;
}
- erhalten Sie verschiedene timing-wenn Sie SOCK_STREAM?
- btw ich benutze setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); zu deaktivieren Nagel-Algorithmus. Ich denke, Sie sollten das auch tun. Aber ich Frage mich, wenn Sie können, verwenden Sie zwei setsockopt in einer Reihe?
- anscheinend kann man auch hinzufügen, die sockopt auf jeder Ebene, die Sie wollen, um echtes timing-ich denke, Sie würde SO_TIMESTAMP am IPPROTO_RAW Ebene
- Nicht das Lesen aus der error queue nicht blockierend? Ich nehme an, du bist immer EAGAIN, weil der Zeitstempel ist noch nicht bereit, wenn Sie anrufen recvmsg(). Vielleicht versuchen Sie es mit poll() und warten Sie, bis POLLERR.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Blick in den Linux-kernel source code fand ich, dass die Funktion dafür verantwortlich, dass die Nachricht mit dem Zeitstempel des Pakets auf die error queue wird
skb_tx_timestamp
. Diese Funktion soll aufgerufen werden, indem Sie den NIC-Treiber und leider, diee1000
Fahrer nicht nennen (es gibt eine ähnliche Funktion für die hardware-Zeitstempelung, aber das ist natürlich abhängig von der NIC-Treiber unterstützen es).Laut diese NetDev Diskussion vom letzten September, "keine Treiber ruft skb_tx_timestamp()" und "Sie müssen optimieren Sie Ihre NIC-Treiber zu spielen mit diesem TX-Zeitstempel". Nach dem hinzufügen eines Anrufs zu
skb_tx_timestamp
zue1000_xmit_frame
aufe1000_main.c
ich war in der Lage zu erhalten Zeitstempel für ausgehende Pakete (über einen UDP-socket). Ich war nicht in der Lage zu erhalten Zeitstempel für ausgehende Pakete auf einem RAW-socket, obwohl (ich bekomme immer nochEAGAIN
).Es ist schwer zu wissen, was Sie tun falsch ist, da wir nicht den code sehen.
Jedoch:
Die Dokumentation sagt, dass
SO_TIMESTAMP
ist für eingehende Pakete, währendSO_TIMESTAMPING
ist für ausgehende Pakete.Die kernel-Dokumentation enthält eine vollständige Beispiel, das könnte man als Basis verwenden - obwohl es die UDP verwenden, aber Sie sollten in der Lage sein zu justieren, um mit einem RAW-socket.
Siehe den linux-kernel Documentation/networking/timestamping/Zeitstempel.c
EDIT: Es scheint sende-Zeitstempel ist nicht universell unterstützt, siehe z.B. hier. Auch heute nur eine Handvoll nic-Treiber implementieren die software-Unterstützung und ein paar hardware-Unterstützung.
recvmsg
sagt mir "Resource temporarily unavailable").EAGAIN
mit den UDP-socket (aberselect
machte es Weg). Als raw-packet,select
Blöcke (kein timeout) und ja, die raw-packet macht es in der Draht (tcpdump zeigt Sie, und ich bekomme auch die Antworten).sock_tx_timestamp wird nur aufgerufen, für SOCK_DGRAM-sockets in der aktuellen kernel-code.
BTW, das Dokument Documentation/networking/timestamping/Zeitstempel.c ist nicht sehr genau.
SO_TIMESTAMP /SO_TIMESTAMPNS /SO_TIMESTAMPING /SIOCGSTAMP /SIOCGSTAMPNS ähnlich sind. Jeder von Ihnen ermöglicht die Anwendung immer der Zeitstempel des empfangenen Pakets.
Mit SOF_TIMESTAMPING_TX_SOFTWARE, eine der oben genannten Optionen wird auch die Anwendung einer CMSG in MSG_ERRQUEUE, zeigt den Zeitstempel des gesendeten Pakets.
Aber SOF_TIMESTAMPING_RX_SOFTWARE ist nutzlos überhaupt. Es kann auch nicht genutzt werden zu deaktivieren, die Meldung Zeitstempel der empfangenen Pakete.
Ich denke, Sie haben zu schweigen von den timestamping-Flagge als
Und auch Sie haben zu prüfen, die strerror für alle system-aufrufen, bevor man die Daten aus dem msg-queue-Fehler. Dies wird Ihnen helfen, um loszuwerden off der EAGAIN Nachricht.