source: tools/tracetop/tracetop.cc @ 37f537f

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

Clean up display
Fix the total bandwidth display

  • Property mode set to 100644
File size: 10.1 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 "config.h"
16#ifdef HAVE_NETPACKET_PACKET_H
17#include <sys/socket.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;
25
26bool use_sip = true;
27bool use_dip = true;
28bool use_sport = true;
29bool use_dport = true;
30bool use_protocol = true;
31
32uint64_t total_bytes=0;
33uint64_t total_packets=0;
34
35int cmp_sockaddr_in6(const struct sockaddr_in6 *a, const struct sockaddr_in6 *b)
36{
37        if (a->sin6_port != b->sin6_port)
38                return a->sin6_port - b->sin6_port;
39        return memcmp(a->sin6_addr.s6_addr,b->sin6_addr.s6_addr,sizeof(a->sin6_addr.s6_addr));
40}
41
42int cmp_sockaddr_in(const struct sockaddr_in *a, const struct sockaddr_in *b)
43{
44        if (a->sin_port != b->sin_port)
45                return a->sin_port - b->sin_port;
46        return a->sin_addr.s_addr - b->sin_addr.s_addr;
47}
48
49#ifdef HAVE_NETPACKET_PACKET_H
50int cmp_sockaddr_ll(const struct sockaddr_ll *a, const struct sockaddr_ll *b)
51{
52        return memcmp(a->sll_addr, b->sll_addr, b->sll_halen);
53}
54#endif
55
56int cmp_sockaddr(const struct sockaddr *a, const struct sockaddr *b)
57{
58        if (a->sa_family != b->sa_family) {
59                return a->sa_family - b->sa_family;
60        }
61        switch (a->sa_family) {
62                case AF_INET:
63                        return cmp_sockaddr_in((struct sockaddr_in *)a,(struct sockaddr_in*)b);
64                case AF_INET6:
65                        return cmp_sockaddr_in6((struct sockaddr_in6 *)a,(struct sockaddr_in6*)b);
66#ifdef HAVE_NETPACKET_PACKET_H
67                case AF_PACKET:
68                        return cmp_sockaddr_ll((struct sockaddr_ll *)a,(struct sockaddr_ll*)b);
69#endif
70                case AF_UNSPEC:
71                        return 0; /* Can't compare UNSPEC's! */
72                default:
73                        fprintf(stderr,"Don't know how to compare family %d\n",a->sa_family);
74                        abort();
75        }
76}
77
78char *trace_sockaddr2string(const struct sockaddr *a, socklen_t salen, char *buffer, size_t bufflen)
79{
80        static char intbuffer[NI_MAXHOST];
81        char *mybuf = buffer ? buffer : intbuffer;
82        size_t mybufflen = buffer ? bufflen : sizeof(intbuffer);
83        int err;
84        switch (a->sa_family) {
85                case AF_INET:
86                case AF_INET6:
87                        if ((err=getnameinfo(a, salen, mybuf, mybufflen, NULL, 0, NI_NUMERICHOST))!=0) {
88                                strncpy(mybuf,gai_strerror(err),mybufflen);
89                        }
90                        break;
91#ifdef HAVE_NETPACKET_PACKET_H
92                case AF_PACKET:
93                        trace_ether_ntoa(((struct sockaddr_ll*)a)->sll_addr, mybuf);
94                        break;
95#endif
96                default:
97                        snprintf(mybuf,mybufflen,"Unknown family %d",a->sa_family);
98        }
99        return mybuf;
100}
101
102struct flowkey_t {
103        struct sockaddr_storage sip;
104        struct sockaddr_storage dip;
105        uint16_t sport;
106        uint16_t dport;
107        uint8_t protocol;
108
109        bool operator <(const flowkey_t &b) const {
110                int c;
111
112                if (use_sip) {
113                        c = cmp_sockaddr((struct sockaddr*)&sip,(struct sockaddr*)&b.sip);
114                        if (c != 0) return c<0;
115                }
116                if (use_dip) {
117                        c = cmp_sockaddr((struct sockaddr*)&dip,(struct sockaddr*)&b.dip);
118                        if (c != 0) return c<0;
119                }
120
121                if (use_sport && sport != b.sport) return sport < b.sport;
122                if (use_dport && dport != b.dport) return dport < b.dport;
123
124                return protocol < b.protocol;
125        }
126};
127
128struct flowdata_t {
129        uint64_t packets;
130        uint64_t bytes;
131};
132
133typedef std::map<flowkey_t,flowdata_t> flows_t;
134
135flows_t flows;
136
137const char *nice_bandwidth(double bytespersec)
138{
139        static char ret[1024];
140        double bitspersec = bytespersec*8;
141
142        if (bitspersec>1e12)
143                snprintf(ret,sizeof(ret),"%.03fTb/s", bitspersec/1e12);
144        else if (bitspersec>1e9)
145                snprintf(ret,sizeof(ret),"%.03fGb/s", bitspersec/1e9);
146        else if (bitspersec>1e6)
147                snprintf(ret,sizeof(ret),"%.03fMb/s", bitspersec/1e6);
148        else if (bitspersec>1e3)
149                snprintf(ret,sizeof(ret),"%.03fkb/s", bitspersec/1e3);
150        else
151                snprintf(ret,sizeof(ret),"%.03fb/s", bitspersec);
152        return ret;
153}
154
155static void per_packet(libtrace_packet_t *packet)
156{
157        flowkey_t flowkey;
158        flows_t::iterator it;
159
160        if (use_sip && trace_get_source_address(packet,(struct sockaddr*)&flowkey.sip)==NULL)
161                flowkey.sip.ss_family = AF_UNSPEC;
162        if (use_dip && trace_get_destination_address(packet,(struct sockaddr*)&flowkey.dip)==NULL)
163                flowkey.dip.ss_family = AF_UNSPEC;
164        if (use_protocol && trace_get_transport(packet,&flowkey.protocol, NULL) == NULL)
165                flowkey.protocol = 0;
166        if (use_sport) flowkey.sport = trace_get_source_port(packet);
167        if (use_dport) flowkey.dport = trace_get_destination_port(packet);
168
169        it = flows.find(flowkey);
170        if (it == flows.end()) {
171                flowdata_t flowdata = { 0, 0 };
172                flows_t::value_type insdata(flowkey,flowdata);
173                std::pair<flows_t::iterator,bool> ins= flows.insert(insdata);
174                it = ins.first;
175        }
176
177        ++it->second.packets;
178        it->second.bytes+=trace_get_capture_length(packet);
179
180        ++total_packets;
181        total_bytes+=trace_get_capture_length(packet);
182
183}
184
185struct flow_data_t {
186        uint64_t bytes;
187        uint64_t packets;
188        struct sockaddr_storage sip;
189        struct sockaddr_storage dip;
190        uint16_t sport;
191        uint16_t dport;
192        uint8_t protocol;
193
194        bool operator< (const flow_data_t &b) const {
195                if (bytes != b.bytes) return bytes < b.bytes;
196                return packets < b.packets;
197        }
198};
199
200static void do_report()
201{
202        typedef  std::priority_queue<flow_data_t> pq_t;
203        int row,col;
204        pq_t pq;
205        for(flows_t::const_iterator it=flows.begin();it!=flows.end();++it) {
206                flow_data_t data;
207                data.bytes = it->second.bytes,
208                data.packets = it->second.packets,
209                data.sip = it->first.sip;
210                data.dip = it->first.dip;
211                data.sport = it->first.sport;
212                data.dport = it->first.dport;
213                data.protocol = it->first.protocol;
214                pq.push(data);
215        }
216        getmaxyx(stdscr,row,col);
217        move(0,0);
218        printw("Total Bytes: %10" PRIu64 " (%s)\tTotal Packets: %10" PRIu64, total_bytes, nice_bandwidth(total_bytes/interval), total_packets);
219        clrtoeol();
220        attrset(A_REVERSE);
221        move(1,0);
222        if (use_sip) {
223                printw("%20s", "source ip");
224                if (use_sport)
225                        printw("/");
226                else
227                        printw("\t");
228        }
229        if (use_sport)
230                printw("%d\t", "sport");
231        if (use_dip) {
232                printw("%20s", "dest ip");
233                if (use_dport)
234                        printw("/");
235                else
236                        printw("\t");
237        }
238        if (use_dport)
239                printw("%d\t", "dport");
240        if (use_protocol)
241                printw("proto\t");
242        switch(display_as) {
243                case BYTES:
244                        printw("%7s","Bytes\t");
245                        break;
246                case BITS_PER_SEC:
247                        printw("%14s\t","Bits/sec");
248                        break;
249                case PERCENT:
250                        printw("%% bytes\t");
251                        break;
252        }
253        printw("Packets");
254
255        attrset(A_NORMAL);
256        char sipstr[1024];
257        char dipstr[1024];
258        for(int i=1; i<row-3 && !pq.empty(); ++i) {
259                move(i+1,0);
260                if (use_sip) {
261                        printw("%20s",
262                                trace_sockaddr2string((struct sockaddr*)&pq.top().sip,
263                                        sizeof(struct sockaddr_storage),
264                                        sipstr,sizeof(sipstr)));
265                        if (use_sport)
266                                printw("/");
267                        else
268                                printw("\t");
269                }
270                if (use_sport)
271                        printw("%-5d\t", pq.top().sport);
272                if (use_dip) {
273                        printw("%20s",
274                                trace_sockaddr2string((struct sockaddr*)&pq.top().dip,
275                                        sizeof(struct sockaddr_storage),
276                                        dipstr,sizeof(dipstr)));
277                        if (use_dport)
278                                printw("/");
279                        else
280                                printw("\t");
281                }
282                if (use_dport)
283                        printw("%-5d\t", pq.top().dport);
284                if (use_protocol) {
285                        struct protoent *proto = getprotobynumber(pq.top().protocol);
286                        if (proto) 
287                                printw("%-5s\t", proto->p_name);
288                        else
289                                printw("%5d\t",pq.top().protocol);
290                }
291                switch (display_as) {
292                        case BYTES:
293                                printw("%7"PRIu64"\t%7"PRIu64"\n",
294                                                pq.top().bytes,
295                                                pq.top().packets);
296                                break;
297                        case BITS_PER_SEC:
298                                printw("%14.03f\t%"PRIu64"\n",
299                                                8.0*pq.top().bytes/interval,
300                                                pq.top().packets);
301                        case PERCENT:
302                                printw("%6.2f%%\t%6.2f%%\n",
303                                                100.0*pq.top().bytes/total_bytes,
304                                                100.0*pq.top().packets/total_packets);
305                }
306                pq.pop();
307        }
308        flows.clear();
309        total_packets = 0;
310        total_bytes = 0;
311
312        clrtobot();
313        refresh();
314}
315
316static void usage(char *argv0)
317{
318        fprintf(stderr,"usage: %s [ --filter | -f bpfexp ]  [ --snaplen | -s snap ]\n\t\t[ --promisc | -p flag] [ --help | -h ] [ --libtrace-help | -H ] libtraceuri...\n",argv0);
319}
320
321int main(int argc, char *argv[])
322{
323        libtrace_t *trace;
324        libtrace_packet_t *packet;
325        libtrace_filter_t *filter=NULL;
326        int snaplen=-1;
327        int promisc=-1;
328        double last_report=0;
329
330        setprotoent(1);
331
332        while(1) {
333                int option_index;
334                struct option long_options[] = {
335                        { "filter",             1, 0, 'f' },
336                        { "snaplen",            1, 0, 's' },
337                        { "promisc",            1, 0, 'p' },
338                        { "help",               0, 0, 'h' },
339                        { "libtrace-help",      0, 0, 'H' },
340                        { "bits-per-sec",       0, 0, 'B' },
341                        { "percent",            0, 0, 'P' },
342                        { "interval",           1, 0, 'i' },
343                        { NULL,                 0, 0, 0 }
344                };
345
346                int c= getopt_long(argc, argv, "f:s:p:hHi:",
347                                long_options, &option_index);
348
349                if (c==-1)
350                        break;
351
352                switch (c) {
353                        case 'f':
354                                filter=trace_create_filter(optarg);
355                                break;
356                        case 's':
357                                snaplen=atoi(optarg);
358                                break;
359                        case 'p':
360                                promisc=atoi(optarg);
361                                break;
362                        case 'H':
363                                trace_help();
364                                return 1;
365                        case 'B':
366                                display_as = BITS_PER_SEC;
367                                break;
368                        case 'P':
369                                display_as = PERCENT;
370                                break;
371                        case 'i':
372                                interval = atof(optarg);
373                                if (interval<=0) {
374                                        fprintf(stderr,"Interval must be >0\n");
375                                        return 1;
376                                }
377                                break;
378                        default:
379                                fprintf(stderr,"Unknown option: %c\n",c);
380                                /* FALL THRU */
381                        case 'h':
382                                usage(argv[0]);
383                                return 1;
384                }
385        }
386
387        if (optind>=argc) {
388                fprintf(stderr,"Missing input uri\n");
389                usage(argv[0]);
390                return 1;
391        }
392
393        initscr(); cbreak(); noecho();
394
395        while (optind<argc) {
396                trace = trace_create(argv[optind]);
397                ++optind;
398
399                if (trace_is_err(trace)) {
400                        endwin();
401                        trace_perror(trace,"Opening trace file");
402                        return 1;
403                }
404
405                if (snaplen>0)
406                        if (trace_config(trace,TRACE_OPTION_SNAPLEN,&snaplen)) {
407                                trace_perror(trace,"ignoring: ");
408                        }
409                if (filter)
410                        if (trace_config(trace,TRACE_OPTION_FILTER,filter)) {
411                                trace_perror(trace,"ignoring: ");
412                        }
413                if (promisc!=-1) {
414                        if (trace_config(trace,TRACE_OPTION_PROMISC,&promisc)) {
415                                trace_perror(trace,"ignoring: ");
416                        }
417                }
418
419                if (trace_start(trace)) {
420                        endwin();
421                        trace_perror(trace,"Starting trace");
422                        trace_destroy(trace);
423                        return 1;
424                }
425
426                packet = trace_create_packet();
427
428                while (trace_read_packet(trace,packet)>0) {
429                        if (trace_get_seconds(packet) - last_report >= interval) {
430                                do_report();
431                                       
432                                last_report=trace_get_seconds(packet);
433                        }
434                        per_packet(packet);
435                }
436
437                trace_destroy_packet(packet);
438
439                if (trace_is_err(trace)) {
440                        trace_perror(trace,"Reading packets");
441                }
442
443                trace_destroy(trace);
444        }
445
446        endwin();
447        endprotoent();
448
449        return 0;
450}
Note: See TracBrowser for help on using the repository browser.