source: tools/tracetop/tracetop.cc @ 2528816

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

Visual cleanups of column headings

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