iptables-test: Support for chain flushing
[framework/connectivity/connman.git] / tools / stats-ringbuffer-dump.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2010  BMW Car IT GmbH. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #define _GNU_SOURCE
26 #include <sys/mman.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/time.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <limits.h>
34 #include <time.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <errno.h>
38
39 #define MAGIC 0xFA00B916
40
41 struct connman_stats_data {
42         unsigned int rx_packets;
43         unsigned int tx_packets;
44         unsigned int rx_bytes;
45         unsigned int tx_bytes;
46         unsigned int rx_errors;
47         unsigned int tx_errors;
48         unsigned int rx_dropped;
49         unsigned int tx_dropped;
50         unsigned int time;
51 };
52
53 struct stats_file_header {
54         unsigned int magic;
55         unsigned int begin;
56         unsigned int end;
57         unsigned int home;
58         unsigned int roaming;
59 };
60
61 struct stats_record {
62         time_t ts;
63         unsigned int roaming;
64         struct connman_stats_data data;
65 };
66
67 struct stats_file {
68         int fd;
69         char *name;
70         char *addr;
71         size_t len;
72
73         /* cached values */
74         int max_nr;
75         int nr;
76         struct stats_record *first;
77         struct stats_record *last;
78         struct stats_record *home_first;
79         struct stats_record *roaming_first;
80 };
81
82 static struct stats_file_header *get_hdr(struct stats_file *file)
83 {
84         return (struct stats_file_header *)file->addr;
85 }
86
87 static struct stats_record *get_begin(struct stats_file *file)
88 {
89         unsigned int off = get_hdr(file)->begin;
90
91         return (struct stats_record *)(file->addr + off);
92 }
93
94 static struct stats_record *get_end(struct stats_file *file)
95 {
96         unsigned int off = get_hdr(file)->end;
97
98         return (struct stats_record *)(file->addr + off);
99 }
100
101 static struct stats_record *get_home(struct stats_file *file)
102 {
103         struct stats_file_header *hdr;
104
105         hdr = get_hdr(file);
106
107         if (hdr->home == UINT_MAX)
108                 return NULL;
109
110         return (struct stats_record *)(file->addr + hdr->home);
111 }
112
113 static struct stats_record *get_roaming(struct stats_file *file)
114 {
115         struct stats_file_header *hdr;
116
117         hdr = get_hdr(file);
118
119         if (hdr->roaming == UINT_MAX)
120                 return NULL;
121
122         return (struct stats_record *)(file->addr + hdr->roaming);
123 }
124
125 static struct stats_record *get_next(struct stats_file *file,
126                                         struct stats_record *cur)
127 {
128         cur++;
129
130         if (cur > file->last)
131                 cur = file->first;
132
133         return cur;
134 }
135
136 static int get_index(struct stats_file *file, struct stats_record *rec)
137 {
138         return rec - file->first;
139 }
140
141 static void stats_print_record(struct stats_record *rec)
142 {
143         char buffer[30];
144
145         strftime(buffer, 30, "%d-%m-%Y %T", localtime(&rec->ts));
146         printf("%p %s %01d %d %d %d %d %d %d %d %d %d\n", rec, buffer,
147                 rec->roaming,
148                 rec->data.rx_packets,
149                 rec->data.tx_packets,
150                 rec->data.rx_bytes,
151                 rec->data.tx_bytes,
152                 rec->data.rx_errors,
153                 rec->data.tx_errors,
154                 rec->data.rx_dropped,
155                 rec->data.tx_dropped,
156                 rec->data.time);
157 }
158
159 static void stats_hdr_info(struct stats_file *file)
160 {
161         struct stats_file_header *hdr;
162         struct stats_record *begin, *end, *home, *roaming;
163         unsigned int home_idx, roaming_idx;
164
165         hdr = get_hdr(file);
166         begin = get_begin(file);
167         end = get_end(file);
168
169         home = get_home(file);
170         if (home == NULL)
171                 home_idx = UINT_MAX;
172         else
173                 home_idx = get_index(file, home);
174
175         roaming = get_roaming(file);
176         if (roaming == NULL)
177                 roaming_idx = UINT_MAX;
178         else
179                 roaming_idx = get_index(file, roaming);
180
181         printf("Data Structure Sizes\n");
182         printf("  sizeof header   %zd/0x%02zx\n",
183                 sizeof(struct stats_file_header),
184                 sizeof(struct stats_file_header));
185         printf("  sizeof entry    %zd/0%02zx\n\n",
186                 sizeof(struct stats_record),
187                 sizeof(struct stats_record));
188
189         printf("File\n");
190         printf("  addr            %p\n",  file->addr);
191         printf("  len             %zd\n", file->len);
192
193         printf("  max nr entries  %d\n", file->max_nr);
194         printf("  nr entries      %d\n\n", file->nr);
195
196         printf("Header\n");
197         printf("  magic           0x%08x\n", hdr->magic);
198         printf("  begin           [%d] 0x%08x\n",
199                 get_index(file, begin), hdr->begin);
200         printf("  end             [%d] 0x%08x\n",
201                 get_index(file, end), hdr->end);
202         printf("  home            [%d] 0x%08x\n",
203                 home_idx, hdr->home);
204         printf("  roaming         [%d] 0x%08x\n\n",
205                 roaming_idx, hdr->roaming);
206
207
208         printf("Pointers\n");
209         printf("  hdr             %p\n", hdr);
210         printf("  begin           %p\n", begin);
211         printf("  end             %p\n", end);
212         printf("  home            %p\n", home);
213         printf("  romaing         %p\n", roaming);
214         printf("  first           %p\n", file->first);
215         printf("  last            %p\n\n", file->last);
216 }
217
218 static void stats_print_entries(struct stats_file *file)
219 {
220         struct stats_record *it;
221         int i;
222
223         printf("[ idx] ptr ts roaming rx_packets tx_packets rx_bytes "
224                 "tx_bytes rx_errors tx_errors rx_dropped tx_dropped time\n\n");
225
226         for (i = 0, it = file->first; it <= file->last; it++, i++) {
227                 printf("[%04d] ", i);
228                 stats_print_record(it);
229         }
230 }
231
232 static void stats_print_rec_diff(struct stats_record *begin,
233                                         struct stats_record *end)
234 {
235         printf("\trx_packets: %d\n",
236                 end->data.rx_packets - begin->data.rx_packets);
237         printf("\ttx_packets: %d\n",
238                 end->data.tx_packets - begin->data.tx_packets);
239         printf("\trx_bytes:   %d\n",
240                 end->data.rx_bytes - begin->data.rx_bytes);
241         printf("\ttx_bytes:   %d\n",
242                 end->data.tx_bytes - begin->data.tx_bytes);
243         printf("\trx_errors:  %d\n",
244                 end->data.rx_errors - begin->data.rx_errors);
245         printf("\ttx_errors:  %d\n",
246                 end->data.tx_errors - begin->data.tx_errors);
247         printf("\trx_dropped: %d\n",
248                 end->data.rx_dropped - begin->data.rx_dropped);
249         printf("\ttx_dropped: %d\n",
250                 end->data.tx_dropped - begin->data.tx_dropped);
251         printf("\ttime:       %d\n",
252                 end->data.time - begin->data.time);
253 }
254
255 static void stats_print_diff(struct stats_file *file)
256 {
257         struct stats_record *begin, *end;
258
259         begin = get_begin(file);
260         begin = get_next(file, begin);
261         end = get_end(file);
262
263         printf("\n(begin + 1)\n");
264         printf("\t[%04d] ", get_index(file, begin));
265         stats_print_record(begin);
266         printf("end\n");
267         printf("\t[%04d] ", get_index(file, end));
268         stats_print_record(end);
269
270         if (file->home_first) {
271                 printf("\nhome\n");
272                 stats_print_rec_diff(file->home_first, get_home(file));
273         }
274
275         if (file->roaming_first) {
276                 printf("\roaming\n");
277                 stats_print_rec_diff(file->roaming_first, get_roaming(file));
278         }
279 }
280
281 static void update_max_nr_entries(struct stats_file *file)
282 {
283         file->max_nr = (file->len - sizeof(struct stats_file_header)) /
284                 sizeof(struct stats_record);
285 }
286
287 static void update_nr_entries(struct stats_file *file)
288 {
289         struct stats_record *begin, *end;
290         int nr;
291
292         begin = get_begin(file);
293         end = get_end(file);
294
295         nr = get_index(file, end) - get_index(file, begin);
296
297         if (nr < 0)
298                 nr += file->max_nr;
299
300         file->nr = nr;
301 }
302
303 static void update_first(struct stats_file *file)
304 {
305         file->first = (struct stats_record *)(file->addr +
306                                         sizeof(struct stats_file_header));
307 }
308
309 static void update_last(struct stats_file *file)
310 {
311         struct stats_record *last;
312
313         last = file->first;
314         last += file->max_nr - 1;
315
316         file->last = last;
317 }
318
319 static int stats_file_update_cache(struct stats_file *file)
320 {
321         struct stats_record *it;
322
323         update_max_nr_entries(file);
324         update_nr_entries(file);
325         update_first(file);
326         update_last(file);
327
328         for (it = file->first; it <= file->last &&
329                      (file->home_first == NULL ||
330                              file->roaming_first == NULL); it++) {
331                 if (file->home_first == NULL && it->roaming == 0)
332                         file->home_first = it;
333
334                 if (file->roaming_first == NULL && it->roaming == 1)
335                         file->roaming_first = it;
336         }
337         return 0;
338 }
339
340 static int stats_file_mmap(struct stats_file *file, size_t size)
341 {
342         size_t page_size;
343
344         page_size = sysconf(_SC_PAGESIZE);
345         file->len = (size + page_size - 1) & ~(page_size - 1);
346
347         file->addr = mmap(NULL, file->len, PROT_READ,
348                         MAP_SHARED, file->fd, 0);
349
350         if (file->addr == MAP_FAILED) {
351                 fprintf(stderr, "mmap error %s for %s\n",
352                         strerror(errno), file->name);
353                 return -errno;
354         }
355
356         stats_file_update_cache(file);
357
358         return 0;
359 }
360
361 int main(int argc, char *argv[])
362 {
363         struct stats_file _file, *file;
364         struct stat stat;
365         int err;
366
367         if (argc < 2) {
368                 printf("Usage: %s [STATS_FILENAME]\n", argv[0]);
369                 exit(0);
370         }
371
372         file = &_file;
373         bzero(file, sizeof(struct stats_file));
374
375         file->name = argv[1];
376
377         file->fd = open(file->name, O_RDONLY, 0644);
378         if (file->fd == -1) {
379                 fprintf(stderr, "open error %s for %s\n",
380                         strerror(errno), file->name);
381                 exit(1);
382         }
383
384         err = fstat(file->fd, &stat);
385         if (err < 0) {
386                 fprintf(stderr, "fstat error %s for %s\n",
387                         strerror(errno), file->name);
388                 exit(1);
389         }
390
391         err = stats_file_mmap(file, stat.st_size);
392         if (err < 0)
393                 exit(1);
394
395         if (get_hdr(file)->magic != MAGIC) {
396                 /* not fatal */
397                 printf("No valid magic found\n");
398         }
399
400         stats_hdr_info(file);
401         stats_print_entries(file);
402         stats_print_diff(file);
403
404         munmap(file->addr, file->len);
405         close(file->fd);
406
407         return 0;
408 }