source: tools/tracetop/tracetop.cc @ 59751a5

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

have trace_get_source_address() / trace_get_destination_address() return link layer addresses
where possible.

  • 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        trace_get_transport(packet,&flowkey.protocol, NULL);
133        flowkey.sport = trace_get_source_port(packet);
134        flowkey.dport = trace_get_destination_port(packet);
135
136        it = flows.find(flowkey);
137        if (it == flows.end()) {
138                flowdata_t flowdata = { 0, 0 };
139                flows_t::value_type insdata(flowkey,flowdata);
140                std::pair<flows_t::iterator,bool> ins= flows.insert(insdata);
141                it = ins.first;
142        }
143
144        ++it->second.packets;
145        it->second.bytes+=trace_get_capture_length(packet);
146
147}
148
149struct flow_data_t {
150        uint64_t bytes;
151        uint64_t packets;
152        struct sockaddr_storage sip;
153        struct sockaddr_storage dip;
154        uint16_t sport;
155        uint16_t dport;
156        uint8_t protocol;
157
158        bool operator< (const flow_data_t &b) const {
159                if (bytes != b.bytes) return bytes < b.bytes;
160                return packets < b.packets;
161        }
162};
163
164static void do_report()
165{
166        typedef  std::priority_queue<flow_data_t> pq_t;
167        int row,col;
168        pq_t pq;
169        for(flows_t::const_iterator it=flows.begin();it!=flows.end();++it) {
170                flow_data_t data;
171                data.bytes = it->second.bytes,
172                data.packets = it->second.packets,
173                data.sip = it->first.sip;
174                data.dip = it->first.dip;
175                data.sport = it->first.sport;
176                data.dport = it->first.dport;
177                data.protocol = it->first.protocol;
178                pq.push(data);
179        }
180        getmaxyx(stdscr,row,col);
181        attrset(A_REVERSE);
182        mvprintw(0,0,"%15s:%s\t%15s:%s\tproto\tbytes\tpackets\n",
183                "sip","sport",
184                "dip","dport"
185                );
186        attrset(A_NORMAL);
187        char sipstr[1024];
188        char dipstr[1024];
189        for(int i=0; i<row-2 && !pq.empty(); ++i) {
190                mvprintw(i+1,0,"%s/%d\t%s/%d\t%d\t%"PRIu64"\t%"PRIu64"\n",
191                                trace_sockaddr2string((struct sockaddr*)&pq.top().sip,
192                                        sizeof(struct sockaddr_storage),
193                                        sipstr,sizeof(sipstr)), 
194                                pq.top().sport,
195                                trace_sockaddr2string((struct sockaddr*)&pq.top().dip,
196                                        sizeof(struct sockaddr_storage),
197                                        dipstr,sizeof(dipstr)), 
198                                pq.top().dport,
199                                pq.top().protocol,
200                                pq.top().bytes,
201                                pq.top().packets);
202                pq.pop();
203        }
204        flows.clear();
205
206        refresh();
207}
208
209static void usage(char *argv0)
210{
211        fprintf(stderr,"usage: %s [ --filter | -f bpfexp ]  [ --snaplen | -s snap ]\n\t\t[ --promisc | -p flag] [ --help | -h ] [ --libtrace-help | -H ] libtraceuri...\n",argv0);
212}
213
214int main(int argc, char *argv[])
215{
216        libtrace_t *trace;
217        libtrace_packet_t *packet;
218        libtrace_filter_t *filter=NULL;
219        int snaplen=-1;
220        int promisc=-1;
221        double last_report=0;
222
223        while(1) {
224                int option_index;
225                struct option long_options[] = {
226                        { "filter",             1, 0, 'f' },
227                        { "snaplen",            1, 0, 's' },
228                        { "promisc",            1, 0, 'p' },
229                        { "help",               0, 0, 'h' },
230                        { "libtrace-help",      0, 0, 'H' },
231                        { NULL,                 0, 0, 0 }
232                };
233
234                int c= getopt_long(argc, argv, "f:s:p:hH",
235                                long_options, &option_index);
236
237                if (c==-1)
238                        break;
239
240                switch (c) {
241                        case 'f':
242                                filter=trace_create_filter(optarg);
243                                break;
244                        case 's':
245                                snaplen=atoi(optarg);
246                                break;
247                        case 'p':
248                                promisc=atoi(optarg);
249                                break;
250                        case 'H':
251                                trace_help();
252                                return 1;
253                        default:
254                                fprintf(stderr,"Unknown option: %c\n",c);
255                                /* FALL THRU */
256                        case 'h':
257                                usage(argv[0]);
258                                return 1;
259                }
260        }
261
262        if (optind>=argc) {
263                fprintf(stderr,"Missing input uri\n");
264                usage(argv[0]);
265                return 1;
266        }
267
268        initscr(); cbreak(); noecho();
269
270        while (optind<argc) {
271                trace = trace_create(argv[optind]);
272                ++optind;
273
274                if (trace_is_err(trace)) {
275                        endwin();
276                        trace_perror(trace,"Opening trace file");
277                        return 1;
278                }
279
280                if (snaplen>0)
281                        if (trace_config(trace,TRACE_OPTION_SNAPLEN,&snaplen)) {
282                                trace_perror(trace,"ignoring: ");
283                        }
284                if (filter)
285                        if (trace_config(trace,TRACE_OPTION_FILTER,filter)) {
286                                trace_perror(trace,"ignoring: ");
287                        }
288                if (promisc!=-1) {
289                        if (trace_config(trace,TRACE_OPTION_PROMISC,&promisc)) {
290                                trace_perror(trace,"ignoring: ");
291                        }
292                }
293
294                if (trace_start(trace)) {
295                        endwin();
296                        trace_perror(trace,"Starting trace");
297                        trace_destroy(trace);
298                        return 1;
299                }
300
301                packet = trace_create_packet();
302
303                while (trace_read_packet(trace,packet)>0) {
304                        if (trace_get_seconds(packet) - last_report > 1) {
305                                do_report();
306                                       
307                                last_report=trace_get_seconds(packet);
308                        }
309                        per_packet(packet);
310                }
311
312                trace_destroy_packet(packet);
313
314                if (trace_is_err(trace)) {
315                        trace_perror(trace,"Reading packets");
316                }
317
318                trace_destroy(trace);
319        }
320
321        endwin();
322
323        return 0;
324}
Note: See TracBrowser for help on using the repository browser.