build: create pkginfo dir earlier to avoid build breakage
[openwrt.git] / package / wprobe / src / exporter / wprobe-export.c
1 /*
2 **     exporter.c - example exporter
3 **
4 **     Copyright Fraunhofer FOKUS
5 **
6 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <errno.h>
12
13 #include <ipfix_def.h>
14 #include <ipfix_def_fokus.h>
15 #include <ipfix_fields_fokus.h>
16
17 #include <ipfix.h>
18 #include <mlog.h>
19 #include <wprobe.h>
20 #include <stdbool.h>
21
22 static ipfix_datarecord_t g_data  = { NULL, NULL, 0 };
23 static int do_close = 0;
24
25 struct wprobe_mapping {
26         int id;
27         bool counter;
28         const char *wprobe_id;
29         struct wprobe_value *val;
30 };
31
32 #ifndef ARRAY_SIZE
33 #define ARRAY_SIZE(_array) (sizeof(_array) / sizeof((_array)[0]))
34 #endif
35
36 #define WMAP(_id, _name, ...) \
37         { \
38                 .counter = false, \
39                 .id = IPFIX_FT_WPROBE_##_id##_N, \
40                 .wprobe_id = _name \
41                 , ## __VA_ARGS__ \
42         }
43
44 #define WMAP_COUNTER(_id, _name, ...) \
45         { \
46                 .counter = true, \
47                 .id = IPFIX_FT_WPROBE_##_id, \
48                 .wprobe_id = _name \
49                 , ## __VA_ARGS__ \
50         }
51
52
53 #define WPROBE_OFFSET   2
54
55 static struct wprobe_mapping map_globals[] = {
56         WMAP(NOISE, "noise"),
57         WMAP(PHY_BUSY, "phy_busy"),
58         WMAP(PHY_RX, "phy_rx"),
59         WMAP(PHY_TX, "phy_tx"),
60         WMAP_COUNTER(FRAMES, "frames"),
61         WMAP_COUNTER(PROBEREQ, "probereq"),
62 };
63
64 static struct wprobe_mapping map_perlink[] = {
65         WMAP(IEEE_TX_RATE, "tx_rate"),
66         WMAP(IEEE_RX_RATE, "rx_rate"),
67         WMAP(RSSI, "rssi"),
68         WMAP(SIGNAL, "signal"),
69         WMAP(RETRANSMIT_200, "retransmit_200"),
70         WMAP(RETRANSMIT_400, "retransmit_400"),
71         WMAP(RETRANSMIT_800, "retransmit_800"),
72         WMAP(RETRANSMIT_1600, "retransmit_1600"),
73 };
74
75 static unsigned char link_local[6];
76 static char link_default[6];
77 static int nfields = 0;
78
79 #define FOKUS_USERID    12325
80
81 static void
82 match_template(struct wprobe_mapping *map, int n, struct list_head *list)
83 {
84         struct wprobe_attribute *attr;
85         int i, j, last = -1;
86
87         list_for_each_entry(attr, list, list) {
88                 for (i = 0; i < n; i++) {
89                         j = (last + 1 + i) % n;
90                         if (!strcmp(attr->name, map[j].wprobe_id))
91                                 goto found;
92                 }
93                 continue;
94 found:
95                 last = j;
96                 map[j].val = &attr->val;
97                 memset(&attr->val, 0, sizeof(attr->val));
98                 nfields++;
99         }
100 }
101
102 /* name: export_ipfix_get_template()
103  */
104 static ipfix_template_t *
105 prepare_template(ipfix_t *handle)
106 {
107     ipfix_template_t *t = NULL;
108         int size = 3 * nfields + WPROBE_OFFSET;
109     int i;
110
111     if (ipfix_new_data_template( handle, &t, size) < 0) {
112         mlogf( 0, "ipfix_new_template() failed: %s\n", strerror(errno) ); 
113                 exit(1);
114     }
115
116         ipfix_add_field(handle, t, 0, IPFIX_FT_SOURCEMACADDRESS, 6);
117         ipfix_add_field(handle, t, 0, IPFIX_FT_DESTINATIONMACADDRESS, 6);
118
119         g_data.lens = calloc(size, sizeof(g_data.lens[0]));
120         g_data.lens[0] = 6;
121         g_data.lens[1] = 6;
122         for (i = WPROBE_OFFSET; i < size; i++)
123                 g_data.lens[i] = 4;
124
125         g_data.addrs = calloc(size, sizeof(g_data.addrs[0]));
126         g_data.addrs[0] = link_local;
127         g_data.maxfields = WPROBE_OFFSET;
128         return t;
129 }
130
131 static void
132 add_template_fields(ipfix_t *handle, ipfix_template_t *t, struct wprobe_mapping *map, int n)
133 {
134         int f = g_data.maxfields;
135         int i;
136
137     for (i = 0; i < n; i++) {
138                 if (!map[i].val)
139                         continue;
140
141                 if (map[i].counter)
142                         g_data.addrs[f++] = &map[i].val->U32;
143                 else
144                         g_data.addrs[f++] = &map[i].val->n;
145
146         if (ipfix_add_field( handle, t, FOKUS_USERID, map[i].id + 0, 4) < 0)
147             exit(1);
148
149                 if (map[i].counter)
150                         continue;
151
152                 g_data.lens[f] = 8;
153                 g_data.addrs[f++] = &map[i].val->s;
154
155                 g_data.lens[f] = 8;
156                 g_data.addrs[f++] = &map[i].val->ss;
157         if (ipfix_add_field( handle, t, FOKUS_USERID, map[i].id + 1, 8) < 0)
158             exit(1);
159         if (ipfix_add_field( handle, t, FOKUS_USERID, map[i].id + 2, 8) < 0)
160             exit(1);
161     }
162         g_data.maxfields = f;
163 }
164
165 static void
166 wprobe_dump_data(ipfix_t *ipfixh, ipfix_template_t *ipfixt, struct wprobe_iface *dev)
167 {
168         struct wprobe_link *link;
169
170         wprobe_update_links(dev);
171         wprobe_request_data(dev, NULL);
172         if (list_empty(&dev->links)) {
173                 g_data.addrs[1] = link_default;
174                 ipfix_export_array(ipfixh, ipfixt, g_data.maxfields, g_data.addrs, g_data.lens);
175                 ipfix_export_flush(ipfixh);
176         }
177         list_for_each_entry(link, &dev->links, list) {
178                 g_data.addrs[1] = link->addr;
179                 wprobe_request_data(dev, link->addr);
180                 ipfix_export_array(ipfixh, ipfixt, g_data.maxfields, g_data.addrs, g_data.lens);
181                 ipfix_export_flush(ipfixh);
182         }
183 }
184
185 int main ( int argc, char **argv )
186 {
187         struct wprobe_iface *dev = NULL;
188     ipfix_template_t  *ipfixt = NULL;
189     ipfix_t *ipfixh = NULL;
190     int protocol = IPFIX_PROTO_TCP;
191     char *chost = NULL;
192         char *ifname = NULL;
193     int sourceid = 12345;
194     int port = IPFIX_PORTNO;
195     int verbose_level = 0;
196     int opt, i = 10;
197         char *err = NULL;
198
199         while ((opt = getopt(argc, argv, "hi:c:p:vstu")) != EOF) {
200                 switch (opt) {
201                 case 'p':
202                         if ((port=atoi(optarg)) <0) {
203                                 fprintf( stderr, "Invalid -p argument!\n" );
204                                 exit(1);
205                         }
206                         break;
207                 case 'i':
208                         ifname = optarg;
209                         break;
210                 case 'c':
211                         chost = optarg;
212                         break;
213
214                 case 's':
215                         protocol = IPFIX_PROTO_SCTP;
216                         break;
217
218                 case 't':
219                         protocol = IPFIX_PROTO_TCP;
220                         break;
221
222                 case 'u':
223                         protocol = IPFIX_PROTO_UDP;
224                         break;
225
226                 case 'v':
227                         verbose_level ++;
228                         break;
229
230                 case 'h':
231                 default:
232                         fprintf(stderr, "usage: %s [-hstuv] -i <interface> -c <collector> [-p portno]\n"
233                                          "  -h               this help\n"
234                                          "  -i <interface>   wprobe interface\n"
235                                          "  -c <collector>   collector address\n"
236                                          "  -p <portno>      collector port number (default=%d)\n"
237                                          "  -s               send data via SCTP\n"
238                                          "  -t               send data via TCP (default)\n"
239                                          "  -u               send data via UDP\n"
240                                          "  -v               increase verbose level\n\n",
241                                          argv[0], IPFIX_PORTNO  );
242                         exit(1);
243                 }
244         }
245
246         if (!ifname) {
247                 fprintf(stderr, "No interface specified\n");
248                 return -1;
249         }
250
251         if (!chost) {
252                 fprintf(stderr, "No collector specified\n");
253                 return -1;
254         }
255
256         dev = wprobe_get_auto(ifname, &err);
257         if (!dev || (list_empty(&dev->global_attr) && list_empty(&dev->link_attr))) {
258                 fprintf(stderr, "Cannot connect to wprobe on interface '%s': %s\n", ifname, (err ? err : "Unknown error"));
259                 return -1;
260         }
261
262         match_template(map_globals, ARRAY_SIZE(map_globals), &dev->global_attr);
263         match_template(map_perlink, ARRAY_SIZE(map_perlink), &dev->link_attr);
264         if (nfields == 0) {
265                 fprintf(stderr, "No usable attributes found\n");
266                 return -1;
267         }
268
269     mlog_set_vlevel( verbose_level );
270     if (ipfix_init() < 0) {
271         fprintf( stderr, "cannot init ipfix module: %s\n", strerror(errno) );
272         exit(1);
273     }
274
275     ipfix_add_vendor_information_elements(ipfix_ft_fokus);
276     if (ipfix_open(&ipfixh, sourceid, IPFIX_VERSION) < 0) {
277         fprintf( stderr, "ipfix_open() failed: %s\n", strerror(errno) );
278         exit(1);
279     }
280
281     if (ipfix_add_collector( ipfixh, chost, port, protocol ) < 0) {
282         fprintf( stderr, "ipfix_add_collector(%s,%d) failed: %s\n", 
283                  chost, port, strerror(errno));
284         exit(1);
285     }
286
287         fprintf(stderr, "Local link address: %02x:%02x:%02x:%02x:%02x:%02x\n",
288                 link_local[0], link_local[1], link_local[2],
289                 link_local[3], link_local[4], link_local[5]);
290
291         ipfixt = prepare_template(ipfixh);
292         add_template_fields(ipfixh, ipfixt, map_globals, ARRAY_SIZE(map_globals));
293         add_template_fields(ipfixh, ipfixt, map_perlink, ARRAY_SIZE(map_perlink));
294
295         while (!do_close) {
296                 sleep(1);
297                 wprobe_dump_data(ipfixh, ipfixt, dev);
298     }
299
300     ipfix_delete_template( ipfixh, ipfixt );
301     ipfix_close( ipfixh );
302     ipfix_cleanup();
303     exit(0);
304 }