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