source: test/test-live.c @ 262a093

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivelibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 262a093 was 262a093, checked in by Richard Sanger <rsangerarj@…>, 6 years ago

Adds tests for the Live Linux formats, int: ring: and pcapint:

Launch from test/do-live-tests.sh (needs root)
Alternatively test/netns-env <command>, bash can be used here useful for debugging etc.

This runs tests in separate network namespace with two virtual adapters, this is isolated from the kernels influence so that the only traffic is that which we create.

  • test-live.c - Tests sending and receiving 100 packets from one format to another between to virtual ports
    • Tests read/write, wirelength, capturelength, packet order/integrity, timestamps, ability to set direction/snap lengths and trace statistics
  • test-live-snaplen.c Tests that snap length works correctly via trace_config(), does basic checks on the wire and capture lengths returned

Limitations

  • Doesn't support BSD yet
  • DPDK included but probably not working in master
  • Doesn't test BPF filters
  • Requires root to run

Found some existing issues :(, fixes to which will be in the following commits.

  • 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
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        // Assume no loss here, if not the case we would of hung in reading loop
153        // anyway
154        if (trace_get_dropped_packets(trace_read) != 0) {
155                if (trace_get_dropped_packets(trace_read) == UINT64_MAX) {
156                        printf("\tInfo: trace does not support drop counter\n");
157                } else {
158                        ERROR("Trace dropped %zu packets\n",
159                                trace_get_dropped_packets(trace_read));
160                }
161        }
162        if (trace_get_filtered_packets(trace_read) != 0) {
163                if (trace_get_filtered_packets(trace_read) == UINT64_MAX) {
164                        printf("\tInfo: trace does not support filter counter\n");
165                } else {
166                        ERROR("Trace dropped %zu packets\n",
167                                trace_get_filtered_packets(trace_read));
168                }
169        }
170        if (trace_get_received_packets(trace_read) != 0) {
171                if (trace_get_received_packets(trace_read) == UINT64_MAX) {
172                        printf("\tInfo: trace does not support received counter\n");
173                } else {
174                        ERROR("Trace received %zu packets\n",
175                                trace_get_received_packets(trace_read));
176                }
177        }
178        if (trace_get_accepted_packets(trace_read) != (size_t) test_size) {
179                // This would more likely be a libtrace issue rather than format specific
180                ERROR("Trace only accepted %zu packets\n",
181                        trace_get_accepted_packets(trace_read));
182        }
183        return err;
184}
185
186static void signal_handler(int signal)
187{
188        if (signal == SIGALRM) {
189                if (reading) {
190                        verify_counters(trace_read);
191                        fprintf(stderr, "!!!Timeout after reading only %d packets of %d!!!\n", i, test_size);
192                } else {
193                        fprintf(stderr, "!!!Timeout after writing only %d packets of %d!!!\n", i, test_size);
194                }
195                exit(-1);
196        }
197}
198
199/**
200 * Verifies a packet matches with what we expected
201 */
202static int verify_packet(libtrace_packet_t *packet, int seq_num)
203{
204        int err = 0;
205        static int caplen_incld_crc = -1;
206        static double ts = -1;
207        libtrace_linktype_t linktype;
208        uint32_t remaining;
209        unsigned char* pktbuffer;
210
211        // Verify wirelen - Wirelen includes checksum of 4 bytes
212        if (trace_get_wire_length(packet) != sizeof(buffer) + 4) {
213                ERROR("Incorrect trace_get_wire_length(), read %zu expected %zu\n",
214                                trace_get_wire_length(packet), sizeof(buffer) + 4);
215        }
216
217        // Verify caplen
218        if (trace_get_capture_length(packet) == sizeof(buffer)) {
219                if (caplen_incld_crc == 1) {
220                        ERROR("Expected trace_get_capture_length() to EXCLUDE the Ethernet checksum,"
221                                " read %zu expected %zu\n", trace_get_capture_length(packet),
222                                sizeof(buffer));
223                } else {
224                        caplen_incld_crc = 0;
225                }
226        } else if (trace_get_capture_length(packet) == sizeof(buffer) + 4) {
227                if (caplen_incld_crc == 0) {
228                        ERROR("Expected trace_get_capture_length() to INCLUDE the Ethernet checksum,"
229                                " read %zu expected %zu\n", trace_get_capture_length(packet),
230                                sizeof(buffer)+4);
231                } else {
232                        caplen_incld_crc = 1;
233                }
234        } else {
235                ERROR("Incorrect trace_get_capture_length(), read %zu expected %zu (or %zu)\n",
236                        trace_get_capture_length(packet), sizeof(buffer), sizeof(buffer)+4);
237        }
238
239        // Verify a packets contents
240        pktbuffer = trace_get_packet_buffer(packet, &linktype, &remaining);
241        assert(trace_get_capture_length(packet) == remaining);
242        assert(linktype == TRACE_TYPE_ETH);
243        // Refill the buffer with the expected data
244        build_packet(seq_num);
245        if (memcmp(pktbuffer, buffer, MIN(sizeof(buffer), remaining)) != 0) {
246                ERROR("Packet contents do not match\n%s", "Received:\n");
247                ONCE(
248                dumparray(pktbuffer, remaining);
249                fprintf(stderr, "Expected:\n");
250                dumparray(buffer, sizeof(buffer));
251                )
252        }
253
254        // Check times count up like we'd expect
255        if (ts != 1 && trace_get_seconds(packet) < ts) {
256                ERROR("Timestamps aren't increasing, ts=%f last_ts=%f\n",
257                        trace_get_seconds(packet), ts);
258        }
259
260        ts = trace_get_seconds(packet);
261
262        // Verify trace_get and set direction work
263        libtrace_direction_t dir_set;
264        if ((dir_set = trace_set_direction(packet, TRACE_DIR_OUTGOING)) != -1) {
265                if (trace_get_direction(packet) != TRACE_DIR_OUTGOING) {
266                        ERROR("Trace lies about its ability to set TRACE_DIR_OUTGOING,"
267                                "read %d expected %d\n", trace_get_direction(packet),
268                                TRACE_DIR_OUTGOING);
269                }
270        }
271        if ((dir_set = trace_set_direction(packet, TRACE_DIR_INCOMING)) != -1) {
272                if (trace_get_direction(packet) != TRACE_DIR_INCOMING) {
273                        ERROR("Trace lies about its ability to set TRACE_DIR_INCOMING,"
274                                "read %d expected %d\n", trace_get_direction(packet),
275                                TRACE_DIR_INCOMING);
276                }
277        }
278        if ((dir_set = trace_set_direction(packet, TRACE_DIR_OTHER)) != -1) {
279                if (trace_get_direction(packet) != TRACE_DIR_OTHER) {
280                        ERROR("Trace lies about its ability to set TRACE_DIR_OTHER,"
281                                "read %d expected %d\n", trace_get_direction(packet),
282                                TRACE_DIR_OTHER);
283                }
284        }
285        if ((dir_set = trace_set_direction(packet, TRACE_DIR_UNKNOWN)) != -1) {
286                if (trace_get_direction(packet) != TRACE_DIR_UNKNOWN) {
287                        ERROR("Trace lies about its ability to set TRACE_DIR_UNKNOWN,"
288                                "read %d expected %d\n", trace_get_direction(packet),
289                                TRACE_DIR_UNKNOWN);
290                }
291        }
292        return err;
293}
294
295static void iferr_out(libtrace_out_t *trace)
296{
297        libtrace_err_t err = trace_get_err_output(trace);
298        if (err.err_num == 0)
299                return;
300        printf("Error: %s\n", err.problem);
301        exit(1);
302}
303
304static void iferr(libtrace_t *trace)
305{
306        libtrace_err_t err = trace_get_err(trace);
307        if (err.err_num == 0)
308                return;
309        printf("Error: %s\n", err.problem);
310        exit(1);
311}
312
313int main(int argc, char *argv[])
314{
315        libtrace_out_t *trace_write;
316        libtrace_packet_t *packet;
317        int psize;
318        int err = 0;
319
320        if (argc < 3) {
321                fprintf(stderr, "usage: %s type(write) type(read)\n", argv[0]);
322                return 1;
323        }
324
325        signal(SIGALRM, signal_handler);
326        // Timeout after 5 seconds
327        alarm(5);
328
329        trace_write = trace_create_output(lookup_uri_write(argv[1]));
330        iferr_out(trace_write);
331        uri_read = lookup_uri_read(argv[2]);
332        trace_read = trace_create(uri_read);
333        iferr(trace_read);
334
335        trace_start_output(trace_write);
336        iferr_out(trace_write);
337        trace_start(trace_read);
338        iferr(trace_read);
339
340        packet = trace_create_packet();
341
342        // Write out test_size (100) almost identical packets
343        for (i = 0; i < test_size; i++) {
344                build_packet(i);
345                trace_construct_packet(packet, TRACE_TYPE_ETH, buffer, sizeof(buffer));
346                if (trace_write_packet(trace_write, packet) == -1) {
347                        iferr_out(trace_write);
348                }
349        }
350        trace_destroy_packet(packet);
351        trace_destroy_output(trace_write);
352
353        // Now read back in, we assume that buffers internally can buffer
354        // the packets without losing them
355        packet = trace_create_packet();
356
357        reading = 1;
358        for (i = 0; i < test_size; i++) {
359                if ((psize = trace_read_packet(trace_read, packet)) < 0) {
360                        iferr(trace_read);
361                        // EOF we shouldn't hit this with a live format
362                        fprintf(stderr, "Error: looks like we lost some packets!\n");
363                        err = 1;
364                        break;
365                }
366                err |= verify_packet(packet, i);
367        }
368
369        err |= verify_counters(trace_read);
370
371        trace_destroy_packet(packet);
372        trace_destroy(trace_read);
373
374        return err;
375}
Note: See TracBrowser for help on using the repository browser.