Merge ed191a2789
into 64f4095c1c
This commit is contained in:
commit
46e9566e4f
@ -24,8 +24,8 @@ CFLAGS_JSONC = $(shell pkg-config --cflags json-c)
|
|||||||
LDFLAGS_JSONC = $(shell pkg-config --libs json-c)
|
LDFLAGS_JSONC = $(shell pkg-config --libs json-c)
|
||||||
|
|
||||||
|
|
||||||
respondd.so: respondd.c handle_neighbour.c
|
respondd.so: respondd.c
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -shared $(LDFLAGS_JSONC) -o $@ $^ -lgluonutil -lblobmsg_json -lubox -lubus -luci
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -shared $(LDFLAGS_JSONC) -o $@ $^ -lgluonutil -lblobmsg_json -lubox -lubus -luci
|
||||||
|
|
||||||
neighbours-babel: neighbours-babel.c handle_neighbour.c
|
neighbours-babel: neighbours-babel.c
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_JSONC) $(LDFLAGS) $(LDLIBS) $(LDFLAGS_JSONC) -o $@ $^
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_JSONC) $(LDFLAGS) $(LDLIBS) $(LDFLAGS_JSONC) -o $@ $^
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "handle_neighbour.h"
|
|
||||||
#include <libbabelhelper/babelhelper.h>
|
|
||||||
|
|
||||||
bool handle_neighbour(char **data, void *arg) {
|
|
||||||
struct json_object *obj = (struct json_object*)arg;
|
|
||||||
|
|
||||||
if (data[NEIGHBOUR]) {
|
|
||||||
struct json_object *neigh = json_object_new_object();
|
|
||||||
|
|
||||||
if (data[RXCOST])
|
|
||||||
json_object_object_add(neigh, "rxcost", json_object_new_int(atoi(data[RXCOST])));
|
|
||||||
if (data[TXCOST])
|
|
||||||
json_object_object_add(neigh, "txcost", json_object_new_int(atoi(data[TXCOST])));
|
|
||||||
if (data[COST])
|
|
||||||
json_object_object_add(neigh, "cost", json_object_new_int(atoi(data[COST])));
|
|
||||||
if (data[REACH])
|
|
||||||
json_object_object_add(neigh, "reachability", json_object_new_double(strtod(data[REACH], NULL)));
|
|
||||||
if (data[IF])
|
|
||||||
json_object_object_add(neigh, "ifname", json_object_new_string(data[IF]));
|
|
||||||
if (data[ADDRESS])
|
|
||||||
json_object_object_add(obj, data[ADDRESS] , neigh);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
@ -2,8 +2,30 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <json-c/json.h>
|
#include <json-c/json.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <libbabelhelper/babelhelper.h>
|
#include <libbabelhelper/babelhelper.h>
|
||||||
#include "handle_neighbour.h"
|
|
||||||
|
bool handle_neighbour(char **data, void *arg) {
|
||||||
|
struct json_object *obj = (struct json_object*)arg;
|
||||||
|
|
||||||
|
if (data[NEIGHBOUR]) {
|
||||||
|
struct json_object *neigh = json_object_new_object();
|
||||||
|
|
||||||
|
if (data[RXCOST])
|
||||||
|
json_object_object_add(neigh, "rxcost", json_object_new_int(atoi(data[RXCOST])));
|
||||||
|
if (data[TXCOST])
|
||||||
|
json_object_object_add(neigh, "txcost", json_object_new_int(atoi(data[TXCOST])));
|
||||||
|
if (data[COST])
|
||||||
|
json_object_object_add(neigh, "cost", json_object_new_int(atoi(data[COST])));
|
||||||
|
if (data[REACH])
|
||||||
|
json_object_object_add(neigh, "reachability", json_object_new_double(strtod(data[REACH], NULL)));
|
||||||
|
if (data[IF])
|
||||||
|
json_object_object_add(neigh, "ifname", json_object_new_string(data[IF]));
|
||||||
|
if (data[ADDRESS])
|
||||||
|
json_object_object_add(obj, data[ADDRESS] , neigh);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
struct json_object *neighbours;
|
struct json_object *neighbours;
|
||||||
|
@ -29,6 +29,10 @@
|
|||||||
#include <json-c/json.h>
|
#include <json-c/json.h>
|
||||||
#include <libgluonutil.h>
|
#include <libgluonutil.h>
|
||||||
#include <uci.h>
|
#include <uci.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@ -61,6 +65,245 @@
|
|||||||
#define UBUS_TIMEOUT 30000
|
#define UBUS_TIMEOUT 30000
|
||||||
|
|
||||||
static struct babelhelper_ctx bhelper_ctx = {};
|
static struct babelhelper_ctx bhelper_ctx = {};
|
||||||
|
static struct json_object *babeld_version = NULL;
|
||||||
|
|
||||||
|
static char *model = NULL;
|
||||||
|
static struct json_object *neighbours = NULL;
|
||||||
|
static pthread_rwlock_t neighbours_lock;
|
||||||
|
static pthread_t babelmonitor;
|
||||||
|
|
||||||
|
struct thread_info {
|
||||||
|
pthread_t thread_id;
|
||||||
|
int thread_num;
|
||||||
|
char *argv_string;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct kernel_route {
|
||||||
|
struct in6_addr prefix;
|
||||||
|
struct in6_addr src_prefix;
|
||||||
|
struct in6_addr gw;
|
||||||
|
int plen;
|
||||||
|
int src_plen; /* no source prefix <=> src_plen == 0 */
|
||||||
|
int metric;
|
||||||
|
int proto;
|
||||||
|
unsigned int ifindex;
|
||||||
|
unsigned int table;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nlrtreq {
|
||||||
|
struct nlmsghdr nl;
|
||||||
|
struct rtmsg rt;
|
||||||
|
char buf[1024];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ROUTE_PROTO 158
|
||||||
|
#define KERNEL_INFINITY 9999
|
||||||
|
|
||||||
|
static const char *print_ip(const struct in6_addr *addr, char *buf, size_t buflen) {
|
||||||
|
return inet_ntop(AF_INET6, &(addr->s6_addr), buf, buflen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rtnl_addattr(struct nlmsghdr *n, size_t maxlen, int type, void *data, int datalen) {
|
||||||
|
int len = RTA_LENGTH(datalen);
|
||||||
|
struct rtattr *rta;
|
||||||
|
if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
|
||||||
|
return -1;
|
||||||
|
rta = (struct rtattr *)(((char *)n) + NLMSG_ALIGN(n->nlmsg_len));
|
||||||
|
rta->rta_type = type;
|
||||||
|
rta->rta_len = len;
|
||||||
|
memcpy(RTA_DATA(rta), data, datalen);
|
||||||
|
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtmgr_rtnl_talk(int fd, struct nlmsghdr *req) {
|
||||||
|
struct sockaddr_nl nladdr = {.nl_family = AF_NETLINK};
|
||||||
|
|
||||||
|
struct iovec iov = {req, 0};
|
||||||
|
struct msghdr msg = {&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0};
|
||||||
|
|
||||||
|
iov.iov_len = req->nlmsg_len;
|
||||||
|
|
||||||
|
if (sendmsg(fd, &msg, 0) < 0) {
|
||||||
|
perror("sendmsg on rtmgr_rtnl_talk()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_route(int fd, const int ifindex, struct in6_addr *address, const int prefix_length) {
|
||||||
|
struct nlrtreq req = {
|
||||||
|
.nl = {
|
||||||
|
.nlmsg_type = RTM_GETROUTE,
|
||||||
|
.nlmsg_flags = NLM_F_REQUEST,
|
||||||
|
.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
|
||||||
|
},
|
||||||
|
.rt = {
|
||||||
|
.rtm_family = AF_INET6,
|
||||||
|
.rtm_protocol = ROUTE_PROTO,
|
||||||
|
.rtm_scope = RT_SCOPE_UNIVERSE,
|
||||||
|
.rtm_type = RTN_UNICAST,
|
||||||
|
.rtm_dst_len = prefix_length
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
rtnl_addattr(&req.nl, sizeof(req), RTA_DST, (void *)address, sizeof(struct in6_addr));
|
||||||
|
|
||||||
|
if (ifindex > 0 )
|
||||||
|
rtnl_addattr(&req.nl, sizeof(req), RTA_OIF, (void *)&ifindex, sizeof(ifindex));
|
||||||
|
|
||||||
|
rtmgr_rtnl_talk(fd, (struct nlmsghdr *)&req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_kernel_route_rta(struct rtmsg *rtm, int len, struct kernel_route *route) {
|
||||||
|
len -= NLMSG_ALIGN(sizeof(*rtm));
|
||||||
|
|
||||||
|
memset(route, 0, sizeof(struct kernel_route));
|
||||||
|
route->proto = rtm->rtm_protocol;
|
||||||
|
|
||||||
|
for (struct rtattr *rta = RTM_RTA(rtm); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
|
||||||
|
switch (rta->rta_type) {
|
||||||
|
case RTA_DST:
|
||||||
|
route->plen = rtm->rtm_dst_len;
|
||||||
|
memcpy(route->prefix.s6_addr, RTA_DATA(rta), 16);
|
||||||
|
break;
|
||||||
|
case RTA_SRC:
|
||||||
|
route->src_plen = rtm->rtm_src_len;
|
||||||
|
memcpy(route->src_prefix.s6_addr, RTA_DATA(rta), 16);
|
||||||
|
break;
|
||||||
|
case RTA_GATEWAY:
|
||||||
|
memcpy(route->gw.s6_addr, RTA_DATA(rta), 16);
|
||||||
|
break;
|
||||||
|
case RTA_OIF:
|
||||||
|
route->ifindex = *(int *)RTA_DATA(rta);
|
||||||
|
break;
|
||||||
|
case RTA_PRIORITY:
|
||||||
|
route->metric = *(int *)RTA_DATA(rta);
|
||||||
|
if (route->metric < 0 || route->metric > KERNEL_INFINITY)
|
||||||
|
route->metric = KERNEL_INFINITY;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool handle_kernel_routes(const struct nlmsghdr *nh, struct kernel_route *route) {
|
||||||
|
int len = nh->nlmsg_len;
|
||||||
|
struct rtmsg *rtm;
|
||||||
|
|
||||||
|
rtm = (struct rtmsg *)NLMSG_DATA(nh);
|
||||||
|
len -= NLMSG_LENGTH(0);
|
||||||
|
|
||||||
|
/* Ignore cached routes, advertised by some kernels (linux 3.x). */
|
||||||
|
if (rtm->rtm_flags & RTM_F_CLONED) return false;
|
||||||
|
|
||||||
|
if (parse_kernel_route_rta(rtm, len, route) < 0) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool rtnl_handle_msg(const struct nlmsghdr *nh,
|
||||||
|
struct kernel_route *route) {
|
||||||
|
if (nh->nlmsg_type == RTM_NEWROUTE) {
|
||||||
|
handle_kernel_routes(nh, route);
|
||||||
|
if (!(route->plen == 0 && route->metric >= KERNEL_INFINITY))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_default_route(struct json_object *ret) {
|
||||||
|
int nlfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||||
|
if (nlfd < 0) {
|
||||||
|
perror("can't open RTNL socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
struct sockaddr_nl snl = {
|
||||||
|
.nl_family = AF_NETLINK,
|
||||||
|
.nl_groups = RTMGRP_IPV6_ROUTE,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (bind(nlfd, (struct sockaddr *)&snl, sizeof(snl)) < 0)
|
||||||
|
perror("can't bind RTNL socket");
|
||||||
|
|
||||||
|
struct in6_addr addr = {};
|
||||||
|
inet_pton(AF_INET6, "2000::/3", &addr);
|
||||||
|
|
||||||
|
get_route(nlfd, 0, &addr, 3);
|
||||||
|
|
||||||
|
struct nlmsghdr readbuffer[8192/sizeof(struct nlmsghdr)];
|
||||||
|
int count = recv(nlfd, readbuffer, sizeof(readbuffer), 0);
|
||||||
|
|
||||||
|
struct nlmsghdr *nh;
|
||||||
|
struct nlmsgerr *ne;
|
||||||
|
struct kernel_route route;
|
||||||
|
|
||||||
|
nh = (struct nlmsghdr *)readbuffer;
|
||||||
|
if (NLMSG_OK(nh, count)) {
|
||||||
|
switch (nh->nlmsg_type) {
|
||||||
|
case NLMSG_DONE:
|
||||||
|
break;
|
||||||
|
case NLMSG_ERROR:
|
||||||
|
ne = NLMSG_DATA(nh);
|
||||||
|
if (ne->error <= 0)
|
||||||
|
break;
|
||||||
|
/* Falls through. */
|
||||||
|
default:
|
||||||
|
if (rtnl_handle_msg(nh, &route) == true) {
|
||||||
|
char strbuf[64];
|
||||||
|
// TODO: for each route that is retrieved, create a json object
|
||||||
|
// containing src, via, interface Yanic currently requires this layout
|
||||||
|
// but it makes sense to adjust it. See https://github.com/FreifunkBremen/yanic/issues/170
|
||||||
|
if (ret) {
|
||||||
|
json_object_object_add(ret, "gateway_src", json_object_new_string(print_ip(&route.src_prefix, strbuf, 64)));
|
||||||
|
json_object_object_add(ret, "gateway_nexthop", json_object_new_string(print_ip(&route.gw, strbuf, 64)));
|
||||||
|
char ifname[IFNAMSIZ];
|
||||||
|
json_object_object_add(ret, "gateway_interface", json_object_new_string(if_indextoname(route.ifindex, ifname)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(nlfd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int babeld_connect() {
|
||||||
|
int fd = -1;
|
||||||
|
fd_set rfds;
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
|
||||||
|
printf("connecting to babeld\n");
|
||||||
|
|
||||||
|
do {
|
||||||
|
fd = babelhelper_babel_connect(BABEL_PORT);
|
||||||
|
if (fd < 0) {
|
||||||
|
fprintf(stderr, "Connecting to babel socket failed. Retrying.\n");
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
} while (fd < 0);
|
||||||
|
|
||||||
|
FD_SET(fd, &rfds);
|
||||||
|
|
||||||
|
// receive and ignore babel header
|
||||||
|
while (true) {
|
||||||
|
if ( babelhelper_input_pump(&bhelper_ctx, fd, NULL, babelhelper_discard_response))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (select(fd + 1, &rfds, NULL, NULL, NULL) < 0) {
|
||||||
|
perror("select (babel header):");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
int amount = 0;
|
||||||
|
while (amount != 8) {
|
||||||
|
amount = babelhelper_sendcommand(&bhelper_ctx, fd, "monitor\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
static void obtain_if_addr(const char *ifname, char *lladdr) {
|
static void obtain_if_addr(const char *ifname, char *lladdr) {
|
||||||
struct ifaddrs *ifaddr, *ifa;
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
@ -96,6 +339,104 @@ cleanup:
|
|||||||
freeifaddrs(ifaddr);
|
freeifaddrs(ifaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void add_neighbour(char **data) {
|
||||||
|
struct json_object *neigh = json_object_new_object();
|
||||||
|
|
||||||
|
if (!neigh)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (data[RXCOST])
|
||||||
|
json_object_object_add(neigh, "rxcost", json_object_new_int(atoi(data[RXCOST])));
|
||||||
|
if (data[TXCOST])
|
||||||
|
json_object_object_add(neigh, "txcost", json_object_new_int(atoi(data[TXCOST])));
|
||||||
|
if (data[COST])
|
||||||
|
json_object_object_add(neigh, "cost", json_object_new_int(atoi(data[COST])));
|
||||||
|
if (data[REACH])
|
||||||
|
json_object_object_add(neigh, "reachability", json_object_new_double(strtod(data[REACH], NULL)));
|
||||||
|
|
||||||
|
struct json_object *nif = NULL;
|
||||||
|
|
||||||
|
if (data[IF] && !json_object_object_get_ex(neighbours, data[IF], &nif)) {
|
||||||
|
char str_ip[NI_MAXHOST] = {};
|
||||||
|
obtain_if_addr((const char *)data[IF], str_ip);
|
||||||
|
|
||||||
|
nif = json_object_new_object();
|
||||||
|
if (nif) {
|
||||||
|
json_object_object_add(nif, "ll-addr", json_object_new_string(str_ip));
|
||||||
|
json_object_object_add(nif, "protocol", json_object_new_string("babel"));
|
||||||
|
json_object_object_add(neighbours, data[IF], nif);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_object *nif_neighbours = NULL;
|
||||||
|
if (!json_object_object_get_ex(nif, "neighbours", &nif_neighbours)) {
|
||||||
|
nif_neighbours = json_object_new_object();
|
||||||
|
if (nif_neighbours) {
|
||||||
|
json_object_object_add(nif, "neighbours", nif_neighbours);
|
||||||
|
json_object_object_add(nif_neighbours, data[ADDRESS], neigh);
|
||||||
|
} else {
|
||||||
|
json_object_put(neigh);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
json_object_object_add(nif_neighbours, data[ADDRESS], neigh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void del_neighbour(char **data) {
|
||||||
|
struct json_object *nif = NULL;
|
||||||
|
if (json_object_object_get_ex(neighbours, data[IF], &nif)) {
|
||||||
|
struct json_object *neighbour = NULL;
|
||||||
|
if (json_object_object_get_ex(nif, "neighbours", &neighbour)) {
|
||||||
|
json_object_object_del(neighbour, data[ADDRESS]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool handle_neighbour(char **data, void *obj) {
|
||||||
|
if (data[NEIGHBOUR]) {
|
||||||
|
pthread_rwlock_wrlock(&neighbours_lock);
|
||||||
|
if (strncmp(data[VERB], "add", 3) == 0) {
|
||||||
|
del_neighbour(data);
|
||||||
|
add_neighbour(data);
|
||||||
|
} else if (strncmp(data[VERB], "del", 3) == 0) {
|
||||||
|
del_neighbour(data);
|
||||||
|
} else if (strncmp(data[VERB], "change", 6) == 0) {
|
||||||
|
del_neighbour(data);
|
||||||
|
add_neighbour(data);
|
||||||
|
}
|
||||||
|
pthread_rwlock_unlock(&neighbours_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool babel_lineprocessor(char **data, void *object) {
|
||||||
|
return handle_neighbour(data, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *babeld_monitor_thread_start(void *arg) {
|
||||||
|
while (true) {
|
||||||
|
int babelfd = babeld_connect();
|
||||||
|
|
||||||
|
fd_set rfds;
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_SET(babelfd, &rfds);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if ( babelhelper_input_pump(&bhelper_ctx, babelfd, NULL, babel_lineprocessor) < 0 ) {
|
||||||
|
perror("input pump");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (select(babelfd + 1, &rfds, NULL, NULL, NULL) < 0) {
|
||||||
|
perror("select (babel data):");
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
close(babelfd);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static char *get_line_from_run(const char *command) {
|
static char *get_line_from_run(const char *command) {
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
@ -122,9 +463,47 @@ static char* get_line_from_run(const char* command) {
|
|||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__((constructor)) static void init(void) {
|
||||||
|
if (pthread_rwlock_init(&neighbours_lock, NULL) != 0) {
|
||||||
|
perror("rwlock init failed for neighbours");
|
||||||
|
exit(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
neighbours = json_object_new_object();
|
||||||
|
|
||||||
|
char *version = get_line_from_run("exec babeld -V 2>&1");
|
||||||
|
babeld_version = gluonutil_wrap_string(version);
|
||||||
|
free(version);
|
||||||
|
|
||||||
|
model = gluonutil_read_line("/tmp/sysinfo/model");
|
||||||
|
|
||||||
|
if (neighbours) {
|
||||||
|
if (pthread_create(&babelmonitor, NULL, &babeld_monitor_thread_start, NULL) < 0 ) {
|
||||||
|
perror("error on pthread_create for babel monitor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Unable to allocate json object >neighbours< - not creating neighbour watcher thread. The neighbour structure will always be empty.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((destructor)) static void deinit(void) {
|
||||||
|
pthread_cancel(babelmonitor);
|
||||||
|
int s = pthread_join(babelmonitor, NULL);
|
||||||
|
if (s)
|
||||||
|
perror("pthread_cancel");
|
||||||
|
pthread_rwlock_destroy(&neighbours_lock);
|
||||||
|
}
|
||||||
|
|
||||||
static struct json_object * get_addresses(void) {
|
static struct json_object * get_addresses(void) {
|
||||||
char *primarymac = gluonutil_get_sysconfig("primary_mac");
|
char *primarymac = gluonutil_get_sysconfig("primary_mac");
|
||||||
char *address = malloc(INET6_ADDRSTRLEN+1);
|
char *address = malloc(INET6_ADDRSTRLEN+1);
|
||||||
|
|
||||||
|
if (!address) {
|
||||||
|
fprintf(stderr, "Could not allocate memory for ipv6 address, not adding addresses to json data.\n");
|
||||||
|
goto free;
|
||||||
|
}
|
||||||
|
|
||||||
char node_prefix_str[INET6_ADDRSTRLEN+1];
|
char node_prefix_str[INET6_ADDRSTRLEN+1];
|
||||||
struct in6_addr node_prefix = {};
|
struct in6_addr node_prefix = {};
|
||||||
struct json_object *retval = json_object_new_array();
|
struct json_object *retval = json_object_new_array();
|
||||||
@ -140,14 +519,20 @@ static struct json_object * get_addresses(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *prefix_addresspart = strndup(node_prefix_str, INET6_ADDRSTRLEN);
|
char *prefix_addresspart = strndup(node_prefix_str, INET6_ADDRSTRLEN);
|
||||||
if (! babelhelper_generateip_str(address, primarymac, prefix_addresspart) ) {
|
if (!prefix_addresspart) {
|
||||||
fprintf(stderr, "IP-address could not be generated by babelhelper");
|
fprintf(stderr, "could not allocate memory to hold node_prefix_str. Not adding address to json data\n");
|
||||||
|
goto free;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! babelhelper_generateip_str(address, primarymac, prefix_addresspart) ) {
|
||||||
|
fprintf(stderr, "IP-address could not be generated by babelhelper\n");
|
||||||
|
goto free;
|
||||||
}
|
}
|
||||||
free(prefix_addresspart);
|
|
||||||
|
|
||||||
json_object_array_add(retval, json_object_new_string(address));
|
json_object_array_add(retval, json_object_new_string(address));
|
||||||
|
|
||||||
free:
|
free:
|
||||||
|
free(prefix_addresspart);
|
||||||
free(address);
|
free(address);
|
||||||
free(primarymac);
|
free(primarymac);
|
||||||
|
|
||||||
@ -176,57 +561,6 @@ static void mesh_add_if(const char *ifname, struct json_object *wireless,
|
|||||||
json_object_array_add(tunnel, address);
|
json_object_array_add(tunnel, address);
|
||||||
else
|
else
|
||||||
json_object_array_add(other, address);
|
json_object_array_add(other, address);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool handle_neighbour(char **data, void *obj) {
|
|
||||||
if (data[NEIGHBOUR]) {
|
|
||||||
struct json_object *neigh = json_object_new_object();
|
|
||||||
|
|
||||||
if (data[RXCOST])
|
|
||||||
json_object_object_add(neigh, "rxcost", json_object_new_int(atoi(data[RXCOST])));
|
|
||||||
if (data[TXCOST])
|
|
||||||
json_object_object_add(neigh, "txcost", json_object_new_int(atoi(data[TXCOST])));
|
|
||||||
if (data[COST])
|
|
||||||
json_object_object_add(neigh, "cost", json_object_new_int(atoi(data[COST])));
|
|
||||||
if (data[REACH])
|
|
||||||
json_object_object_add(neigh, "reachability", json_object_new_double(strtod(data[REACH], NULL)));
|
|
||||||
|
|
||||||
struct json_object *nif = 0;
|
|
||||||
if (data[IF] && !json_object_object_get_ex(obj, data[IF], &nif)) {
|
|
||||||
char str_ip[NI_MAXHOST] = {};
|
|
||||||
obtain_if_addr( (const char*)data[IF], str_ip );
|
|
||||||
|
|
||||||
nif = json_object_new_object();
|
|
||||||
|
|
||||||
json_object_object_add(nif, "ll-addr", json_object_new_string(str_ip));
|
|
||||||
json_object_object_add(nif, "protocol", json_object_new_string("babel"));
|
|
||||||
json_object_object_add(obj, data[IF], nif);
|
|
||||||
|
|
||||||
}
|
|
||||||
struct json_object *neighborcollector = 0;
|
|
||||||
if (!json_object_object_get_ex(nif, "neighbours", &neighborcollector)) {
|
|
||||||
neighborcollector = json_object_new_object();
|
|
||||||
json_object_object_add(nif, "neighbours", neighborcollector);
|
|
||||||
}
|
|
||||||
|
|
||||||
json_object_object_add(neighborcollector, data[ADDRESS], neigh);
|
|
||||||
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct json_object * get_babel_neighbours(void) {
|
|
||||||
|
|
||||||
struct json_object *neighbours;
|
|
||||||
neighbours = json_object_new_object();
|
|
||||||
if (!neighbours)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
babelhelper_readbabeldata(&bhelper_ctx, "dump", (void*)neighbours, handle_neighbour);
|
|
||||||
|
|
||||||
return(neighbours);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void blobmsg_handle_list(struct blob_attr *attr, int len, bool array, struct json_object *wireless, struct json_object *tunnel, struct json_object *other);
|
static void blobmsg_handle_list(struct blob_attr *attr, int len, bool array, struct json_object *wireless, struct json_object *tunnel, struct json_object *other);
|
||||||
@ -305,7 +639,6 @@ static void receive_call_result_data(struct ubus_request *req, int type, struct
|
|||||||
*((struct json_object**)(req->priv)) = ret;
|
*((struct json_object**)(req->priv)) = ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct json_object * get_mesh_ifs() {
|
static struct json_object * get_mesh_ifs() {
|
||||||
struct ubus_context *ubus_ctx;
|
struct ubus_context *ubus_ctx;
|
||||||
struct json_object *ret = NULL;
|
struct json_object *ret = NULL;
|
||||||
@ -344,11 +677,9 @@ static struct json_object * get_mesh(void) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct json_object * get_babeld_version(void) {
|
static struct json_object * get_babeld_version(void) {
|
||||||
char *version = get_line_from_run("exec babeld -V 2>&1");
|
return babeld_version ? json_object_get(babeld_version) : json_object_new_string("unknown");
|
||||||
struct json_object *ret = gluonutil_wrap_string(version);
|
|
||||||
free(version);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct json_object * respondd_provider_nodeinfo(void) {
|
static struct json_object * respondd_provider_nodeinfo(void) {
|
||||||
@ -390,9 +721,7 @@ static struct json_object * read_number(const char *ifname, const char *stat) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct json_object * get_traffic(void) {
|
static struct json_object * get_traffic_if(const char *ifname) {
|
||||||
const char *ifname = "br-client";
|
|
||||||
|
|
||||||
struct json_object *ret = NULL;
|
struct json_object *ret = NULL;
|
||||||
struct json_object *rx = json_object_new_object();
|
struct json_object *rx = json_object_new_object();
|
||||||
struct json_object *tx = json_object_new_object();
|
struct json_object *tx = json_object_new_object();
|
||||||
@ -407,21 +736,17 @@ static struct json_object * get_traffic(void) {
|
|||||||
ret = json_object_new_object();
|
ret = json_object_new_object();
|
||||||
json_object_object_add(ret, "rx", rx);
|
json_object_object_add(ret, "rx", rx);
|
||||||
json_object_object_add(ret, "tx", tx);
|
json_object_object_add(ret, "tx", tx);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool handle_route_addgw_nexthop(char **data, void *arg) {
|
static struct json_object * get_traffic(void) {
|
||||||
struct json_object *obj = (struct json_object*) arg;
|
struct json_object *ret = get_traffic_if("br-client"); // keep for compatibility
|
||||||
if (data[PREFIX] && data[FROM] && data[VIA] && data[IF]) {
|
json_object_object_add(ret, "local-node", get_traffic_if("local-node"));
|
||||||
if ( (! strncmp(data[PREFIX], "::/0", 4) ) && ( ! strncmp(data[FROM], "::/0", 4) ) ) {
|
json_object_object_add(ret, "br-client", get_traffic_if("br-client"));
|
||||||
int gw_nexthoplen=strlen(data[VIA]) + strlen(data[IF])+2;
|
|
||||||
char gw_nexthop[gw_nexthoplen];
|
// TODO: add traffic stats for all mesh interfaces
|
||||||
snprintf(gw_nexthop, gw_nexthoplen , "%s%%%s", data[VIA], data[IF]);
|
|
||||||
json_object_object_add(obj, "gateway_nexthop", json_object_new_string(gw_nexthop));
|
return ret;
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int json_parse_get_clients(json_object * object) {
|
static int json_parse_get_clients(json_object * object) {
|
||||||
@ -507,18 +832,35 @@ static struct json_object * respondd_provider_statistics(void) {
|
|||||||
json_object_object_add(ret, "clients", get_clients());
|
json_object_object_add(ret, "clients", get_clients());
|
||||||
json_object_object_add(ret, "traffic", get_traffic());
|
json_object_object_add(ret, "traffic", get_traffic());
|
||||||
|
|
||||||
babelhelper_readbabeldata(&bhelper_ctx, "dump", (void*)ret, handle_route_addgw_nexthop );
|
get_default_route(ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct json_object * respondd_provider_neighbours(void) {
|
static struct json_object * respondd_provider_neighbours(void) {
|
||||||
struct json_object *ret = json_object_new_object();
|
struct json_object *ret = json_object_new_object();
|
||||||
|
struct json_object *neighbours_copy = NULL;
|
||||||
|
|
||||||
struct json_object *babel = get_babel_neighbours();
|
if (!ret)
|
||||||
if (babel)
|
return NULL;
|
||||||
json_object_object_add(ret, "babel", babel);
|
|
||||||
|
|
||||||
|
if (neighbours) {
|
||||||
|
pthread_rwlock_rdlock(&neighbours_lock);
|
||||||
|
#if (JSON_C_MINOR_VERSION >= 13)
|
||||||
|
int deepcopy_state = json_object_deep_copy(neighbours, &neighbours_copy, NULL);
|
||||||
|
#else
|
||||||
|
char *serialized_neighbours = json_object_to_json_string(neighbours);
|
||||||
|
#endif
|
||||||
|
pthread_rwlock_unlock(&neighbours_lock);
|
||||||
|
|
||||||
|
#if (JSON_C_MINOR_VERSION >= 13)
|
||||||
|
if (!deepcopy_state)
|
||||||
|
json_object_object_add(ret, "babel", neighbours_copy);
|
||||||
|
#else
|
||||||
|
if (serialized_neighbours)
|
||||||
|
json_object_object_add(ret, "babel", json_tokener_parse(serialized_neighbours));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user