wprobe: move measurement task to the kernel, add some configurability (work in progress)
[openwrt/svn-archive/archive.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"),
69 WMAP(IEEE_RX_RATE, "rx_rate"),
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 int nfields = 0;
81
82 #define FOKUS_USERID 12325
83
84 static void
85 match_template(struct wprobe_mapping *map, int n, struct list_head *list)
86 {
87 struct wprobe_attribute *attr;
88 int i, j, last = -1;
89
90 list_for_each_entry(attr, list, list) {
91 for (i = 0; i < n; i++) {
92 j = (last + 1 + i) % n;
93 if (!strcmp(attr->name, map[j].wprobe_id))
94 goto found;
95 }
96 continue;
97 found:
98 last = j;
99 map[j].val = &attr->val;
100 memset(&attr->val, 0, sizeof(attr->val));
101 nfields++;
102 }
103 }
104
105 /* name: export_ipfix_get_template()
106 */
107 static ipfix_template_t *
108 prepare_template(ipfix_t *handle)
109 {
110 ipfix_template_t *t = NULL;
111 int size = 3 * nfields + WPROBE_OFFSET;
112 int i;
113
114 if (ipfix_new_data_template( handle, &t, size) < 0) {
115 mlogf( 0, "ipfix_new_template() failed: %s\n", strerror(errno) );
116 exit(1);
117 }
118
119 ipfix_add_field(handle, t, 0, IPFIX_FT_SOURCEMACADDRESS, 6);
120 ipfix_add_field(handle, t, 0, IPFIX_FT_DESTINATIONMACADDRESS, 6);
121
122 g_data.lens = calloc(size, sizeof(g_data.lens[0]));
123 g_data.lens[0] = 6;
124 g_data.lens[1] = 6;
125 for (i = WPROBE_OFFSET; i < size; i++)
126 g_data.lens[i] = 4;
127
128 g_data.addrs = calloc(size, sizeof(g_data.addrs[0]));
129 g_data.addrs[0] = link_local;
130 g_data.maxfields = WPROBE_OFFSET;
131 return t;
132 }
133
134 static void
135 add_template_fields(ipfix_t *handle, ipfix_template_t *t, struct wprobe_mapping *map, int n)
136 {
137 int f = g_data.maxfields;
138 int i;
139
140 for (i = 0; i < n; i++) {
141 if (!map[i].val)
142 continue;
143
144 if (map[i].counter)
145 g_data.addrs[f++] = &map[i].val->U32;
146 else
147 g_data.addrs[f++] = &map[i].val->avg;
148
149 if (ipfix_add_field( handle, t, FOKUS_USERID, map[i].id + 0, 4) < 0)
150 exit(1);
151
152 if (map[i].counter)
153 continue;
154
155 g_data.addrs[f++] = &map[i].val->stdev;
156 g_data.addrs[f++] = &map[i].val->n;
157 if (ipfix_add_field( handle, t, FOKUS_USERID, map[i].id + 1, 4) < 0)
158 exit(1);
159 if (ipfix_add_field( handle, t, FOKUS_USERID, map[i].id + 2, 4) < 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
198 while ((opt = getopt(argc, argv, "hi:c:p:vstu")) != EOF) {
199 switch (opt) {
200 case 'p':
201 if ((port=atoi(optarg)) <0) {
202 fprintf( stderr, "Invalid -p argument!\n" );
203 exit(1);
204 }
205 break;
206 case 'i':
207 ifname = optarg;
208 break;
209 case 'c':
210 chost = optarg;
211 break;
212
213 case 's':
214 protocol = IPFIX_PROTO_SCTP;
215 break;
216
217 case 't':
218 protocol = IPFIX_PROTO_TCP;
219 break;
220
221 case 'u':
222 protocol = IPFIX_PROTO_UDP;
223 break;
224
225 case 'v':
226 verbose_level ++;
227 break;
228
229 case 'h':
230 default:
231 fprintf(stderr, "usage: %s [-hstuv] -i <interface> -c <collector> [-p portno]\n"
232 " -h this help\n"
233 " -i <interface> wprobe interface\n"
234 " -c <collector> collector address\n"
235 " -p <portno> collector port number (default=%d)\n"
236 " -s send data via SCTP\n"
237 " -t send data via TCP (default)\n"
238 " -u send data via UDP\n"
239 " -v increase verbose level\n\n",
240 argv[0], IPFIX_PORTNO );
241 exit(1);
242 }
243 }
244
245 if (!ifname) {
246 fprintf(stderr, "No interface specified\n");
247 return -1;
248 }
249
250 if (!chost) {
251 fprintf(stderr, "No collector specified\n");
252 return -1;
253 }
254
255 dev = wprobe_get_dev(ifname);
256 if (!dev || (list_empty(&dev->global_attr) && list_empty(&dev->link_attr))) {
257 fprintf(stderr, "Cannot connect to wprobe on interface '%s'\n", ifname);
258 return -1;
259 }
260
261 match_template(map_globals, ARRAY_SIZE(map_globals), &dev->global_attr);
262 match_template(map_perlink, ARRAY_SIZE(map_perlink), &dev->link_attr);
263 if (nfields == 0) {
264 fprintf(stderr, "No usable attributes found\n");
265 return -1;
266 }
267
268 mlog_set_vlevel( verbose_level );
269 if (ipfix_init() < 0) {
270 fprintf( stderr, "cannot init ipfix module: %s\n", strerror(errno) );
271 exit(1);
272 }
273
274 ipfix_add_vendor_information_elements(ipfix_ft_fokus);
275 if (ipfix_open(&ipfixh, sourceid, IPFIX_VERSION) < 0) {
276 fprintf( stderr, "ipfix_open() failed: %s\n", strerror(errno) );
277 exit(1);
278 }
279
280 if (ipfix_add_collector( ipfixh, chost, port, protocol ) < 0) {
281 fprintf( stderr, "ipfix_add_collector(%s,%d) failed: %s\n",
282 chost, port, strerror(errno));
283 exit(1);
284 }
285
286 fprintf(stderr, "Local link address: %02x:%02x:%02x:%02x:%02x:%02x\n",
287 link_local[0], link_local[1], link_local[2],
288 link_local[3], link_local[4], link_local[5]);
289
290 ipfixt = prepare_template(ipfixh);
291 add_template_fields(ipfixh, ipfixt, map_globals, ARRAY_SIZE(map_globals));
292 add_template_fields(ipfixh, ipfixt, map_perlink, ARRAY_SIZE(map_perlink));
293
294 while (!do_close) {
295 sleep(1);
296 wprobe_dump_data(ipfixh, ipfixt, dev);
297 }
298
299 ipfix_delete_template( ipfixh, ipfixt );
300 ipfix_close( ipfixh );
301 ipfix_cleanup();
302 exit(0);
303 }