source: tools/tracetop/tracetop.cc @ d4242e4

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

Support IPv4/IPv6 addresses.

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