source: lib/format_dpdkndag.c @ d83ba86a

cachetimestampsdevelopdpdk-ndagetsiliverc-4.0.3rc-4.0.4ringdecrementfixringperformance
Last change on this file since d83ba86a was d83ba86a, checked in by Shane Alcock <salcock@…>, 3 years ago

Don't do string conversions and comparisons for every packet

Since the expected address is never going to change, it is a lot
more efficient to just convert that string to a sockaddr and
compare sockaddrs instead.

  • Property mode set to 100644
File size: 20.9 KB
Line 
1
2#include "config.h"
3#include "common.h"
4#include "libtrace.h"
5#include "libtrace_int.h"
6#include "format_helper.h"
7#include "format_erf.h"
8
9#include <assert.h>
10#include <errno.h>
11#include <fcntl.h>
12#include <stdio.h>
13#include <string.h>
14#include <unistd.h>
15#include <stdlib.h>
16#include <sys/types.h>
17#include <sys/socket.h>
18#include <netdb.h>
19
20#include "format_dpdk.h"
21#include "format_ndag.h"
22
23static struct libtrace_format_t dpdkndag;
24
25typedef struct capstream {
26
27        uint16_t port;
28        uint32_t expectedseq;
29        uint64_t recordcount;
30} capstream_t;
31
32typedef struct perthread {
33        capstream_t *capstreams;
34        uint16_t streamcount;
35        uint64_t dropped_upstream;
36        uint64_t missing_records;
37        uint64_t received_packets;
38
39        libtrace_packet_t *dpdkpkt;
40        char *ndagheader;
41        char *nextrec;
42        uint32_t ndagsize;
43
44        dpdk_per_stream_t *dpdkstreamdata;
45        int burstsize;
46        int burstoffset;
47        struct rte_mbuf* burstspace[20];
48
49} perthread_t;
50
51
52typedef struct dpdkndag_format_data {
53        libtrace_t *dpdkrecv;
54
55        struct addrinfo *multicastgroup;
56        char *localiface;
57
58        perthread_t *threaddatas;
59
60} dpdkndag_format_data_t;
61
62#define FORMAT_DATA ((dpdkndag_format_data_t *)libtrace->format_data)
63
64static inline int seq_cmp(uint32_t seq_a, uint32_t seq_b) {
65
66        /* Calculate seq_a - seq_b, taking wraparound into account */
67        if (seq_a == seq_b) return 0;
68
69        if (seq_a > seq_b) {
70                return (int) (seq_a - seq_b);
71        }
72
73        /* -1 for the wrap and another -1 because we don't use zero */
74        return (int) (0xffffffff - ((seq_b - seq_a) - 2));
75}
76
77
78static int dpdkndag_init_input(libtrace_t *libtrace) {
79
80        char *scan = NULL;
81        char *next = NULL;
82        char dpdkuri[1280];
83        struct addrinfo hints, *result;
84
85        libtrace->format_data = (dpdkndag_format_data_t *)malloc(
86                        sizeof(dpdkndag_format_data_t));
87
88        FORMAT_DATA->localiface = NULL;
89        FORMAT_DATA->threaddatas = NULL;
90        FORMAT_DATA->dpdkrecv = NULL;
91
92        scan = strchr(libtrace->uridata, ',');
93        if (scan == NULL) {
94                trace_set_err(libtrace, TRACE_ERR_BAD_FORMAT,
95                        "Bad dpdkndag URI. Should be dpdkndag:<interface>,<multicast group>");
96                return -1;
97        }
98        FORMAT_DATA->localiface = strndup(libtrace->uridata,
99                        (size_t)(scan - libtrace->uridata));
100        next = scan + 1;
101
102        memset(&hints, 0, sizeof(struct addrinfo));
103        hints.ai_family = AF_UNSPEC;
104        hints.ai_socktype = SOCK_DGRAM;
105        hints.ai_flags = AI_PASSIVE;
106        hints.ai_protocol = 0;
107
108        if (getaddrinfo(next, NULL, &hints, &result) != 0) {
109                perror("getaddrinfo");
110                trace_set_err(libtrace, TRACE_ERR_BAD_FORMAT,
111                        "Invalid multicast address: %s", next);
112                return -1;
113        }
114
115        FORMAT_DATA->multicastgroup = result;
116
117        snprintf(dpdkuri, 1279, "dpdk:%s", FORMAT_DATA->localiface);
118        FORMAT_DATA->dpdkrecv = trace_create(dpdkuri);
119
120        if (trace_is_err(FORMAT_DATA->dpdkrecv)) {
121                libtrace_err_t err = trace_get_err(FORMAT_DATA->dpdkrecv);
122                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "%s", err.problem);
123                free(libtrace->format_data);
124                libtrace->format_data = NULL;
125                return -1;
126        }
127
128        return 0;
129}
130
131static int dpdkndag_config_input (libtrace_t *libtrace, trace_option_t option,
132                void *data) {
133
134        return dpdk_config_input(FORMAT_DATA->dpdkrecv, option, data);
135}
136
137static int dpdkndag_init_threads(libtrace_t *libtrace, uint32_t maxthreads) {
138
139        uint32_t i;
140        if (FORMAT_DATA->threaddatas == NULL) {
141                FORMAT_DATA->threaddatas = (perthread_t *)malloc(
142                                sizeof(perthread_t) * maxthreads);
143        }
144
145        for (i = 0; i < maxthreads; i++) {
146                FORMAT_DATA->threaddatas[i].capstreams = NULL;
147                FORMAT_DATA->threaddatas[i].streamcount = 0;
148                FORMAT_DATA->threaddatas[i].dropped_upstream = 0;
149                FORMAT_DATA->threaddatas[i].received_packets = 0;
150                FORMAT_DATA->threaddatas[i].missing_records = 0;
151                FORMAT_DATA->threaddatas[i].dpdkstreamdata = NULL;
152                FORMAT_DATA->threaddatas[i].dpdkpkt = trace_create_packet();
153                FORMAT_DATA->threaddatas[i].ndagheader = NULL;
154                FORMAT_DATA->threaddatas[i].nextrec = NULL;
155                FORMAT_DATA->threaddatas[i].burstsize = 0;
156                FORMAT_DATA->threaddatas[i].burstoffset = 0;
157                memset(FORMAT_DATA->threaddatas[i].burstspace, 0,
158                                sizeof(struct rte_mbuf *) * 20);
159        }
160        return maxthreads;
161}
162
163static int dpdkndag_start_input(libtrace_t *libtrace) {
164
165        if (dpdk_start_input(FORMAT_DATA->dpdkrecv) == -1) {
166                libtrace_err_t err = trace_get_err(FORMAT_DATA->dpdkrecv);
167                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "%s", err.problem);
168                return -1;
169        }
170
171        dpdkndag_init_threads(libtrace, 1);
172
173        return 0;
174}
175
176static int dpdkndag_pstart_input(libtrace_t *libtrace) {
177
178        FORMAT_DATA->dpdkrecv->perpkt_thread_count = libtrace->perpkt_thread_count;
179        if (dpdk_pstart_input(FORMAT_DATA->dpdkrecv) == -1) {
180                libtrace_err_t err = trace_get_err(FORMAT_DATA->dpdkrecv);
181                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "%s", err.problem);
182                return -1;
183        }
184        dpdkndag_init_threads(libtrace, libtrace->perpkt_thread_count);
185        return 0;
186}
187
188static void clear_threaddata(perthread_t *pt) {
189
190        int i;
191
192        if (pt->dpdkpkt) {
193                trace_destroy_packet(pt->dpdkpkt);
194        }
195        pt->dpdkpkt = NULL;
196
197        if (pt->capstreams) {
198                free(pt->capstreams);
199        }
200
201        for (i = 0; i < 20; i++) {
202                if (pt->burstspace[i]) {
203                        rte_pktmbuf_free(pt->burstspace[i]);
204                }
205        }
206}
207
208static int dpdkndag_pause_input(libtrace_t *libtrace) {
209
210        int i;
211        /* Pause DPDK receive */
212        dpdk_pause_input(FORMAT_DATA->dpdkrecv);
213
214        /* Clear the threaddatas */
215        for (i = 0; i < libtrace->perpkt_thread_count; i++) {
216                clear_threaddata(&(FORMAT_DATA->threaddatas[i]));
217        }
218        return 0;
219}
220
221static int dpdkndag_fin_input(libtrace_t *libtrace) {
222
223        if (FORMAT_DATA->dpdkrecv) {
224                trace_destroy(FORMAT_DATA->dpdkrecv);
225        }
226
227        if (FORMAT_DATA->threaddatas) {
228                free(FORMAT_DATA->threaddatas);
229        }
230
231        if (FORMAT_DATA->localiface) {
232                free(FORMAT_DATA->localiface);
233        }
234
235        if (FORMAT_DATA->multicastgroup) {
236                freeaddrinfo(FORMAT_DATA->multicastgroup);
237        }
238
239        free(FORMAT_DATA);
240        return 0;
241}
242
243static int dpdkndag_pregister_thread(libtrace_t *libtrace, libtrace_thread_t *t,
244                bool reader) {
245
246        perthread_t *pt;
247
248        if (!reader || t->type != THREAD_PERPKT) {
249                return 0;
250        }
251
252        if (dpdk_pregister_thread(FORMAT_DATA->dpdkrecv, t, reader) == -1) {
253                libtrace_err_t err = trace_get_err(FORMAT_DATA->dpdkrecv);
254                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "%s", err.problem);
255                return -1;
256        }
257
258        /* t->format_data now contains our dpdk stream data */
259        pt = &(FORMAT_DATA->threaddatas[t->perpkt_num]);
260        pt->dpdkstreamdata = t->format_data;
261        t->format_data = pt;
262
263        return 0;
264}
265
266static void dpdkndag_punregister_thread(libtrace_t *libtrace, libtrace_thread_t *t) {
267
268        dpdk_punregister_thread(libtrace, t);
269}
270
271static void dpdkndag_get_thread_stats(libtrace_t *libtrace, libtrace_thread_t *t,
272                libtrace_stat_t *stat) {
273
274        perthread_t *pt = (perthread_t *)t->format_data;
275
276        if (libtrace == NULL) {
277                return;
278        }
279
280                /* TODO Is this thread safe */
281        stat->dropped_valid = 1;
282        stat->dropped = pt->dropped_upstream;
283
284        stat->received_valid = 1;
285        stat->received = pt->received_packets;
286
287        stat->missing_valid = 1;
288        stat->missing = pt->missing_records;
289}
290
291static void dpdkndag_get_statistics(libtrace_t *libtrace, libtrace_stat_t *stat) {
292        int i;
293
294        stat->dropped_valid = 1;
295        stat->dropped = 0;
296        stat->received_valid = 1;
297        stat->received = 0;
298        stat->missing_valid = 1;
299        stat->missing = 0;
300
301        /* TODO Is this thread safe? */
302        for (i = 0; i < libtrace->perpkt_thread_count; i++) {
303                stat->dropped += FORMAT_DATA->threaddatas[i].dropped_upstream;
304                stat->received += FORMAT_DATA->threaddatas[i].received_packets;
305                stat->missing += FORMAT_DATA->threaddatas[i].missing_records;
306        }
307}
308
309static int is_ndag_packet(libtrace_packet_t *packet, perthread_t *pt) {
310
311        void *trans = NULL;
312        uint32_t rem = 0;
313        uint8_t proto;
314        char *payload;
315
316        trans = trace_get_transport(packet, &proto, &rem);
317        if (trans == NULL) {
318                return 0;
319        }
320
321        if (proto != TRACE_IPPROTO_UDP) {
322                return 0;
323        }
324
325        payload = (char *)trace_get_payload_from_udp((libtrace_udp_t *)trans,
326                        &rem);
327
328        if (payload == NULL) {
329                return 0;
330        }
331
332        if (rem < 4) {
333                return 0;
334        }
335
336        if (payload[0] == 'N' && payload[1] == 'D' && payload[2] == 'A'
337                        && payload[3] == 'G') {
338                pt->ndagsize = rem;
339                pt->ndagheader = payload;
340                return 1;
341        }
342
343        return 0;
344
345}
346
347static int sockaddr_same(struct sockaddr *a, struct sockaddr *b) {
348
349        if (a->sa_family != b->sa_family) {
350                return 0;
351        }
352
353        if (a->sa_family == AF_INET) {
354                struct sockaddr_in *ain = (struct sockaddr_in *)a;
355                struct sockaddr_in *bin = (struct sockaddr_in *)b;
356
357                if (ain->sin_addr.s_addr != bin->sin_addr.s_addr) {
358                        return 0;
359                }
360                return 1;
361        } else if (a->sa_family == AF_INET6) {
362                struct sockaddr_in6 *ain6 = (struct sockaddr_in6 *)a;
363                struct sockaddr_in6 *bin6 = (struct sockaddr_in6 *)b;
364
365                if (memcmp(ain6->sin6_addr.s6_addr, bin6->sin6_addr.s6_addr,
366                                sizeof(ain6->sin6_addr.s6_addr)) != 0) {
367                        return 0;
368                }
369                return 1;
370        }
371        return 0;
372}
373
374static int process_fresh_packet(perthread_t *pt, struct addrinfo *expectedaddr) {
375
376        ndag_common_t *header = (ndag_common_t *)pt->ndagheader;
377        ndag_encap_t *encaphdr = (ndag_encap_t *)(pt->ndagheader +
378                        sizeof(ndag_common_t));
379        uint16_t targetport;
380        struct sockaddr_storage targetaddr;
381        struct sockaddr *p;
382        capstream_t *cap = NULL;
383        int i;
384
385        memset((&targetaddr), 0, sizeof(targetaddr));
386        if (header->type != NDAG_PKT_ENCAPERF) {
387                pt->nextrec = NULL;
388                pt->ndagsize = 0;
389                pt->ndagheader = NULL;
390                return 1;
391        }
392
393        if ((p = trace_get_destination_address(pt->dpdkpkt,
394                        (struct sockaddr *)(&targetaddr))) == NULL) {
395                pt->nextrec = NULL;
396                pt->ndagsize = 0;
397                pt->ndagheader = NULL;
398                return 1;
399        }
400
401        if (!(sockaddr_same(p, expectedaddr->ai_addr))) {
402                pt->nextrec = NULL;
403                pt->ndagsize = 0;
404                pt->ndagheader = NULL;
405                return 1;
406        }
407
408        targetport = trace_get_destination_port(pt->dpdkpkt);
409        if (pt->streamcount == 0) {
410                pt->capstreams = (capstream_t *)malloc(sizeof(capstream_t));
411                pt->streamcount = 1;
412                pt->capstreams[0].port = targetport;
413                pt->capstreams[0].expectedseq = 0;
414                pt->capstreams[0].recordcount = 0;
415                cap = pt->capstreams;
416
417        } else {
418                for (i = 0; i < pt->streamcount; i++) {
419                        if (pt->capstreams[i].port == targetport) {
420                                cap = (&pt->capstreams[i]);
421                                break;
422                        }
423                }
424
425                if (cap == NULL) {
426                        uint16_t next = pt->streamcount;
427                        pt->capstreams = (capstream_t *)realloc(pt->capstreams,
428                                    sizeof(capstream_t) * (pt->streamcount + 1));
429                        pt->streamcount += 1;
430                        pt->capstreams[next].port = targetport;
431                        pt->capstreams[next].expectedseq = 0;
432                        pt->capstreams[next].recordcount = 0;
433                        cap = &(pt->capstreams[next]);
434                }
435        }
436
437        if (cap->expectedseq != 0) {
438                pt->missing_records += seq_cmp(
439                                ntohl(encaphdr->seqno), cap->expectedseq);
440        }
441        cap->expectedseq = ntohl(encaphdr->seqno) + 1;
442        if (cap->expectedseq == 0) {
443                cap->expectedseq ++;
444        }
445
446        pt->nextrec = ((char *)header) + sizeof(ndag_common_t) +
447                        sizeof(ndag_encap_t);
448
449        return 1;
450}
451
452static int ndagrec_to_libtrace_packet(libtrace_t *libtrace, perthread_t *pt,
453                libtrace_packet_t *packet) {
454
455        /* This is mostly borrowed from ndag_prepare_packet_stream, minus
456         * the ndag socket-specific stuff */
457
458        dag_record_t *erfptr;
459        ndag_encap_t *encaphdr;
460
461        if (pt->nextrec == NULL) {
462                return -1;
463        }
464
465        if (pt->nextrec - pt->ndagheader >= pt->ndagsize) {
466                return -1;
467        }
468
469        packet->buf_control = TRACE_CTRL_EXTERNAL;
470
471        packet->trace = libtrace;
472        packet->buffer = pt->nextrec;
473        packet->header = pt->nextrec;
474        packet->type = TRACE_RT_DATA_ERF;
475
476        erfptr = (dag_record_t *)packet->header;
477
478        if (erfptr->flags.rxerror == 1) {
479                packet->payload = NULL;
480                erfptr->rlen = htons(erf_get_framing_length(packet));
481        } else {
482                packet->payload = (char *)packet->buffer +
483                                erf_get_framing_length(packet);
484        }
485
486        /* Update upstream drops using lctr */
487
488        if (erfptr->type == TYPE_DSM_COLOR_ETH) {
489                /* TODO */
490        } else {
491                if (pt->received_packets > 0) {
492                        pt->dropped_upstream += ntohs(erfptr->lctr);
493                }
494        }
495
496        pt->received_packets ++;
497        encaphdr = (ndag_encap_t *)(pt->ndagheader + sizeof(ndag_common_t));
498
499        if ((ntohs(encaphdr->recordcount) & 0x8000) != 0) {
500                /* Record was truncated */
501                erfptr->rlen = htons(pt->ndagsize - (pt->nextrec -
502                                pt->ndagheader));
503        }
504
505        pt->nextrec += ntohs(erfptr->rlen);
506
507        if (pt->nextrec - pt->ndagheader >= pt->ndagsize) {
508                pt->ndagheader = NULL;
509                pt->nextrec = NULL;
510                pt->ndagsize = 0;
511        }
512
513        packet->order = erf_get_erf_timestamp(packet);
514        packet->error = packet->payload ? ntohs(erfptr->rlen) :
515                        erf_get_framing_length(packet);
516        return ntohs(erfptr->rlen);
517}
518
519static int dpdkndag_pread_packets(libtrace_t *libtrace,
520                                    libtrace_thread_t *t,
521                                    libtrace_packet_t **packets,
522                                    size_t nb_packets) {
523
524        perthread_t *pt = (perthread_t *)t->format_data;
525        size_t read_packets = 0;
526        int ret;
527
528        while (pt->nextrec == NULL) {
529                trace_fin_packet(pt->dpdkpkt);
530
531                if (pt->burstsize > 0 && pt->burstsize != pt->burstoffset) {
532                        pt->dpdkpkt->buffer = pt->burstspace[pt->burstoffset];
533                        pt->dpdkpkt->trace = FORMAT_DATA->dpdkrecv;
534                        dpdk_prepare_packet(FORMAT_DATA->dpdkrecv, pt->dpdkpkt,
535                                        pt->dpdkpkt->buffer,
536                                        TRACE_RT_DATA_DPDK, 0);
537                        pt->burstoffset ++;
538                } else {
539                        ret = dpdk_read_packet_stream(FORMAT_DATA->dpdkrecv,
540                                        pt->dpdkstreamdata,
541                                        &t->messages,
542                                        pt->burstspace,
543                                        20);
544                        if (ret <= 0) {
545                                return ret;
546                        }
547                        pt->dpdkpkt->buffer = pt->burstspace[0];
548                        pt->dpdkpkt->trace = FORMAT_DATA->dpdkrecv;
549                        dpdk_prepare_packet(FORMAT_DATA->dpdkrecv, pt->dpdkpkt,
550                                        pt->dpdkpkt->buffer,
551                                        TRACE_RT_DATA_DPDK, 0);
552                        pt->burstsize = ret;
553                        pt->burstoffset = 1;
554                }
555
556                if (!is_ndag_packet(pt->dpdkpkt, pt)) {
557                        continue;
558                }
559
560                ret = process_fresh_packet(pt, FORMAT_DATA->multicastgroup);
561                if (ret <= 0) {
562                        return ret;
563                }
564        }
565
566        while (pt->nextrec != NULL) {
567                if (read_packets == nb_packets) {
568                        break;
569                }
570
571                if (packets[read_packets]->buf_control == TRACE_CTRL_PACKET) {
572                        free(packets[read_packets]->buffer);
573                        packets[read_packets]->buffer = NULL;
574                }
575                ret = ndagrec_to_libtrace_packet(libtrace, pt,
576                                packets[read_packets]);
577                if (ret < 0) {
578                        return ret;
579                }
580                read_packets ++;
581
582        }
583
584        return read_packets;
585}
586
587static int dpdkndag_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
588
589        perthread_t *pt = &(FORMAT_DATA->threaddatas[0]);
590        int ret;
591
592        if (packet->buf_control == TRACE_CTRL_PACKET) {
593                free(packet->buffer);
594                packet->buffer = NULL;
595        }
596
597        while (pt->nextrec == NULL) {
598                trace_fin_packet(pt->dpdkpkt);
599
600                ret = dpdk_read_packet(FORMAT_DATA->dpdkrecv, pt->dpdkpkt);
601                if (ret <= 0) {
602                        return ret;
603                }
604
605                if (!is_ndag_packet(pt->dpdkpkt, pt)) {
606                        continue;
607                }
608
609                ret = process_fresh_packet(pt, FORMAT_DATA->multicastgroup);
610                if (ret <= 0) {
611                        return ret;
612                }
613        }
614
615        return ndagrec_to_libtrace_packet(libtrace, pt, packet);
616}
617
618static libtrace_eventobj_t trace_event_dpdkndag(libtrace_t *libtrace,
619                libtrace_packet_t *packet) {
620
621
622        libtrace_eventobj_t event;
623        int ret;
624        perthread_t *pt = &(FORMAT_DATA->threaddatas[0]);
625
626        if (packet->buf_control == TRACE_CTRL_PACKET) {
627                free(packet->buffer);
628                packet->buffer = NULL;
629        }
630
631        while (pt->nextrec == NULL) {
632
633                event = dpdk_trace_event(libtrace, pt->dpdkpkt);
634
635                if (event.type != TRACE_EVENT_PACKET) {
636                        return event;
637                }
638
639                if (!is_ndag_packet(pt->dpdkpkt, pt)) {
640                        continue;
641                }
642
643                ret = process_fresh_packet(pt, FORMAT_DATA->multicastgroup);
644                if (ret <= 0) {
645                        event.type = TRACE_EVENT_TERMINATE;
646                        return event;
647                }
648        }
649
650        ret = ndagrec_to_libtrace_packet(libtrace, pt, packet);
651        if (ret < 0) {
652                event.type = TRACE_EVENT_TERMINATE;
653        } else {
654                event.type = TRACE_EVENT_PACKET;
655                event.size = 1;
656        }
657        return event;
658}
659
660static struct libtrace_format_t dpdkndag = {
661
662        "dpdkndag",
663        "",
664        TRACE_FORMAT_DPDK_NDAG,
665        NULL,                   /* probe filename */
666        NULL,                   /* probe magic */
667        dpdkndag_init_input,        /* init_input */
668        dpdkndag_config_input,      /* config_input */
669        dpdkndag_start_input,       /* start_input */
670        dpdkndag_pause_input,       /* pause_input */
671        NULL,                   /* init_output */
672        NULL,                   /* config_output */
673        NULL,                   /* start_output */
674        dpdkndag_fin_input,         /* fin_input */
675        NULL,                   /* fin_output */
676        dpdkndag_read_packet,   /* read_packet */
677        NULL,                   /* prepare_packet */
678        NULL,                   /* fin_packet */
679        NULL,                   /* write_packet */
680        erf_get_link_type,      /* get_link_type */
681        erf_get_direction,      /* get_direction */
682        erf_set_direction,      /* set_direction */
683        erf_get_erf_timestamp,  /* get_erf_timestamp */
684        NULL,                   /* get_timeval */
685        NULL,                   /* get_seconds */
686        NULL,                   /* get_timespec */
687        NULL,                   /* seek_erf */
688        NULL,                   /* seek_timeval */
689        NULL,                   /* seek_seconds */
690        erf_get_capture_length, /* get_capture_length */
691        erf_get_wire_length,    /* get_wire_length */
692        erf_get_framing_length, /* get_framing_length */
693        erf_set_capture_length, /* set_capture_length */
694        NULL,                   /* get_received_packets */
695        NULL,                   /* get_filtered_packets */
696        NULL,                   /* get_dropped_packets */
697        dpdkndag_get_statistics,    /* get_statistics */
698        NULL,                   /* get_fd */
699        trace_event_dpdkndag,       /* trace_event */
700        NULL,                   /* help */
701        NULL,                   /* next pointer */
702        {true, 0},              /* live packet capture */
703        dpdkndag_pstart_input,      /* parallel start */
704        dpdkndag_pread_packets,     /* parallel read */
705        dpdkndag_pause_input,       /* parallel pause */
706        NULL,
707        dpdkndag_pregister_thread,  /* register thread */
708        dpdkndag_punregister_thread,
709        dpdkndag_get_thread_stats   /* per-thread stats */
710};
711
712void dpdkndag_constructor(void) {
713        register_format(&dpdkndag);
714}
Note: See TracBrowser for help on using the repository browser.