PERFORCE change 166971 for review
Fang Wang
fangwang at FreeBSD.org
Mon Aug 3 16:57:42 UTC 2009
http://perforce.freebsd.org/chv.cgi?CH=166971
Change 166971 by fangwang at fangwang_utobsd on 2009/08/03 16:56:52
Tcputo regression test code, use libpcap to capture the retransmission packets
Affected files ...
.. //depot/projects/soc2009/tcputo/src/tools/regression/netinet/tcputo/Makefile#3 edit
.. //depot/projects/soc2009/tcputo/src/tools/regression/netinet/tcputo/tcputo.c#5 edit
Differences ...
==== //depot/projects/soc2009/tcputo/src/tools/regression/netinet/tcputo/Makefile#3 (text+ko) ====
@@ -3,6 +3,7 @@
#
PROG= tcputo
+CFLAGS+= -lpcap -lpthread
NO_MAN=
.include <bsd.prog.mk>
==== //depot/projects/soc2009/tcputo/src/tools/regression/netinet/tcputo/tcputo.c#5 (text+ko) ====
@@ -29,8 +29,11 @@
#include <sys/types.h>
#include <sys/socket.h>
+#include <net/ethernet.h>
#include <netinet/in.h>
-#include <netinet/tcp.h>
+#include <netinet/ip.h>
+//#include <netinet/tcp.h>
+#include "tcp.h"
#include <arpa/inet.h>
@@ -41,16 +44,171 @@
#include <string.h>
#include <unistd.h>
#include <time.h>
+#include <signal.h>
+#include <pcap.h>
+#include <pthread.h>
+
static void
usage(void)
{
- fprintf(stderr, "tcpconnect server port [user timeout]\n");
- fprintf(stderr, "tcpconnect client ip port [user timeout]\n");
+ fprintf(stderr, "tcpconnect [-e] server port [user timeout]\n");
+ fprintf(stderr, "tcpconnect [-e] client ip port [user timeout]\n");
exit(-1);
}
+#define SIZE_ETHERNET sizeof(struct ether_header)
+
+struct tcprxt {
+ struct timeval ts;
+ u_int length;
+ u_int th_off;
+ tcp_seq th_seq;
+ tcp_seq th_ack;
+ u_char th_flags;
+};
+
+#define MAX_RXT 200
+
+struct tcprxt rxts[MAX_RXT];
+
+void
+parse_packet(u_char *args, const struct pcap_pkthdr *pkt_header, const u_char *packet)
+{
+ const struct ip *ip; /* The IP header */
+ const struct tcphdr *tcp; /* The TCP header */
+ const u_char *tcpopt; /* Tcp option */
+ struct tcprxt rxt;
+ u_int opt, optlen;
+ u_int hlen;
+ u_int length;
+
+ length = pkt_header->len - SIZE_ETHERNET;
+ ip = (struct ip *)(packet + SIZE_ETHERNET);
+ hlen = ip->ip_hl * 4;
+ length -= hlen;
+ if (hlen < 20) {
+ printf(" * Invalid IP header length: %u bytes\n", hlen);
+ return;
+ }
+ tcp = (struct tcphdr *)((u_char *)ip + hlen);
+ hlen = tcp->th_off * 4;
+ length -= hlen;
+ if (hlen < 20) {
+ printf(" * Invalid TCP header length: %u bytes\n", hlen);
+ return;
+ }
+ tcpopt = (u_char *)tcp + sizeof(*tcp);
+ hlen -= sizeof(*tcp);
+ while (hlen > 0) {
+ opt = *tcpopt++;
+ hlen--;
+ if (opt == TCPOPT_EOL)
+ break;
+ if (opt == TCPOPT_NOP)
+ continue;
+ optlen = *tcpopt++;
+ if (opt == TCPOPT_UTO) {
+ u_int uto = htons(*(u_short *)tcpopt);
+ if (uto & 1)
+ uto = (uto >> 1) * 60;
+ else
+ uto >>= 1;
+ printf("Time:%u.%u Seq:%u Ack:%u Win:%u Length:%u UTO:%u\n", pkt_header->ts.tv_sec, pkt_header->ts.tv_usec, htonl(tcp->th_seq), htonl(tcp->th_ack), htons(tcp->th_win), length, uto);
+ }
+ hlen -= optlen - 1;
+ tcpopt += optlen - 2;
+ }
+ if (length > 0 || tcp->th_flags & TH_RST) {
+ memset(&rxt, 0, sizeof(rxt));
+ memcpy(&rxt.ts, &pkt_header->ts, sizeof(rxt.ts));
+ rxt.length = length;
+ rxt.th_off = tcp->th_off;
+ rxt.th_ack = tcp->th_ack;
+ rxt.th_seq = tcp->th_seq;
+ rxt.th_flags = tcp->th_flags;
+ memcpy(&rxts[0], &rxts[1], sizeof(struct tcprxt) * (MAX_RXT - 1));
+ memcpy(&rxts[MAX_RXT - 1], &rxt, sizeof(rxt));
+ }
+}
+
+void
+dump_packet(void *arg)
+{
+ pcap_t *handle; /* Session handle */
+ char *dev; /* The device to sniff on */
+ //char dev[] = "le1"; /* The device to sniff on */
+ char errbuf[PCAP_ERRBUF_SIZE]; /* Error string */
+ struct bpf_program fp; /* The compiled filter */
+ char filter_exp[] = "tcp port 8000"; /* The filter expression */
+ bpf_u_int32 mask; /* Our netmask */
+ bpf_u_int32 net; /* Our IP */
+ struct pcap_pkthdr header; /* The header that pcap gives us */
+ const u_char *packet; /* The actual packet */
+
+ /* Define the device */
+ dev = pcap_lookupdev(errbuf);
+ if (dev == NULL) {
+ fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
+ exit(-1);
+ }
+ /* Find the properties for the device */
+ if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
+ fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);
+ net = 0;
+ mask = 0;
+ }
+ /* Open the session in promiscuous mode */
+ handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
+ if (handle == NULL) {
+ fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
+ exit(-1);
+ }
+ /* Compile and apply the filter */
+ if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
+ fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
+ exit(-1);
+ }
+ if (pcap_setfilter(handle, &fp) == -1) {
+ fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
+ exit(-1);
+ }
+ pcap_loop(handle, -1, parse_packet, NULL);
+ pcap_close(handle);
+}
+
+void print_result()
+{
+ tcp_seq rxt_seq;
+ int i, last, rxt_nr;
+ struct tm *p;
+
+ rxt_seq = rxts[MAX_RXT - 2].th_seq;
+ for (last = -1, rxt_nr = 0, i = 0; i < MAX_RXT; i++) {
+ if (rxts[i].th_seq == rxt_seq || rxts[i].th_flags & TH_RST) {
+ if (rxts[i].th_flags & TH_RST)
+ printf("reset packet, ");
+ else if (rxt_nr)
+ printf("retransmit %d, ", rxt_nr);
+ else if (!rxt_nr)
+ printf("send packet, ");
+ p = localtime(&rxts[i].ts.tv_sec);
+ printf("time %d:%d:%d.%-6u, ", p->tm_hour, p->tm_min, p->tm_sec, rxts[i].ts.tv_usec);
+ printf("seq %u, ack %u, ", rxts[i].th_seq, rxts[i].th_ack);
+ if (last != -1) {
+ if (rxts[i].ts.tv_usec < rxts[last].ts.tv_usec)
+ printf("interval %u.%-6u, ", rxts[i].ts.tv_sec - rxts[last].ts.tv_sec - 1, 1000000 + rxts[i].ts.tv_usec - rxts[last].ts.tv_usec);
+ else
+ printf("interval %u.%-6u, ", rxts[i].ts.tv_sec - rxts[last].ts.tv_sec, rxts[i].ts.tv_usec - rxts[last].ts.tv_usec);
+ }
+ printf("length %u\n", rxts[i].length);
+ last = i;
+ rxt_nr++;
+ }
+ }
+}
+
static int
tcputo_timer(void)
{
@@ -82,6 +240,7 @@
int user_timeout;
int optval;
struct tcputo uto;
+ pthread_t tid;
if (argc != 1 && argc != 2)
usage();
@@ -121,6 +280,8 @@
if (setsockopt(accept_sock, IPPROTO_TCP, TCP_UTO, &uto, sizeof(uto)) == -1)
err(-1, "setsockopt");
close(listen_sock);
+ if (pthread_create(&tid, NULL, dump_packet, NULL))
+ err(-1, "create thread");
while(1) {
sleep(1);
printf("server again %d\n", optval++);
@@ -130,12 +291,13 @@
(void)tcputo_timer();
continue;
}
- puts(strerror(errno));
user_timeout = tcputo_timer();
printf("Connection timeout, %d seconds.\n", user_timeout);
break;
}
-
+ /* wait for the reset packet to be captured */
+ sleep(1);
+ pthread_kill(tid, SIGTERM);
close(accept_sock);
}
@@ -150,6 +312,7 @@
int user_timeout;
int optval = 4*1024;
struct tcputo uto;
+ pthread_t tid;
if (argc != 2 && argc != 3)
usage();
@@ -179,7 +342,8 @@
}
if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) == -1)
err(-1, "connect");
-
+ if (pthread_create(&tid, NULL, dump_packet, NULL))
+ err(-1, "create thread");
while (1) {
sleep(1);
printf("client again %d\n", optval++);
@@ -189,19 +353,19 @@
(void)tcputo_timer();
continue;
}
- puts(strerror(errno));
user_timeout = tcputo_timer();
printf("Connection timeout, %d seconds.\n", user_timeout);
break;
}
-
+ /* wait for the reset packet to be captured */
+ sleep(1);
+ pthread_kill(tid, SIGTERM);
close(sock);
}
int
main(int argc, char *argv[])
{
-
if (argc < 2)
usage();
@@ -211,6 +375,6 @@
tcputo_client(argc - 2, argv + 2);
else
usage();
-
+ print_result();
exit(0);
}
More information about the p4-projects
mailing list