source: tools/traceflow/traceflow.cc @ b25f4b0

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since b25f4b0 was b25f4b0, checked in by Shane Alcock <salcock@…>, 15 years ago

Added a new report type to tracereport which can be used to provide stats as to how much traffic is national / international based on the IP addresses involved. This report does require the user to provide a list of "local" IP ranges.
Replaced the "remove" call in traceflow which should make it run a lot faster.

  • Property mode set to 100644
File size: 6.8 KB
Line 
1#include <stdlib.h>
2#include <stdio.h>
3#include <inttypes.h>
4#include <assert.h>
5#include <string.h>
6#include <unistd.h>
7#include <strings.h>
8#include <map>
9#include <list>
10
11#include "libtrace.h"
12#include "connid.h"
13
14uint32_t info_freq = 180;
15double last_report = 0.0;
16
17uint32_t new_flows = 0;
18uint32_t f_exp = 0;
19
20class Direction {
21        public:
22                uint32_t packet_count;
23                uint32_t byte_count;
24
25                Direction() {
26                        this->packet_count = 0;
27                        this->byte_count = 0;
28                }
29};
30
31typedef std::list<class Flow*> FlowList;
32
33class Flow {
34        public:
35                Connid id;
36                double expiry_ts;
37                Direction dir[2];
38       
39                double first_pkt_ts;
40                double last_pkt_ts;
41               
42                FlowList *flow_list;   
43       
44                Flow(const Connid conn_id) {
45                        this->id = conn_id;
46                        this->expiry_ts = 0;
47                        this->first_pkt_ts = 0;
48                        this->last_pkt_ts = 0;
49                }
50};
51
52typedef std::map<Connid, FlowList::iterator> FlowMap;
53typedef std::list<class Flow *> ExpiredFlowList;
54
55FlowList active_lru;
56FlowList inactive;
57
58FlowMap active_flows;
59ExpiredFlowList expired_flows;
60
61Flow *getFlow(libtrace_packet_t *packet) {
62        uint16_t src_port, dst_port;
63        libtrace_ip_t *ip;
64        Connid pkt_id;
65
66        ip = trace_get_ip(packet);
67        src_port = trace_get_source_port(packet);
68        dst_port = trace_get_destination_port(packet);
69
70        if (trace_get_server_port(ip->ip_p, src_port, dst_port) == USE_SOURCE) {
71                /* Server port = source port */
72                pkt_id = Connid(ip->ip_src.s_addr, ip->ip_dst.s_addr,
73                                        src_port, dst_port, ip->ip_p);
74        } else {
75                /* Server port = dest port */
76                pkt_id = Connid(ip->ip_dst.s_addr, ip->ip_src.s_addr,
77                                        dst_port, src_port, ip->ip_p);
78        }
79
80        /* Is it in the map? */
81        FlowMap::iterator i = active_flows.find(pkt_id);
82
83        if (i != active_flows.end()) {
84                Flow * pkt_flow = *((*i).second);
85                return pkt_flow;
86        }
87       
88       
89        /* Not in map - new connection */
90        Flow *new_flow = new Flow(pkt_id);
91        new_flow->flow_list = &active_lru;
92        new_flow->first_pkt_ts = trace_get_seconds(packet);
93        active_lru.push_front(new_flow);
94        active_flows[new_flow->id] = active_lru.begin();
95        new_flows ++;
96        return new_flow;
97
98}
99
100void update_expiry(Flow *flow, double ts) {
101       
102        double timeout = 5.0;
103        FlowList *lru = &active_lru;
104       
105        flow->expiry_ts = ts + timeout;
106        flow->flow_list->erase(active_flows[flow->id]);
107        flow->flow_list = lru;
108        lru->push_front(flow);
109        active_flows[flow->id] = lru->begin();
110}
111
112
113void expire_conns_lru(FlowList *lru, double ts) {
114
115        FlowList::iterator i;
116        while (!lru->empty()) {
117                Flow *flow = lru->back();
118                if (flow->expiry_ts <= ts) {
119                        lru->pop_back();
120                        /* Move into inactive list */
121                        flow->flow_list = &inactive;
122                        inactive.push_front(flow);
123                        active_flows[flow->id] = inactive.begin();
124                } else {
125                        break;
126                }
127        }
128}
129
130double extract_data(Flow *pkt_flow, libtrace_packet_t *packet) {
131        double timestamp = trace_get_seconds(packet);
132        libtrace_ip_t *ip = trace_get_ip(packet);
133        libtrace_direction_t pkt_dir = trace_get_direction(packet);
134       
135        uint32_t ip_pkt_size = ntohs(ip->ip_len);
136        pkt_flow->dir[pkt_dir].byte_count += ip_pkt_size;
137        pkt_flow->dir[pkt_dir].packet_count ++;
138
139        update_expiry(pkt_flow, timestamp);
140        expire_conns_lru(&active_lru, timestamp);
141       
142        return timestamp;
143               
144}
145
146void print_flow_stdout(Flow *f) {
147       
148        /* Textual representation - good for testing :] */     
149        printf("%s ", f->id.get_server_ip_str());
150        printf("%s ", f->id.get_client_ip_str());
151        printf("%u ", f->id.get_server_port());
152        printf("%u ", f->id.get_client_port());
153        printf("%u\n", f->id.get_protocol());
154
155        printf("\t Outgoing Bytes: %-14u\tOutgoing Packets: %-10u\n", f->dir[0].byte_count, f->dir[0].packet_count);
156        printf("\t Incoming Bytes: %-14u\tIncoming Packets: %-10u\n", f->dir[1].byte_count, f->dir[1].packet_count);
157        fflush(stdout); 
158}
159
160void export_flow(Flow *f) {
161        print_flow_stdout(f);
162
163}
164
165void calc_expiry_ts(Flow *f) {
166        double interval = (f->last_pkt_ts - f->first_pkt_ts) / (f->dir[0].packet_count + f->dir[1].packet_count);
167
168        double exp_time = f->last_pkt_ts + (interval * 20);
169        f->expiry_ts = exp_time;
170}
171
172void produce_report(double report_time) {
173        printf("Report produced at %.6f trace time\n", report_time);
174       
175        printf("Active Flows\n");
176        printf("-------------------------\n");
177
178        FlowList::iterator i;
179        for (i = active_lru.begin(); i != active_lru.end(); i++) {
180                Flow *f = *i;
181
182                export_flow(f);
183        }
184       
185        for (i = inactive.begin(); i != inactive.end();) {
186                Flow *f = *i;
187
188                calc_expiry_ts(f);
189                if (f->expiry_ts < report_time) {
190                        expired_flows.push_front(f);
191                        inactive.erase(i++);
192                        active_flows.erase(f->id);
193                } else {
194                        export_flow(f);
195                        ++i;
196                }
197        }
198       
199       
200        printf("\nExpired Flows\n");
201        printf("===========================\n");
202
203       
204        while (!expired_flows.empty()) {
205               
206                Flow *f = expired_flows.front();
207                export_flow(f);
208                f_exp ++;
209                expired_flows.pop_front();
210                delete(f);     
211        }
212        expired_flows.clear();
213        assert(expired_flows.size() == 0);
214        printf("**********************\n");
215        printf("New flows added since last report: %d\n", new_flows);
216        printf("Flows expired since last report: %d\n", f_exp);
217        printf("Unexpired flows: %d\n", active_lru.size() + inactive.size());
218        printf("**********************\n\n");
219       
220        new_flows = 0;
221        f_exp = 0;
222}
223
224void per_packet(libtrace_packet_t *packet) {
225        double timestamp;
226
227        if (trace_get_ip(packet) == NULL) return;
228
229        Flow * pkt_flow = getFlow(packet);
230        timestamp = extract_data(pkt_flow, packet);
231        if (timestamp < 0)
232                return;
233
234        pkt_flow->last_pkt_ts = timestamp;
235        if (last_report == 0.0)
236                last_report = timestamp;
237       
238        if (timestamp > last_report + info_freq) {
239                last_report += info_freq;
240                produce_report(last_report);
241        }
242}
243
244void usage(char *prog) {
245        fprintf(stderr,"Usage: %s tracefile...\n",prog);
246}
247
248int main(int argc, char *argv[]) {
249
250        int opt;
251        libtrace_t *trace;
252        libtrace_packet_t *packet;
253
254        while ((opt = getopt(argc, argv, "f:")) != EOF) {
255                switch(opt) {
256                        case 'f':
257                                printf("Filtering not supported yet\n");
258                                break;
259                        default:
260                                usage(argv[0]);
261                }
262        }
263
264        if (optind + 1 > argc) {
265                usage(argv[0]);
266                return 1;
267        }
268        packet = trace_create_packet();
269
270        for (int i = optind; i < argc; i++) {
271                trace = trace_create(argv[i]);
272
273                if (trace_is_err(trace)) {
274                        trace_perror(trace,"Opening trace file");
275                        return 1;
276                }
277
278                if (trace_start(trace)) {
279                        trace_perror(trace,"Starting trace");
280                        trace_destroy(trace);
281                        return 1;
282                }
283
284
285                while (trace_read_packet(trace,packet)>0) {
286                        per_packet(packet);
287                }
288
289
290                if (trace_is_err(trace)) {
291                        trace_perror(trace,"Reading packets");
292                        trace_destroy(trace);
293                        continue;
294                }
295
296                trace_destroy(trace);
297        }
298        trace_destroy_packet(packet);
299        return 0;
300}       
Note: See TracBrowser for help on using the repository browser.