source: tools/tracetop/tracetop.cc @ 4325ef8

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 4325ef8 was 4325ef8, checked in by Perry Lorier <perry@…>, 12 years ago

Add totally stupid fullspeed option for jamie doing crazy things

  • Property mode set to 100644
File size: 12.6 KB
Line 
1/* Show the top 'n' flows from a libtrace source
2 *
3 */
4#define __STDC_FORMAT_MACROS 1
5#include "libtrace.h"
6#include <stdio.h>
7#include <getopt.h>
8#include <stdlib.h>
9#include <map>
10#include <queue>
11#include <inttypes.h>
12#include <ncurses.h>
13#include <sys/socket.h>
14#include <netdb.h>
15#include <string.h>
16#include "config.h"
17#ifdef HAVE_NETPACKET_PACKET_H
18#include <netpacket/packet.h>
19#include <net/ethernet.h>
20#endif
21
22typedef enum { BITS_PER_SEC, BYTES, PERCENT } display_t;
23display_t display_as = BYTES;
24float interval=2;
25double last_report=0;
26
27bool use_sip = true;
28bool use_dip = true;
29bool use_sport = true;
30bool use_dport = true;
31bool use_protocol = true;
32bool quit = false;
33bool fullspeed = false;
34
35uint64_t total_bytes=0;
36uint64_t total_packets=0;
37
38int cmp_sockaddr_in6(const struct sockaddr_in6 *a, const struct sockaddr_in6 *b)
39{
40        if (a->sin6_port != b->sin6_port)
41                return a->sin6_port - b->sin6_port;
42        return memcmp(a->sin6_addr.s6_addr,b->sin6_addr.s6_addr,sizeof(a->sin6_addr.s6_addr));
43}
44
45int cmp_sockaddr_in(const struct sockaddr_in *a, const struct sockaddr_in *b)
46{
47        if (a->sin_port != b->sin_port)
48                return a->sin_port - b->sin_port;
49        return a->sin_addr.s_addr - b->sin_addr.s_addr;
50}
51
52#ifdef HAVE_NETPACKET_PACKET_H
53int cmp_sockaddr_ll(const struct sockaddr_ll *a, const struct sockaddr_ll *b)
54{
55        return memcmp(a->sll_addr, b->sll_addr, b->sll_halen);
56}
57#endif
58
59int cmp_sockaddr(const struct sockaddr *a, const struct sockaddr *b)
60{
61        if (a->sa_family != b->sa_family) {
62                return a->sa_family - b->sa_family;
63        }
64        switch (a->sa_family) {
65                case AF_INET:
66                        return cmp_sockaddr_in((struct sockaddr_in *)a,(struct sockaddr_in*)b);
67                case AF_INET6:
68                        return cmp_sockaddr_in6((struct sockaddr_in6 *)a,(struct sockaddr_in6*)b);
69#ifdef HAVE_NETPACKET_PACKET_H
70                case AF_PACKET:
71                        return cmp_sockaddr_ll((struct sockaddr_ll *)a,(struct sockaddr_ll*)b);
72#endif
73                case AF_UNSPEC:
74                        return 0; /* Can't compare UNSPEC's! */
75                default:
76                        fprintf(stderr,"Don't know how to compare family %d\n",a->sa_family);
77                        abort();
78        }
79}
80
81char *trace_sockaddr2string(const struct sockaddr *a, socklen_t salen, char *buffer, size_t bufflen)
82{
83        static char intbuffer[NI_MAXHOST];
84        char *mybuf = buffer ? buffer : intbuffer;
85        size_t mybufflen = buffer ? bufflen : sizeof(intbuffer);
86        int err;
87        switch (a->sa_family) {
88                case AF_INET:
89                case AF_INET6:
90                        if ((err=getnameinfo(a, salen, mybuf, mybufflen, NULL, 0, NI_NUMERICHOST))!=0) {
91                                strncpy(mybuf,gai_strerror(err),mybufflen);
92                        }
93                        break;
94#ifdef HAVE_NETPACKET_PACKET_H
95                case AF_PACKET:
96                        trace_ether_ntoa(((struct sockaddr_ll*)a)->sll_addr, mybuf);
97                        break;
98#endif
99                default:
100                        snprintf(mybuf,mybufflen,"Unknown family %d",a->sa_family);
101        }
102        return mybuf;
103}
104
105struct flowkey_t {
106        struct sockaddr_storage sip;
107        struct sockaddr_storage dip;
108        uint16_t sport;
109        uint16_t dport;
110        uint8_t protocol;
111
112        bool operator <(const flowkey_t &b) const {
113                int c;
114
115                if (use_sip) {
116                        c = cmp_sockaddr((struct sockaddr*)&sip,(struct sockaddr*)&b.sip);
117                        if (c != 0) return c<0;
118                }
119                if (use_dip) {
120                        c = cmp_sockaddr((struct sockaddr*)&dip,(struct sockaddr*)&b.dip);
121                        if (c != 0) return c<0;
122                }
123
124                if (use_sport && sport != b.sport) return sport < b.sport;
125                if (use_dport && dport != b.dport) return dport < b.dport;
126
127                return protocol < b.protocol;
128        }
129};
130
131struct flowdata_t {
132        uint64_t packets;
133        uint64_t bytes;
134};
135
136typedef std::map<flowkey_t,flowdata_t> flows_t;
137
138flows_t flows;
139
140const char *nice_bandwidth(double bytespersec)
141{
142        static char ret[1024];
143        double bitspersec = bytespersec*8;
144
145        if (bitspersec>1e12)
146                snprintf(ret,sizeof(ret),"%.03fTb/s", bitspersec/1e12);
147        else if (bitspersec>1e9)
148                snprintf(ret,sizeof(ret),"%.03fGb/s", bitspersec/1e9);
149        else if (bitspersec>1e6)
150                snprintf(ret,sizeof(ret),"%.03fMb/s", bitspersec/1e6);
151        else if (bitspersec>1e3)
152                snprintf(ret,sizeof(ret),"%.03fkb/s", bitspersec/1e3);
153        else
154                snprintf(ret,sizeof(ret),"%.03fb/s", bitspersec);
155        return ret;
156}
157
158static void per_packet(libtrace_packet_t *packet)
159{
160        flowkey_t flowkey;
161        flows_t::iterator it;
162
163        if (use_sip && trace_get_source_address(packet,(struct sockaddr*)&flowkey.sip)==NULL)
164                flowkey.sip.ss_family = AF_UNSPEC;
165        if (use_dip && trace_get_destination_address(packet,(struct sockaddr*)&flowkey.dip)==NULL)
166                flowkey.dip.ss_family = AF_UNSPEC;
167        if (use_protocol && trace_get_transport(packet,&flowkey.protocol, NULL) == NULL)
168                flowkey.protocol = 255;
169        if (use_sport) flowkey.sport = trace_get_source_port(packet);
170        if (use_dport) flowkey.dport = trace_get_destination_port(packet);
171
172        it = flows.find(flowkey);
173        if (it == flows.end()) {
174                flowdata_t flowdata = { 0, 0 };
175                flows_t::value_type insdata(flowkey,flowdata);
176                std::pair<flows_t::iterator,bool> ins= flows.insert(insdata);
177                it = ins.first;
178        }
179
180        ++it->second.packets;
181        it->second.bytes+=trace_get_capture_length(packet);
182
183        ++total_packets;
184        total_bytes+=trace_get_capture_length(packet);
185
186}
187
188struct flow_data_t {
189        uint64_t bytes;
190        uint64_t packets;
191        struct sockaddr_storage sip;
192        struct sockaddr_storage dip;
193        uint16_t sport;
194        uint16_t dport;
195        uint8_t protocol;
196
197        bool operator< (const flow_data_t &b) const {
198                if (bytes != b.bytes) return bytes < b.bytes;
199                return packets < b.packets;
200        }
201};
202
203static void do_report()
204{
205        typedef  std::priority_queue<flow_data_t> pq_t;
206        int row,col;
207        pq_t pq;
208        for(flows_t::const_iterator it=flows.begin();it!=flows.end();++it) {
209                flow_data_t data;
210                data.bytes = it->second.bytes,
211                data.packets = it->second.packets,
212                data.sip = it->first.sip;
213                data.dip = it->first.dip;
214                data.sport = it->first.sport;
215                data.dport = it->first.dport;
216                data.protocol = it->first.protocol;
217                pq.push(data);
218        }
219        getmaxyx(stdscr,row,col);
220        move(0,0);
221        printw("Total Bytes: %10" PRIu64 " (%s)\tTotal Packets: %10" PRIu64, total_bytes, nice_bandwidth(total_bytes/interval), total_packets);
222        clrtoeol();
223        attrset(A_REVERSE);
224        move(1,0);
225        if (use_sip) {
226                printw("%20s", "source ip");
227                if (use_sport)
228                        printw("/");
229                else
230                        printw("\t");
231        }
232        if (use_sport)
233                printw("%s\t", "sport");
234        if (use_dip) {
235                printw("%20s", "dest ip");
236                if (use_dport)
237                        printw("/");
238                else
239                        printw("\t");
240        }
241        if (use_dport)
242                printw("%s\t", "dport");
243        if (use_protocol)
244                printw("proto\t");
245        switch(display_as) {
246                case BYTES:
247                        printw("%7s","Bytes\t");
248                        break;
249                case BITS_PER_SEC:
250                        printw("%14s\t","Bits/sec");
251                        break;
252                case PERCENT:
253                        printw("%% bytes\t");
254                        break;
255        }
256        printw("Packets");
257
258        attrset(A_NORMAL);
259        char sipstr[1024];
260        char dipstr[1024];
261        for(int i=1; i<row-3 && !pq.empty(); ++i) {
262                move(i+1,0);
263                if (use_sip) {
264                        printw("%20s",
265                                trace_sockaddr2string((struct sockaddr*)&pq.top().sip,
266                                        sizeof(struct sockaddr_storage),
267                                        sipstr,sizeof(sipstr)));
268                        if (use_sport)
269                                printw("/");
270                        else
271                                printw("\t");
272                }
273                if (use_sport)
274                        printw("%-5d\t", pq.top().sport);
275                if (use_dip) {
276                        printw("%20s",
277                                trace_sockaddr2string((struct sockaddr*)&pq.top().dip,
278                                        sizeof(struct sockaddr_storage),
279                                        dipstr,sizeof(dipstr)));
280                        if (use_dport)
281                                printw("/");
282                        else
283                                printw("\t");
284                }
285                if (use_dport)
286                        printw("%-5d\t", pq.top().dport);
287                if (use_protocol) {
288                        struct protoent *proto = getprotobynumber(pq.top().protocol);
289                        if (proto) 
290                                printw("%-5s\t", proto->p_name);
291                        else
292                                printw("%5d\t",pq.top().protocol);
293                }
294                switch (display_as) {
295                        case BYTES:
296                                printw("%7"PRIu64"\t%7"PRIu64"\n",
297                                                pq.top().bytes,
298                                                pq.top().packets);
299                                break;
300                        case BITS_PER_SEC:
301                                printw("%14.03f\t%"PRIu64"\n",
302                                                8.0*pq.top().bytes/interval,
303                                                pq.top().packets);
304                        case PERCENT:
305                                printw("%6.2f%%\t%6.2f%%\n",
306                                                100.0*pq.top().bytes/total_bytes,
307                                                100.0*pq.top().packets/total_packets);
308                }
309                pq.pop();
310        }
311        flows.clear();
312        total_packets = 0;
313        total_bytes = 0;
314
315        clrtobot();
316        refresh();
317}
318
319static void run_trace(libtrace_t *trace)
320{
321        libtrace_packet_t *packet = trace_create_packet();
322        libtrace_eventobj_t obj;
323        fd_set rfds;
324        struct timeval sleep_tv;
325        struct timeval *tv = NULL;
326
327        do {
328                int maxfd=0;
329                FD_ZERO(&rfds);
330                FD_SET(0, &rfds); /* stdin */
331                tv=NULL;
332                maxfd=0;
333
334                obj = trace_event(trace, packet);
335                switch(obj.type) {
336                        case TRACE_EVENT_IOWAIT:
337                                FD_SET(obj.fd, &rfds);
338                                maxfd = obj.fd;
339                                break;
340
341                        case TRACE_EVENT_SLEEP:
342                                sleep_tv.tv_sec = (int)obj.seconds;
343                                sleep_tv.tv_usec = (int)((obj.seconds - sleep_tv.tv_sec)*1000000.0);
344
345                                tv = &sleep_tv;
346                                break;;
347
348                        case TRACE_EVENT_TERMINATE:
349                                trace_destroy_packet(packet);
350                                return;
351
352                        case TRACE_EVENT_PACKET:
353                                if (obj.size == -1)
354                                        break;
355                                if (trace_get_seconds(packet) - last_report >= interval) {
356                                        do_report();
357                                               
358                                        last_report=trace_get_seconds(packet);
359                                }
360                                if (trace_read_packet(trace,packet) <= 0) {
361                                        obj.size = -1;
362                                        break;
363                                }
364                                per_packet(packet);
365                                continue;
366                }
367
368                if (tv && tv->tv_sec > interval) {
369                        tv->tv_sec = (int)interval;
370                        tv->tv_usec = 0;
371                }
372
373                select(maxfd+1, &rfds, 0, 0, tv);
374                if (FD_ISSET(0, &rfds)) {
375                        switch (getch()) {
376                                case '%':
377                                        display_as = PERCENT;
378                                        break;
379                                case 'b':
380                                        display_as = BITS_PER_SEC;
381                                        break;
382                                case 'B':
383                                        display_as = BYTES;
384                                        break;
385                                case '\x1b': /* Escape */
386                                case 'q':
387                                        quit = true;
388                                        trace_destroy_packet(packet);
389                                        return;
390                                case '1': use_sip       = !use_sip; break;
391                                case '2': use_sport     = !use_sport; break;
392                                case '3': use_dip       = !use_dip; break;
393                                case '4': use_dport     = !use_dport; break;
394                                case '5': use_protocol  = !use_protocol; break;
395                        }
396                }
397        } while (obj.type != TRACE_EVENT_TERMINATE || obj.size == -1);
398
399        trace_destroy_packet(packet);
400} 
401
402static void usage(char *argv0)
403{
404        fprintf(stderr,"usage: %s [options] libtraceuri...\n",argv0);
405        fprintf(stderr," --filter bpfexpr\n");
406        fprintf(stderr," -f bpfexpr\n");
407        fprintf(stderr,"\t\tApply a bpf filter expression\n");
408        fprintf(stderr," --snaplen snaplen\n");
409        fprintf(stderr," -s snaplen\n");
410        fprintf(stderr,"\t\tCapture only snaplen bytes\n");
411        fprintf(stderr," --promisc 0|1\n");
412        fprintf(stderr," -p 0|1\n");
413        fprintf(stderr,"\t\tEnable/Disable promiscuous mode\n");
414        fprintf(stderr," --bits-per-sec\n");
415        fprintf(stderr," -B\n");
416        fprintf(stderr,"\t\tDisplay usage in bits per second, not bytes per second\n");
417        fprintf(stderr," --percent\n");
418        fprintf(stderr," -P\n");
419        fprintf(stderr,"\t\tDisplay usage in percentage of total usage\n");
420        fprintf(stderr," --interval int\n");
421        fprintf(stderr," -i int\n");
422        fprintf(stderr,"\t\tUpdate the display every int seconds\n");
423}
424
425int main(int argc, char *argv[])
426{
427        libtrace_t *trace;
428        libtrace_packet_t *packet;
429        libtrace_filter_t *filter=NULL;
430        int snaplen=-1;
431        int promisc=-1;
432
433        setprotoent(1);
434
435        while(1) {
436                int option_index;
437                struct option long_options[] = {
438                        { "filter",             1, 0, 'f' },
439                        { "snaplen",            1, 0, 's' },
440                        { "promisc",            1, 0, 'p' },
441                        { "help",               0, 0, 'h' },
442                        { "libtrace-help",      0, 0, 'H' },
443                        { "bits-per-sec",       0, 0, 'B' },
444                        { "percent",            0, 0, 'P' },
445                        { "interval",           1, 0, 'i' },
446                        { "fast",               0, 0, 'F' },
447                        { NULL,                 0, 0, 0 }
448                };
449
450                int c= getopt_long(argc, argv, "f:Fs:p:hHi:",
451                                long_options, &option_index);
452
453                if (c==-1)
454                        break;
455
456                switch (c) {
457                        case 'f':
458                                filter=trace_create_filter(optarg);
459                                break;
460                        case 'F':
461                                fullspeed = true;
462                                break;
463                        case 's':
464                                snaplen=atoi(optarg);
465                                break;
466                        case 'p':
467                                promisc=atoi(optarg);
468                                break;
469                        case 'H':
470                                trace_help();
471                                return 1;
472                        case 'B':
473                                display_as = BITS_PER_SEC;
474                                break;
475                        case 'P':
476                                display_as = PERCENT;
477                                break;
478                        case 'i':
479                                interval = atof(optarg);
480                                if (interval<=0) {
481                                        fprintf(stderr,"Interval must be >0\n");
482                                        return 1;
483                                }
484                                break;
485                        default:
486                                fprintf(stderr,"Unknown option: %c\n",c);
487                                /* FALL THRU */
488                        case 'h':
489                                usage(argv[0]);
490                                return 1;
491                }
492        }
493
494        if (optind>=argc) {
495                fprintf(stderr,"Missing input uri\n");
496                usage(argv[0]);
497                return 1;
498        }
499
500        initscr(); cbreak(); noecho();
501
502        while (!quit && optind<argc) {
503                trace = trace_create(argv[optind]);
504                ++optind;
505
506                if (trace_is_err(trace)) {
507                        endwin();
508                        trace_perror(trace,"Opening trace file");
509                        return 1;
510                }
511
512                if (snaplen>0)
513                        if (trace_config(trace,TRACE_OPTION_SNAPLEN,&snaplen)) {
514                                trace_perror(trace,"ignoring: ");
515                        }
516                if (filter)
517                        if (trace_config(trace,TRACE_OPTION_FILTER,filter)) {
518                                trace_perror(trace,"ignoring: ");
519                        }
520                if (promisc!=-1) {
521                        if (trace_config(trace,TRACE_OPTION_PROMISC,&promisc)) {
522                                trace_perror(trace,"ignoring: ");
523                        }
524                }
525                if (fullspeed) {
526                        int flag=1;
527                        if (trace_config(trace,TRACE_OPTION_EVENT_REALTIME,&flag)) {
528                                trace_perror(trace,"Setting EVENT_REALTIME option");
529                        }
530                }
531
532                if (trace_start(trace)) {
533                        endwin();
534                        trace_perror(trace,"Starting trace");
535                        trace_destroy(trace);
536                        return 1;
537                }
538
539                run_trace(trace);
540
541                if (trace_is_err(trace)) {
542                        trace_perror(trace,"Reading packets");
543                }
544
545                trace_destroy(trace);
546        }
547
548        endwin();
549        endprotoent();
550
551        return 0;
552}
Note: See TracBrowser for help on using the repository browser.