dec71a1b7759d21b1a485c3c25b979dda81e4ce7
[feed/routing.git] / babeld / src / ubus.c
1 #include <stdint.h>
2 #include <stdlib.h>
3 #include <sys/select.h>
4
5 #include <libubox/blob.h>
6 #include <libubox/blobmsg.h>
7 #include <libubox/list.h>
8 #include <libubus.h>
9
10 #include <arpa/inet.h>
11 #include <net/if.h>
12 #include <netinet/in.h>
13 #include <sys/ioctl.h>
14 #include <sys/socket.h>
15
16 #include "babeld.h"
17 #include "configuration.h"
18 #include "interface.h"
19 #include "kernel.h"
20 #include "local.h"
21 #include "message.h"
22 #include "neighbour.h"
23 #include "net.h"
24 #include "resend.h"
25 #include "route.h"
26 #include "source.h"
27 #include "util.h"
28 #include "version.h"
29 #include "xroute.h"
30
31 #include "ubus.h"
32
33 // Definition of header variable whether to enable ubus bindings.
34 int ubus_bindings = 0;
35
36 // Shared state maintained throughout calls to handle ubus messages.
37 static struct ubus_context *shared_ctx;
38
39 // List of exported routes (to be used with ubox's list helpers).
40 struct xroute_list_entry {
41 struct list_head list;
42 struct xroute *xroute;
43 };
44
45 // List of received routes (to be used with ubox's list helpers).
46 struct route_list_entry {
47 struct list_head list;
48 struct babel_route *route;
49 };
50
51 // List of neighbours (to be used with ubox's list helpers).
52 struct neighbour_list_entry {
53 struct list_head list;
54 struct neighbour *neighbour;
55 };
56
57 // Definition of interface function enums (to be used with ubox's blobmsg
58 // helpers).
59 enum { INTERFACE_IFNAME, __INTERFACE_MAX };
60
61 // Definition of interface parsing (to be used with ubox's blobmsg helpers).
62 static const struct blobmsg_policy interface_policy[__INTERFACE_MAX] = {
63 [INTERFACE_IFNAME] = {"ifname", BLOBMSG_TYPE_STRING},
64 };
65
66 // Definition of filter function enums (to be used with ubox's blobmsg
67 // helpers).
68 enum { FILTER_IFNAME, FILTER_TYPE, FILTER_METRIC, __FILTER_MAX };
69
70 // Definition of filter parsing (to be used with ubox's blobmsg helpers).
71 static const struct blobmsg_policy filter_policy[__FILTER_MAX] = {
72 [FILTER_IFNAME] = {"ifname", BLOBMSG_TYPE_STRING},
73 [FILTER_TYPE] = {"type", BLOBMSG_TYPE_INT32},
74 [FILTER_METRIC] = {"metric", BLOBMSG_TYPE_INT32},
75 };
76
77 // Adds a filter (ubus equivalent to "filter"-function).
78 static int babeld_ubus_add_filter(struct ubus_context *ctx_local,
79 struct ubus_object *obj,
80 struct ubus_request_data *req,
81 const char *method, struct blob_attr *msg) {
82 struct blob_attr *tb[__FILTER_MAX];
83 struct blob_buf b = {0};
84 struct filter *filter = NULL;
85 char *ifname;
86 int metric, type;
87
88 blobmsg_parse(filter_policy, __FILTER_MAX, tb, blob_data(msg), blob_len(msg));
89
90 if (!tb[FILTER_IFNAME])
91 return UBUS_STATUS_INVALID_ARGUMENT;
92
93 if (!tb[FILTER_TYPE])
94 return UBUS_STATUS_INVALID_ARGUMENT;
95
96 type = blobmsg_get_u32(tb[FILTER_TYPE]);
97
98 if (tb[FILTER_METRIC])
99 metric = blobmsg_get_u32(tb[FILTER_METRIC]);
100
101 filter = calloc(1, sizeof(struct filter));
102 if (filter == NULL)
103 return UBUS_STATUS_UNKNOWN_ERROR;
104
105 filter->af = AF_INET6;
106 filter->proto = 0;
107 filter->plen_le = 128;
108 filter->src_plen_le = 128;
109 filter->action.add_metric = metric;
110
111 ifname = blobmsg_get_string(tb[FILTER_IFNAME]);
112 filter->ifname = strdup(ifname);
113 filter->ifindex = if_nametoindex(filter->ifname);
114
115 add_filter(filter, type);
116
117 return UBUS_STATUS_OK;
118 }
119
120 // Adds an inteface (ubus equivalent to "interface"-function).
121 static int babeld_ubus_add_interface(struct ubus_context *ctx_local,
122 struct ubus_object *obj,
123 struct ubus_request_data *req,
124 const char *method,
125 struct blob_attr *msg) {
126 struct blob_attr *tb[__INTERFACE_MAX];
127 struct blob_buf b = {0};
128 struct interface *ifp = NULL;
129 char *ifname;
130
131 blobmsg_parse(interface_policy, __INTERFACE_MAX, tb, blob_data(msg),
132 blob_len(msg));
133
134 if (!tb[INTERFACE_IFNAME])
135 return UBUS_STATUS_INVALID_ARGUMENT;
136
137 ifname = blobmsg_get_string(tb[INTERFACE_IFNAME]);
138
139 ifp = add_interface(ifname, NULL);
140 if (ifp == NULL)
141 return UBUS_STATUS_UNKNOWN_ERROR;
142
143 return UBUS_STATUS_OK;
144 }
145
146 // Sends a babel info message on ubus socket.
147 static int babeld_ubus_babeld_info(struct ubus_context *ctx_local,
148 struct ubus_object *obj,
149 struct ubus_request_data *req,
150 const char *method, struct blob_attr *msg) {
151 struct blob_buf b = {0};
152 void *prefix;
153 char host[64];
154 int ret;
155
156 blob_buf_init(&b, 0);
157 blobmsg_add_string(&b, "babeld-version", BABELD_VERSION);
158 blobmsg_add_string(&b, "my-id", format_eui64(myid));
159 if (!gethostname(host, sizeof(host)))
160 blobmsg_add_string(&b, "host", host);
161
162 ret = ubus_send_reply(ctx_local, req, b.head);
163 if (ret)
164 fprintf(stderr, "Failed to send reply: %s\n", ubus_strerror(ret));
165
166 blob_buf_free(&b);
167
168 return ret;
169 }
170
171 // Appends an exported route message entry to the buffer.
172 static void babeld_add_xroute_buf(struct xroute *xroute, struct blob_buf *b) {
173 void *prefix;
174
175 prefix = blobmsg_open_table(b, format_prefix(xroute->prefix, xroute->plen));
176
177 blobmsg_add_string(b, "src-prefix",
178 format_prefix(xroute->src_prefix, xroute->src_plen));
179 blobmsg_add_u32(b, "metric", xroute->metric);
180 blobmsg_close_table(b, prefix);
181 }
182
183 // Sends an exported routes message on ubus socket, splitting apart IPv4 and
184 // IPv6 routes.
185 static int babeld_ubus_get_xroutes(struct ubus_context *ctx_local,
186 struct ubus_object *obj,
187 struct ubus_request_data *req,
188 const char *method, struct blob_attr *msg) {
189 struct blob_buf b = {0};
190 struct xroute_stream *xroutes;
191 struct xroute_list_entry *cur, *tmp;
192 void *ipv4, *ipv6;
193 int ret;
194 LIST_HEAD(xroute_ipv4_list);
195 LIST_HEAD(xroute_ipv6_list);
196
197 blob_buf_init(&b, 0);
198
199 xroutes = xroute_stream();
200 if (xroutes) {
201 while (1) {
202 struct xroute *xroute = xroute_stream_next(xroutes);
203 if (xroute == NULL)
204 break;
205
206 struct xroute_list_entry *xr =
207 calloc(1, sizeof(struct xroute_list_entry));
208 xr->xroute = xroute;
209
210 if (v4mapped(xroute->prefix)) {
211 list_add(&xr->list, &xroute_ipv4_list);
212 } else {
213 list_add(&xr->list, &xroute_ipv6_list);
214 }
215 }
216 xroute_stream_done(xroutes);
217 }
218
219 ipv4 = blobmsg_open_table(&b, "IPv4");
220 list_for_each_entry_safe(cur, tmp, &xroute_ipv4_list, list) {
221 babeld_add_xroute_buf(cur->xroute, &b);
222 list_del(&cur->list);
223 free(cur);
224 }
225 blobmsg_close_table(&b, ipv4);
226
227 ipv6 = blobmsg_open_table(&b, "IPv6");
228 list_for_each_entry_safe(cur, tmp, &xroute_ipv6_list, list) {
229 babeld_add_xroute_buf(cur->xroute, &b);
230 list_del(&cur->list);
231 free(cur);
232 }
233 blobmsg_close_table(&b, ipv6);
234
235 ret = ubus_send_reply(ctx_local, req, b.head);
236 if (ret)
237 fprintf(stderr, "Failed to send reply: %s\n", ubus_strerror(ret));
238
239 blob_buf_free(&b);
240
241 return ret;
242 }
243
244 // Appends an route message entry to the buffer.
245 static void babeld_add_route_buf(struct babel_route *route,
246 struct blob_buf *b) {
247 void *prefix;
248 char channels[100];
249
250 if (route->channels_len == 0) {
251 channels[0] = '\0';
252 } else {
253 int i, j = 0;
254 snprintf(channels, sizeof(channels), " chan (");
255 j = strlen(channels);
256 for (i = 0; i < route->channels_len; i++) {
257 if (i > 0)
258 channels[j++] = ',';
259 snprintf(channels + j, sizeof(channels) - j, "%u",
260 (unsigned)route->channels[i]);
261 j = strlen(channels);
262 }
263 snprintf(channels + j, sizeof(channels) - j, ")");
264 }
265
266 prefix = blobmsg_open_table(
267 b, format_prefix(route->src->prefix, route->src->plen));
268
269 blobmsg_add_string(
270 b, "src-prefix",
271 format_prefix(route->src->src_prefix, route->src->src_plen));
272 blobmsg_add_u32(b, "route_metric", route_metric(route));
273 blobmsg_add_u32(b, "route_smoothed_metric", route_smoothed_metric(route));
274 blobmsg_add_u32(b, "refmetric", route->refmetric);
275 blobmsg_add_string(b, "id", format_eui64(route->src->id));
276 blobmsg_add_u32(b, "seqno", (uint32_t)route->seqno);
277 blobmsg_add_string(b, "channels", channels);
278 blobmsg_add_u32(b, "age", (int)(now.tv_sec - route->time));
279 blobmsg_add_string(b, "via", format_address(route->neigh->address));
280 if (memcmp(route->nexthop, route->neigh->address, 16) != 0)
281 blobmsg_add_string(b, "nexthop", format_address(route->nexthop));
282
283 blobmsg_add_u8(b, "installed", route->installed);
284 blobmsg_add_u8(b, "feasible", route_feasible(route));
285
286 blobmsg_close_table(b, prefix);
287 }
288
289 // Sends received routes message on ubus socket, splitting apart IPv4 and IPv6
290 // routes.
291 static int babeld_ubus_get_routes(struct ubus_context *ctx_local,
292 struct ubus_object *obj,
293 struct ubus_request_data *req,
294 const char *method, struct blob_attr *msg) {
295 struct blob_buf b = {0};
296 struct route_stream *routes;
297 struct route_list_entry *cur, *tmp;
298 void *prefix, *ipv4, *ipv6;
299 int ret;
300 LIST_HEAD(route_ipv4_list);
301 LIST_HEAD(route_ipv6_list);
302
303 blob_buf_init(&b, 0);
304
305 routes = route_stream(0);
306 if (routes) {
307 while (1) {
308 struct babel_route *route = route_stream_next(routes);
309 if (route == NULL)
310 break;
311 struct route_list_entry *r = calloc(1, sizeof(struct route_list_entry));
312 r->route = route;
313
314 if (v4mapped(route->src->prefix)) {
315 list_add(&r->list, &route_ipv4_list);
316 } else {
317 list_add(&r->list, &route_ipv6_list);
318 }
319 }
320 route_stream_done(routes);
321 }
322
323 ipv4 = blobmsg_open_table(&b, "IPv4");
324 list_for_each_entry_safe(cur, tmp, &route_ipv4_list, list) {
325 babeld_add_route_buf(cur->route, &b);
326 list_del(&cur->list);
327 free(cur);
328 }
329 blobmsg_close_table(&b, ipv4);
330
331 ipv6 = blobmsg_open_table(&b, "IPv6");
332 list_for_each_entry_safe(cur, tmp, &route_ipv6_list, list) {
333 babeld_add_route_buf(cur->route, &b);
334 list_del(&cur->list);
335 free(cur);
336 }
337 blobmsg_close_table(&b, ipv6);
338
339 ret = ubus_send_reply(ctx_local, req, b.head);
340 if (ret)
341 fprintf(stderr, "Failed to send reply: %s\n", ubus_strerror(ret));
342
343 blob_buf_free(&b);
344
345 return ret;
346 }
347
348 // Appends an neighbour entry to the buffer.
349 static void babeld_add_neighbour_buf(struct neighbour *neigh,
350 struct blob_buf *b) {
351 void *neighbour;
352
353 neighbour = blobmsg_open_table(b, format_address(neigh->address));
354 blobmsg_add_string(b, "dev", neigh->ifp->name);
355 blobmsg_add_u32(b, "hello-reach", neigh->hello.reach);
356 blobmsg_add_u32(b, "uhello-reach", neigh->uhello.reach);
357 blobmsg_add_u32(b, "rxcost", neighbour_rxcost(neigh));
358 blobmsg_add_u32(b, "txcost", neigh->txcost);
359 blobmsg_add_string(b, "rtt", format_thousands(neigh->rtt));
360 blobmsg_add_u32(b, "channel", neigh->ifp->channel);
361 blobmsg_add_u8(b, "if_up", if_up(neigh->ifp));
362 blobmsg_close_table(b, neighbour);
363 }
364
365 // Sends neighbours message on ubus socket, splitting apart IPv4 and IPv6
366 // neighbours.
367 static int babeld_ubus_get_neighbours(struct ubus_context *ctx_local,
368 struct ubus_object *obj,
369 struct ubus_request_data *req,
370 const char *method,
371 struct blob_attr *msg) {
372 struct blob_buf b = {0};
373 struct neighbour *neigh;
374 struct neighbour_list_entry *cur, *tmp;
375 void *ipv4, *ipv6;
376 int ret;
377 LIST_HEAD(neighbour_ipv4_list);
378 LIST_HEAD(neighbour_ipv6_list);
379
380 blob_buf_init(&b, 0);
381
382 FOR_ALL_NEIGHBOURS(neigh) {
383 struct neighbour_list_entry *n =
384 calloc(1, sizeof(struct neighbour_list_entry));
385 n->neighbour = neigh;
386 if (v4mapped(neigh->address)) {
387 list_add(&n->list, &neighbour_ipv4_list);
388 } else {
389 list_add(&n->list, &neighbour_ipv6_list);
390 }
391 }
392
393 ipv4 = blobmsg_open_table(&b, "IPv4");
394 list_for_each_entry_safe(cur, tmp, &neighbour_ipv4_list, list) {
395 babeld_add_neighbour_buf(cur->neighbour, &b);
396 list_del(&cur->list);
397 free(cur);
398 }
399 blobmsg_close_table(&b, ipv4);
400
401 ipv6 = blobmsg_open_table(&b, "IPv6");
402 list_for_each_entry_safe(cur, tmp, &neighbour_ipv6_list, list) {
403 babeld_add_neighbour_buf(cur->neighbour, &b);
404 list_del(&cur->list);
405 free(cur);
406 }
407 blobmsg_close_table(&b, ipv6);
408
409 ret = ubus_send_reply(ctx_local, req, b.head);
410 if (ret)
411 fprintf(stderr, "Failed to send reply: %s\n", ubus_strerror(ret));
412
413 blob_buf_free(&b);
414
415 return ret;
416 }
417
418 // List of functions we expose via the ubus bus.
419 static const struct ubus_method babeld_methods[] = {
420 UBUS_METHOD("add_interface", babeld_ubus_add_interface, interface_policy),
421 UBUS_METHOD("add_filter", babeld_ubus_add_filter, filter_policy),
422 UBUS_METHOD_NOARG("get_info", babeld_ubus_babeld_info),
423 UBUS_METHOD_NOARG("get_xroutes", babeld_ubus_get_xroutes),
424 UBUS_METHOD_NOARG("get_routes", babeld_ubus_get_routes),
425 UBUS_METHOD_NOARG("get_neighbours", babeld_ubus_get_neighbours),
426 };
427
428 // Definition of the ubus object type.
429 static struct ubus_object_type babeld_object_type =
430 UBUS_OBJECT_TYPE("babeld", babeld_methods);
431
432 // Object we announce via the ubus bus.
433 static struct ubus_object babeld_object = {
434 .name = "babeld",
435 .type = &babeld_object_type,
436 .methods = babeld_methods,
437 .n_methods = ARRAY_SIZE(babeld_methods),
438 };
439
440 // Registers handlers for babel methods in the global ubus context.
441 static bool ubus_init_object() {
442 int ret;
443
444 ret = ubus_add_object(shared_ctx, &babeld_object);
445 if (ret) {
446 fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret));
447 return false;
448 }
449
450 return true;
451 }
452
453 // Initializes the global ubus context, connecting to the bus to be able to
454 // receive and send messages.
455 static bool babeld_ubus_init(void) {
456 if (shared_ctx)
457 return true;
458
459 shared_ctx = ubus_connect(NULL);
460 if (!shared_ctx)
461 return false;
462
463 return true;
464 }
465
466 void ubus_notify_route(struct babel_route *route, int kind) {
467 struct blob_buf b = {0};
468 char method[50]; // possible methods are route.change, route.add, route.flush
469
470 if (!babeld_object.has_subscribers)
471 return;
472
473 if (!route)
474 return;
475
476 if (!shared_ctx)
477 return;
478
479 blob_buf_init(&b, 0);
480 babeld_add_route_buf(route, &b);
481 snprintf(method, sizeof(method), "route.%s", local_kind(kind));
482 ubus_notify(shared_ctx, &babeld_object, method, b.head, -1);
483 blob_buf_free(&b);
484 }
485
486 void ubus_notify_xroute(struct xroute *xroute, int kind) {
487 struct blob_buf b = {0};
488 char method[50]; // possible methods are xroute.change, xroute.add,
489 // xroute.flush
490
491 if (!babeld_object.has_subscribers)
492 return;
493
494 if (!xroute)
495 return;
496
497 if (!shared_ctx)
498 return;
499
500 blob_buf_init(&b, 0);
501 babeld_add_xroute_buf(xroute, &b);
502 snprintf(method, sizeof(method), "xroute.%s", local_kind(kind));
503 ubus_notify(shared_ctx, &babeld_object, method, b.head, -1);
504 blob_buf_free(&b);
505 }
506
507 void ubus_notify_neighbour(struct neighbour *neigh, int kind) {
508 struct blob_buf b = {0};
509 char method[50]; // possible methods are neigh.change, neigh.add, neigh.flush
510
511 if (!babeld_object.has_subscribers)
512 return;
513
514 if (!neigh)
515 return;
516
517 if (!shared_ctx)
518 return;
519
520 blob_buf_init(&b, 0);
521 babeld_add_neighbour_buf(neigh, &b);
522 snprintf(method, sizeof(method), "neigh.%s", local_kind(kind));
523 ubus_notify(shared_ctx, &babeld_object, method, b.head, -1);
524 blob_buf_free(&b);
525 }
526
527 void babeld_ubus_receive(fd_set *readfds) {
528 if (!shared_ctx)
529 return;
530 if (FD_ISSET(shared_ctx->sock.fd, readfds))
531 ubus_handle_event(shared_ctx);
532 }
533
534 int babeld_ubus_add_read_sock(fd_set *readfds, int maxfd) {
535 if (!shared_ctx)
536 return maxfd;
537
538 FD_SET(shared_ctx->sock.fd, readfds);
539 return MAX(maxfd, shared_ctx->sock.fd);
540 }
541
542 bool babeld_add_ubus() {
543 if (!babeld_ubus_init()) {
544 fprintf(stderr, "Failed to initialize ubus!\n");
545 return false;
546 }
547
548 if (!ubus_init_object()) {
549 fprintf(stderr, "Failed to add objects to ubus!\n");
550 return false;
551 }
552
553 return true;
554 }