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