source: tools/tracetop/tracetop.cc @ 752353b

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

Allow for bits per second measurements

  • Property mode set to 100644
File size: 7.9 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 } display_t;
23display_t display_as = BYTES;
24int interval=1;
25
26int cmp_sockaddr_in6(const struct sockaddr_in6 *a, const struct sockaddr_in6 *b)
27{
28        if (a->sin6_port != b->sin6_port)
29                return a->sin6_port - b->sin6_port;
30        return memcmp(a->sin6_addr.s6_addr,b->sin6_addr.s6_addr,sizeof(a->sin6_addr.s6_addr));
31}
32
33int cmp_sockaddr_in(const struct sockaddr_in *a, const struct sockaddr_in *b)
34{
35        if (a->sin_port != b->sin_port)
36                return a->sin_port - b->sin_port;
37        return a->sin_addr.s_addr - b->sin_addr.s_addr;
38}
39
40#ifdef HAVE_NETPACKET_PACKET_H
41int cmp_sockaddr_ll(const struct sockaddr_ll *a, const struct sockaddr_ll *b)
42{
43        return memcmp(a->sll_addr, b->sll_addr, b->sll_halen);
44}
45#endif
46
47int cmp_sockaddr(const struct sockaddr *a, const struct sockaddr *b)
48{
49        if (a->sa_family != b->sa_family) {
50                return a->sa_family - b->sa_family;
51        }
52        switch (a->sa_family) {
53                case AF_INET:
54                        return cmp_sockaddr_in((struct sockaddr_in *)a,(struct sockaddr_in*)b);
55                case AF_INET6:
56                        return cmp_sockaddr_in6((struct sockaddr_in6 *)a,(struct sockaddr_in6*)b);
57#ifdef HAVE_NETPACKET_PACKET_H
58                case AF_PACKET:
59                        return cmp_sockaddr_ll((struct sockaddr_ll *)a,(struct sockaddr_ll*)b);
60#endif
61                case AF_UNSPEC:
62                        return 0; /* Can't compare UNSPEC's! */
63                default:
64                        fprintf(stderr,"Don't know how to compare family %d\n",a->sa_family);
65                        abort();
66        }
67}
68
69char *trace_sockaddr2string(const struct sockaddr *a, socklen_t salen, char *buffer, size_t bufflen)
70{
71        static char intbuffer[NI_MAXHOST];
72        char *mybuf = buffer ? buffer : intbuffer;
73        size_t mybufflen = buffer ? bufflen : sizeof(intbuffer);
74        int err;
75        switch (a->sa_family) {
76                case AF_INET:
77                case AF_INET6:
78                        if ((err=getnameinfo(a, salen, mybuf, mybufflen, NULL, 0, NI_NUMERICHOST))!=0) {
79                                strncpy(mybuf,gai_strerror(err),mybufflen);
80                        }
81                        break;
82#ifdef HAVE_NETPACKET_PACKET_H
83                case AF_PACKET:
84                        trace_ether_ntoa(((struct sockaddr_ll*)a)->sll_addr, mybuf);
85                        break;
86#endif
87                default:
88                        snprintf(mybuf,mybufflen,"Unknown family %d",a->sa_family);
89        }
90        return mybuf;
91}
92
93struct flowkey_t {
94        struct sockaddr_storage sip;
95        struct sockaddr_storage dip;
96        uint16_t sport;
97        uint16_t dport;
98        uint8_t protocol;
99
100        bool operator <(const flowkey_t &b) const {
101                int c;
102
103                c = cmp_sockaddr((struct sockaddr*)&sip,(struct sockaddr*)&b.sip);
104                if (c != 0) return c<0;
105                c = cmp_sockaddr((struct sockaddr*)&dip,(struct sockaddr*)&b.dip);
106                if (c != 0) return c<0;
107
108                if (sport != b.sport) return sport < b.sport;
109                if (dport != b.dport) return dport < b.dport;
110
111                return protocol < b.protocol;
112        }
113};
114
115struct flowdata_t {
116        uint64_t packets;
117        uint64_t bytes;
118};
119
120typedef std::map<flowkey_t,flowdata_t> flows_t;
121
122flows_t flows;
123
124static void per_packet(libtrace_packet_t *packet)
125{
126        flowkey_t flowkey;
127        flows_t::iterator it;
128
129        if (trace_get_source_address(packet,(struct sockaddr*)&flowkey.sip)==NULL)
130                flowkey.sip.ss_family = AF_UNSPEC;
131        if (trace_get_destination_address(packet,(struct sockaddr*)&flowkey.dip)==NULL)
132                flowkey.dip.ss_family = AF_UNSPEC;
133        if (trace_get_transport(packet,&flowkey.protocol, NULL) == NULL)
134                flowkey.protocol = NULL;
135        flowkey.sport = trace_get_source_port(packet);
136        flowkey.dport = trace_get_destination_port(packet);
137
138        it = flows.find(flowkey);
139        if (it == flows.end()) {
140                flowdata_t flowdata = { 0, 0 };
141                flows_t::value_type insdata(flowkey,flowdata);
142                std::pair<flows_t::iterator,bool> ins= flows.insert(insdata);
143                it = ins.first;
144        }
145
146        ++it->second.packets;
147        it->second.bytes+=trace_get_capture_length(packet);
148
149}
150
151struct flow_data_t {
152        uint64_t bytes;
153        uint64_t packets;
154        struct sockaddr_storage sip;
155        struct sockaddr_storage dip;
156        uint16_t sport;
157        uint16_t dport;
158        uint8_t protocol;
159
160        bool operator< (const flow_data_t &b) const {
161                if (bytes != b.bytes) return bytes < b.bytes;
162                return packets < b.packets;
163        }
164};
165
166static void do_report()
167{
168        typedef  std::priority_queue<flow_data_t> pq_t;
169        int row,col;
170        pq_t pq;
171        for(flows_t::const_iterator it=flows.begin();it!=flows.end();++it) {
172                flow_data_t data;
173                data.bytes = it->second.bytes,
174                data.packets = it->second.packets,
175                data.sip = it->first.sip;
176                data.dip = it->first.dip;
177                data.sport = it->first.sport;
178                data.dport = it->first.dport;
179                data.protocol = it->first.protocol;
180                pq.push(data);
181        }
182        getmaxyx(stdscr,row,col);
183        attrset(A_REVERSE);
184        mvprintw(0,0,"%20s/%s\t%20s/%s\tproto\t%s\tpackets\n",
185                "source ip","sport",
186                "dest ip","dport",
187                (display_as == BYTES ? "bytes" : "bits/sec")
188                );
189        attrset(A_NORMAL);
190        char sipstr[1024];
191        char dipstr[1024];
192        for(int i=0; i<row-2 && !pq.empty(); ++i) {
193                mvprintw(i+1,0,"%20s/%-5d\t%20s/%-5d\t%d\t",
194                                trace_sockaddr2string((struct sockaddr*)&pq.top().sip,
195                                        sizeof(struct sockaddr_storage),
196                                        sipstr,sizeof(sipstr)), 
197                                pq.top().sport,
198                                trace_sockaddr2string((struct sockaddr*)&pq.top().dip,
199                                        sizeof(struct sockaddr_storage),
200                                        dipstr,sizeof(dipstr)), 
201                                pq.top().dport,
202                                pq.top().protocol);
203                switch (display_as) {
204                        case BYTES:
205                                printw("%"PRIu64"\t%"PRIu64"\n",
206                                                pq.top().bytes,
207                                                pq.top().packets);
208                                break;
209                        case BITS_PER_SEC:
210                                printw("%8.03f\t%"PRIu64"\n",
211                                                8.0*pq.top().bytes/interval,
212                                                pq.top().packets);
213                }
214                pq.pop();
215        }
216        flows.clear();
217
218        clrtobot();
219        refresh();
220}
221
222static void usage(char *argv0)
223{
224        fprintf(stderr,"usage: %s [ --filter | -f bpfexp ]  [ --snaplen | -s snap ]\n\t\t[ --promisc | -p flag] [ --help | -h ] [ --libtrace-help | -H ] libtraceuri...\n",argv0);
225}
226
227int main(int argc, char *argv[])
228{
229        libtrace_t *trace;
230        libtrace_packet_t *packet;
231        libtrace_filter_t *filter=NULL;
232        int snaplen=-1;
233        int promisc=-1;
234        double last_report=0;
235
236        while(1) {
237                int option_index;
238                struct option long_options[] = {
239                        { "filter",             1, 0, 'f' },
240                        { "snaplen",            1, 0, 's' },
241                        { "promisc",            1, 0, 'p' },
242                        { "help",               0, 0, 'h' },
243                        { "libtrace-help",      0, 0, 'H' },
244                        { "bits-per-sec",       0, 0, 'b' },
245                        { NULL,                 0, 0, 0 }
246                };
247
248                int c= getopt_long(argc, argv, "f:s:p:hH",
249                                long_options, &option_index);
250
251                if (c==-1)
252                        break;
253
254                switch (c) {
255                        case 'f':
256                                filter=trace_create_filter(optarg);
257                                break;
258                        case 's':
259                                snaplen=atoi(optarg);
260                                break;
261                        case 'p':
262                                promisc=atoi(optarg);
263                                break;
264                        case 'H':
265                                trace_help();
266                                return 1;
267                        case 'b':
268                                display_as = BITS_PER_SEC;
269                                break;
270                        default:
271                                fprintf(stderr,"Unknown option: %c\n",c);
272                                /* FALL THRU */
273                        case 'h':
274                                usage(argv[0]);
275                                return 1;
276                }
277        }
278
279        if (optind>=argc) {
280                fprintf(stderr,"Missing input uri\n");
281                usage(argv[0]);
282                return 1;
283        }
284
285        initscr(); cbreak(); noecho();
286
287        while (optind<argc) {
288                trace = trace_create(argv[optind]);
289                ++optind;
290
291                if (trace_is_err(trace)) {
292                        endwin();
293                        trace_perror(trace,"Opening trace file");
294                        return 1;
295                }
296
297                if (snaplen>0)
298                        if (trace_config(trace,TRACE_OPTION_SNAPLEN,&snaplen)) {
299                                trace_perror(trace,"ignoring: ");
300                        }
301                if (filter)
302                        if (trace_config(trace,TRACE_OPTION_FILTER,filter)) {
303                                trace_perror(trace,"ignoring: ");
304                        }
305                if (promisc!=-1) {
306                        if (trace_config(trace,TRACE_OPTION_PROMISC,&promisc)) {
307                                trace_perror(trace,"ignoring: ");
308                        }
309                }
310
311                if (trace_start(trace)) {
312                        endwin();
313                        trace_perror(trace,"Starting trace");
314                        trace_destroy(trace);
315                        return 1;
316                }
317
318                packet = trace_create_packet();
319
320                while (trace_read_packet(trace,packet)>0) {
321                        if (trace_get_seconds(packet) - last_report >= interval) {
322                                do_report();
323                                       
324                                last_report=trace_get_seconds(packet);
325                        }
326                        per_packet(packet);
327                }
328
329                trace_destroy_packet(packet);
330
331                if (trace_is_err(trace)) {
332                        trace_perror(trace,"Reading packets");
333                }
334
335                trace_destroy(trace);
336        }
337
338        endwin();
339
340        return 0;
341}
Note: See TracBrowser for help on using the repository browser.