source: test/test-live.c @ cac1d92

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivendag_formatrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since cac1d92 was cac1d92, checked in by Shane Alcock <salcock@…>, 4 years ago

Fix incorrectly reported test failures in test-live

test-live was not taking the smaller test-size into account when
evaluating whether tests where pcapint was the source had
succeeded. Therefore they would report as failed because the
other end had only received 30 packets instead of 100, but
the pcapint source was set to only send 30 packets in the first
place!

  • Property mode set to 100644
File size: 10.1 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007 The University of Waikato, Hamilton, New Zealand.
5 * Authors: Richard Sanger
6 *         
7 * All rights reserved.
8 *
9 * This code has been developed by the University of Waikato WAND
10 * research group. For further information please see http://www.wand.net.nz/
11 *
12 * libtrace is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * libtrace is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with libtrace; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25 *
26 * $Id$
27 *
28 */
29
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <assert.h>
34#include <string.h>
35#include <sys/time.h>
36#include <sys/types.h>
37#include <time.h>
38#include <math.h>
39#include <signal.h>
40#include <unistd.h>
41#include <stdint.h>
42#include <netinet/in.h>
43#include <netinet/in_systm.h>
44#include <netinet/tcp.h>
45#include <netinet/ip.h>
46#include <netinet/ip_icmp.h>
47#include <arpa/inet.h>
48#include <sys/socket.h>
49#include "dagformat.h"
50#include "libtrace.h"
51
52
53#define ONCE(run_me) { \
54        static int hit = 0; \
55        if (!hit) { \
56                run_me \
57        } \
58        hit = 1; \
59}
60
61#define ERROR(mesg, ...) { \
62        ONCE( \
63                err = 1; \
64                fprintf(stderr, "%s[%d] Error: " mesg, uri_read, i, __VA_ARGS__); \
65        ) \
66}
67
68static const char *uri_read;
69static sig_atomic_t i = 0;
70static sig_atomic_t reading = 0;
71static libtrace_t *trace_read;
72static int test_size = 100;
73
74static const char *lookup_uri_write(const char *type)
75{
76        if (!strcmp(type, "int"))
77                return "int:veth0";
78        if (!strcmp(type, "ring"))
79                return "ring:veth0";
80        if (!strcmp(type, "pcapint"))
81                return "pcapint:veth0";
82        if (!strncmp(type, "dpdk:", sizeof("dpdk:")))
83                return type;
84        return "unknown";
85}
86
87static const char *lookup_uri_read(const char *type)
88{
89        if (!strcmp(type, "int"))
90                return "int:veth1";
91        if (!strcmp(type, "ring"))
92                return "ring:veth1";
93        if (!strcmp(type, "pcapint")) {
94                // The newer Linux memmap (ring:) implementation of PCAP only makes
95                // space for about 30 maybe 31 packet buffers. If we exceeded this we'll
96                // drop packets.
97                test_size = 30; 
98                return "pcapint:veth1";
99        }
100        if (!strncmp(type, "dpdk:", sizeof("dpdk:")))
101                return type;
102        return "unknown";
103}
104
105
106/**
107 * Source packet we modify this every write see build_packet
108 */
109static unsigned char buffer[] = {
110        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, /* Dest Mac */
111        0x00, 0x01, 0x02, 0x03, 0x04, 0x06, /* Src Mac */
112        0x01, 0x01, /* Ethertype = Experimental */
113        0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, /* payload */
114};
115
116
117union uint32_char {
118        char chars[4];
119        uint32_t i32;
120};
121
122/* Build a unique packet from a seed value of i */
123static void build_packet(int i)
124{
125        // Shh about them type-punned aliasing issues
126        union uint32_char u;
127        srand(i);
128        u.i32 = (uint32_t) rand();
129        buffer[sizeof(libtrace_ether_t)] = u.chars[0];
130        buffer[sizeof(libtrace_ether_t)+1] = u.chars[1];
131        buffer[sizeof(libtrace_ether_t)+2] = u.chars[2];
132        buffer[sizeof(libtrace_ether_t)+3] = u.chars[3];
133}
134
135static void dumparray(unsigned char *arr, size_t len)
136{
137        size_t i;
138
139        fprintf(stderr, "{");
140        for (i = 0; i < len; ++i) {
141                fprintf(stderr, "0x%02X,", arr[i]);
142        }
143        fprintf(stderr, "}\n");
144}
145
146/**
147 * Verifies statistic counters at the end of the trace
148 */
149static int verify_counters(libtrace_t *trace_read)
150{
151        int err = 0;
152        libtrace_stat_t *stat;
153
154        stat = trace_create_statistics();
155
156        trace_get_statistics(trace_read, stat);
157        // Assume no loss here, if not the case we would of hung in reading loop
158        // anyway
159        if (!stat->dropped_valid) {
160                printf("\tInfo: trace does not support drop counter\n");
161        } else if (stat->dropped != 0) {
162                ERROR("Trace dropped %zu packets\n", stat->dropped);
163        }
164
165        if (!stat->filtered_valid) {
166                printf("\tInfo: trace does not support filter counter\n");
167        } else if (stat->filtered != 0) {
168                ERROR("Trace filtered %zu packets\n", stat->filtered);
169        }
170
171        if (!stat->received_valid) {
172                printf("\tInfo: trace does not support received counter\n");
173        } else if (stat->received != (uint32_t) test_size) {
174                ERROR("Trace received %zu/%u packets\n", stat->received,
175                                (uint32_t)test_size);
176        }
177
178        if (!stat->accepted_valid) {
179                printf("\tInfo: trace does not support accepted counter\n");
180        } else if (stat->accepted != (uint32_t) test_size) {
181                ERROR("Trace only accepted %zu/%u packets\n", stat->accepted,
182                                (uint32_t)test_size);
183        }
184
185        return err;
186}
187
188static void signal_handler(int signal)
189{
190        if (signal == SIGALRM) {
191                if (reading) {
192                        verify_counters(trace_read);
193                        fprintf(stderr, "!!!Timeout after reading only %d packets of %d!!!\n", i, test_size);
194                } else {
195                        fprintf(stderr, "!!!Timeout after writing only %d packets of %d!!!\n", i, test_size);
196                }
197                exit(-1);
198        }
199}
200
201/**
202 * Verifies a packet matches with what we expected
203 */
204static int verify_packet(libtrace_packet_t *packet, int seq_num)
205{
206        int err = 0;
207        static int caplen_incld_crc = -1;
208        static double ts = -1;
209        libtrace_linktype_t linktype;
210        uint32_t remaining;
211        unsigned char* pktbuffer;
212
213        // Verify wirelen - Wirelen includes checksum of 4 bytes
214        if (trace_get_wire_length(packet) != sizeof(buffer) + 4) {
215                ERROR("Incorrect trace_get_wire_length(), read %zu expected %zu\n",
216                                trace_get_wire_length(packet), sizeof(buffer) + 4);
217        }
218
219        // Verify caplen
220        if (trace_get_capture_length(packet) == sizeof(buffer)) {
221                if (caplen_incld_crc == 1) {
222                        ERROR("Expected trace_get_capture_length() to EXCLUDE the Ethernet checksum,"
223                                " read %zu expected %zu\n", trace_get_capture_length(packet),
224                                sizeof(buffer));
225                } else {
226                        caplen_incld_crc = 0;
227                }
228        } else if (trace_get_capture_length(packet) == sizeof(buffer) + 4) {
229                if (caplen_incld_crc == 0) {
230                        ERROR("Expected trace_get_capture_length() to INCLUDE the Ethernet checksum,"
231                                " read %zu expected %zu\n", trace_get_capture_length(packet),
232                                sizeof(buffer)+4);
233                } else {
234                        caplen_incld_crc = 1;
235                }
236        } else {
237                ERROR("Incorrect trace_get_capture_length(), read %zu expected %zu (or %zu)\n",
238                        trace_get_capture_length(packet), sizeof(buffer), sizeof(buffer)+4);
239        }
240
241        // Verify a packets contents
242        pktbuffer = trace_get_packet_buffer(packet, &linktype, &remaining);
243        assert(trace_get_capture_length(packet) == remaining);
244        assert(linktype == TRACE_TYPE_ETH);
245        // Refill the buffer with the expected data
246        build_packet(seq_num);
247        if (memcmp(pktbuffer, buffer, MIN(sizeof(buffer), remaining)) != 0) {
248                ERROR("Packet contents do not match\n%s", "Received:\n");
249                ONCE(
250                dumparray(pktbuffer, remaining);
251                fprintf(stderr, "Expected:\n");
252                dumparray(buffer, sizeof(buffer));
253                )
254        }
255
256        // Check times count up like we'd expect
257        if (ts != 1 && trace_get_seconds(packet) < ts) {
258                ERROR("Timestamps aren't increasing, ts=%f last_ts=%f\n",
259                        trace_get_seconds(packet), ts);
260        }
261
262        ts = trace_get_seconds(packet);
263
264        // Verify trace_get and set direction work
265        libtrace_direction_t dir_set;
266        if ((dir_set = trace_set_direction(packet, TRACE_DIR_OUTGOING)) != -1) {
267                if (trace_get_direction(packet) != TRACE_DIR_OUTGOING) {
268                        ERROR("Trace lies about its ability to set TRACE_DIR_OUTGOING,"
269                                "read %d expected %d\n", trace_get_direction(packet),
270                                TRACE_DIR_OUTGOING);
271                }
272        }
273        if ((dir_set = trace_set_direction(packet, TRACE_DIR_INCOMING)) != -1) {
274                if (trace_get_direction(packet) != TRACE_DIR_INCOMING) {
275                        ERROR("Trace lies about its ability to set TRACE_DIR_INCOMING,"
276                                "read %d expected %d\n", trace_get_direction(packet),
277                                TRACE_DIR_INCOMING);
278                }
279        }
280        if ((dir_set = trace_set_direction(packet, TRACE_DIR_OTHER)) != -1) {
281                if (trace_get_direction(packet) != TRACE_DIR_OTHER) {
282                        ERROR("Trace lies about its ability to set TRACE_DIR_OTHER,"
283                                "read %d expected %d\n", trace_get_direction(packet),
284                                TRACE_DIR_OTHER);
285                }
286        }
287        if ((dir_set = trace_set_direction(packet, TRACE_DIR_UNKNOWN)) != -1) {
288                if (trace_get_direction(packet) != TRACE_DIR_UNKNOWN) {
289                        ERROR("Trace lies about its ability to set TRACE_DIR_UNKNOWN,"
290                                "read %d expected %d\n", trace_get_direction(packet),
291                                TRACE_DIR_UNKNOWN);
292                }
293        }
294        return err;
295}
296
297static void iferr_out(libtrace_out_t *trace)
298{
299        libtrace_err_t err = trace_get_err_output(trace);
300        if (err.err_num == 0)
301                return;
302        printf("Error: %s\n", err.problem);
303        exit(1);
304}
305
306static void iferr(libtrace_t *trace)
307{
308        libtrace_err_t err = trace_get_err(trace);
309        if (err.err_num == 0)
310                return;
311        printf("Error: %s\n", err.problem);
312        exit(1);
313}
314
315int main(int argc, char *argv[])
316{
317        libtrace_out_t *trace_write;
318        libtrace_packet_t *packet;
319        int psize;
320        int err = 0;
321
322        if (argc < 3) {
323                fprintf(stderr, "usage: %s type(write) type(read)\n", argv[0]);
324                return 1;
325        }
326
327        signal(SIGALRM, signal_handler);
328        // Timeout after 5 seconds
329        alarm(5);
330
331        trace_write = trace_create_output(lookup_uri_write(argv[1]));
332        iferr_out(trace_write);
333        uri_read = lookup_uri_read(argv[2]);
334        trace_read = trace_create(uri_read);
335        iferr(trace_read);
336
337        trace_start_output(trace_write);
338        iferr_out(trace_write);
339        trace_start(trace_read);
340        iferr(trace_read);
341
342        packet = trace_create_packet();
343
344        // Write out test_size (100) almost identical packets
345        for (i = 0; i < test_size; i++) {
346                build_packet(i);
347                trace_construct_packet(packet, TRACE_TYPE_ETH, buffer, sizeof(buffer));
348                if (trace_write_packet(trace_write, packet) == -1) {
349                        iferr_out(trace_write);
350                }
351        }
352        trace_destroy_packet(packet);
353        trace_destroy_output(trace_write);
354
355        // Now read back in, we assume that buffers internally can buffer
356        // the packets without losing them
357        packet = trace_create_packet();
358
359        reading = 1;
360        for (i = 0; i < test_size; i++) {
361                if ((psize = trace_read_packet(trace_read, packet)) < 0) {
362                        iferr(trace_read);
363                        // EOF we shouldn't hit this with a live format
364                        fprintf(stderr, "Error: looks like we lost some packets!\n");
365                        err = 1;
366                        break;
367                }
368                err |= verify_packet(packet, i);
369        }
370
371        err |= verify_counters(trace_read);
372
373        trace_destroy_packet(packet);
374        trace_destroy(trace_read);
375
376        return err;
377}
Note: See TracBrowser for help on using the repository browser.