source: tools/tracetop/tracetop.cc @ c9754d0

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