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