babeld: update to 1.13
[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
249 prefix = blobmsg_open_table(
250 b, format_prefix(route->src->prefix, route->src->plen));
251
252 blobmsg_add_string(
253 b, "src-prefix",
254 format_prefix(route->src->src_prefix, route->src->src_plen));
255 blobmsg_add_u32(b, "route_metric", route_metric(route));
256 blobmsg_add_u32(b, "route_smoothed_metric", route_smoothed_metric(route));
257 blobmsg_add_u32(b, "refmetric", route->refmetric);
258 blobmsg_add_string(b, "id", format_eui64(route->src->id));
259 blobmsg_add_u32(b, "seqno", (uint32_t)route->seqno);
260 blobmsg_add_u32(b, "age", (int)(now.tv_sec - route->time));
261 blobmsg_add_string(b, "via", format_address(route->neigh->address));
262 if (memcmp(route->nexthop, route->neigh->address, 16) != 0)
263 blobmsg_add_string(b, "nexthop", format_address(route->nexthop));
264
265 blobmsg_add_u8(b, "installed", route->installed);
266 blobmsg_add_u8(b, "feasible", route_feasible(route));
267
268 blobmsg_close_table(b, prefix);
269 }
270
271 // Sends received routes message on ubus socket, splitting apart IPv4 and IPv6
272 // routes.
273 static int babeld_ubus_get_routes(struct ubus_context *ctx_local,
274 struct ubus_object *obj,
275 struct ubus_request_data *req,
276 const char *method, struct blob_attr *msg) {
277 struct blob_buf b = {0};
278 struct route_stream *routes;
279 struct route_list_entry *cur, *tmp;
280 void *prefix, *ipv4, *ipv6;
281 int ret;
282 LIST_HEAD(route_ipv4_list);
283 LIST_HEAD(route_ipv6_list);
284
285 blob_buf_init(&b, 0);
286
287 routes = route_stream(0);
288 if (routes) {
289 while (1) {
290 struct babel_route *route = route_stream_next(routes);
291 if (route == NULL)
292 break;
293 struct route_list_entry *r = calloc(1, sizeof(struct route_list_entry));
294 r->route = route;
295
296 if (v4mapped(route->src->prefix)) {
297 list_add(&r->list, &route_ipv4_list);
298 } else {
299 list_add(&r->list, &route_ipv6_list);
300 }
301 }
302 route_stream_done(routes);
303 }
304
305 ipv4 = blobmsg_open_table(&b, "IPv4");
306 list_for_each_entry_safe(cur, tmp, &route_ipv4_list, list) {
307 babeld_add_route_buf(cur->route, &b);
308 list_del(&cur->list);
309 free(cur);
310 }
311 blobmsg_close_table(&b, ipv4);
312
313 ipv6 = blobmsg_open_table(&b, "IPv6");
314 list_for_each_entry_safe(cur, tmp, &route_ipv6_list, list) {
315 babeld_add_route_buf(cur->route, &b);
316 list_del(&cur->list);
317 free(cur);
318 }
319 blobmsg_close_table(&b, ipv6);
320
321 ret = ubus_send_reply(ctx_local, req, b.head);
322 if (ret)
323 fprintf(stderr, "Failed to send reply: %s\n", ubus_strerror(ret));
324
325 blob_buf_free(&b);
326
327 return ret;
328 }
329
330 // Appends an neighbour entry to the buffer.
331 static void babeld_add_neighbour_buf(struct neighbour *neigh,
332 struct blob_buf *b) {
333 void *neighbour;
334
335 neighbour = blobmsg_open_table(b, format_address(neigh->address));
336 blobmsg_add_string(b, "dev", neigh->ifp->name);
337 blobmsg_add_u32(b, "hello-reach", neigh->hello.reach);
338 blobmsg_add_u32(b, "uhello-reach", neigh->uhello.reach);
339 blobmsg_add_u32(b, "rxcost", neighbour_rxcost(neigh));
340 blobmsg_add_u32(b, "txcost", neigh->txcost);
341 blobmsg_add_string(b, "rtt", format_thousands(neigh->rtt));
342 blobmsg_add_u8(b, "if_up", if_up(neigh->ifp));
343 blobmsg_close_table(b, neighbour);
344 }
345
346 // Sends neighbours message on ubus socket, splitting apart IPv4 and IPv6
347 // neighbours.
348 static int babeld_ubus_get_neighbours(struct ubus_context *ctx_local,
349 struct ubus_object *obj,
350 struct ubus_request_data *req,
351 const char *method,
352 struct blob_attr *msg) {
353 struct blob_buf b = {0};
354 struct neighbour *neigh;
355 struct neighbour_list_entry *cur, *tmp;
356 void *ipv4, *ipv6;
357 int ret;
358 LIST_HEAD(neighbour_ipv4_list);
359 LIST_HEAD(neighbour_ipv6_list);
360
361 blob_buf_init(&b, 0);
362
363 FOR_ALL_NEIGHBOURS(neigh) {
364 struct neighbour_list_entry *n =
365 calloc(1, sizeof(struct neighbour_list_entry));
366 n->neighbour = neigh;
367 if (v4mapped(neigh->address)) {
368 list_add(&n->list, &neighbour_ipv4_list);
369 } else {
370 list_add(&n->list, &neighbour_ipv6_list);
371 }
372 }
373
374 ipv4 = blobmsg_open_table(&b, "IPv4");
375 list_for_each_entry_safe(cur, tmp, &neighbour_ipv4_list, list) {
376 babeld_add_neighbour_buf(cur->neighbour, &b);
377 list_del(&cur->list);
378 free(cur);
379 }
380 blobmsg_close_table(&b, ipv4);
381
382 ipv6 = blobmsg_open_table(&b, "IPv6");
383 list_for_each_entry_safe(cur, tmp, &neighbour_ipv6_list, list) {
384 babeld_add_neighbour_buf(cur->neighbour, &b);
385 list_del(&cur->list);
386 free(cur);
387 }
388 blobmsg_close_table(&b, ipv6);
389
390 ret = ubus_send_reply(ctx_local, req, b.head);
391 if (ret)
392 fprintf(stderr, "Failed to send reply: %s\n", ubus_strerror(ret));
393
394 blob_buf_free(&b);
395
396 return ret;
397 }
398
399 // List of functions we expose via the ubus bus.
400 static const struct ubus_method babeld_methods[] = {
401 UBUS_METHOD("add_interface", babeld_ubus_add_interface, interface_policy),
402 UBUS_METHOD("add_filter", babeld_ubus_add_filter, filter_policy),
403 UBUS_METHOD_NOARG("get_info", babeld_ubus_babeld_info),
404 UBUS_METHOD_NOARG("get_xroutes", babeld_ubus_get_xroutes),
405 UBUS_METHOD_NOARG("get_routes", babeld_ubus_get_routes),
406 UBUS_METHOD_NOARG("get_neighbours", babeld_ubus_get_neighbours),
407 };
408
409 // Definition of the ubus object type.
410 static struct ubus_object_type babeld_object_type =
411 UBUS_OBJECT_TYPE("babeld", babeld_methods);
412
413 // Object we announce via the ubus bus.
414 static struct ubus_object babeld_object = {
415 .name = "babeld",
416 .type = &babeld_object_type,
417 .methods = babeld_methods,
418 .n_methods = ARRAY_SIZE(babeld_methods),
419 };
420
421 // Registers handlers for babel methods in the global ubus context.
422 static bool ubus_init_object() {
423 int ret;
424
425 ret = ubus_add_object(shared_ctx, &babeld_object);
426 if (ret) {
427 fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret));
428 return false;
429 }
430
431 return true;
432 }
433
434 // Initializes the global ubus context, connecting to the bus to be able to
435 // receive and send messages.
436 static bool babeld_ubus_init(void) {
437 if (shared_ctx)
438 return true;
439
440 shared_ctx = ubus_connect(NULL);
441 if (!shared_ctx)
442 return false;
443
444 return true;
445 }
446
447 void ubus_notify_route(struct babel_route *route, int kind) {
448 struct blob_buf b = {0};
449 char method[50]; // possible methods are route.change, route.add, route.flush
450
451 if (!babeld_object.has_subscribers)
452 return;
453
454 if (!route)
455 return;
456
457 if (!shared_ctx)
458 return;
459
460 blob_buf_init(&b, 0);
461 babeld_add_route_buf(route, &b);
462 snprintf(method, sizeof(method), "route.%s", local_kind(kind));
463 ubus_notify(shared_ctx, &babeld_object, method, b.head, -1);
464 blob_buf_free(&b);
465 }
466
467 void ubus_notify_xroute(struct xroute *xroute, int kind) {
468 struct blob_buf b = {0};
469 char method[50]; // possible methods are xroute.change, xroute.add,
470 // xroute.flush
471
472 if (!babeld_object.has_subscribers)
473 return;
474
475 if (!xroute)
476 return;
477
478 if (!shared_ctx)
479 return;
480
481 blob_buf_init(&b, 0);
482 babeld_add_xroute_buf(xroute, &b);
483 snprintf(method, sizeof(method), "xroute.%s", local_kind(kind));
484 ubus_notify(shared_ctx, &babeld_object, method, b.head, -1);
485 blob_buf_free(&b);
486 }
487
488 void ubus_notify_neighbour(struct neighbour *neigh, int kind) {
489 struct blob_buf b = {0};
490 char method[50]; // possible methods are neigh.change, neigh.add, neigh.flush
491
492 if (!babeld_object.has_subscribers)
493 return;
494
495 if (!neigh)
496 return;
497
498 if (!shared_ctx)
499 return;
500
501 blob_buf_init(&b, 0);
502 babeld_add_neighbour_buf(neigh, &b);
503 snprintf(method, sizeof(method), "neigh.%s", local_kind(kind));
504 ubus_notify(shared_ctx, &babeld_object, method, b.head, -1);
505 blob_buf_free(&b);
506 }
507
508 void babeld_ubus_receive(fd_set *readfds) {
509 if (!shared_ctx)
510 return;
511 if (FD_ISSET(shared_ctx->sock.fd, readfds))
512 ubus_handle_event(shared_ctx);
513 }
514
515 int babeld_ubus_add_read_sock(fd_set *readfds, int maxfd) {
516 if (!shared_ctx)
517 return maxfd;
518
519 FD_SET(shared_ctx->sock.fd, readfds);
520 return MAX(maxfd, shared_ctx->sock.fd);
521 }
522
523 bool babeld_add_ubus() {
524 if (!babeld_ubus_init()) {
525 fprintf(stderr, "Failed to initialize ubus!\n");
526 return false;
527 }
528
529 if (!ubus_init_object()) {
530 fprintf(stderr, "Failed to add objects to ubus!\n");
531 return false;
532 }
533
534 return true;
535 }