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