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