From d77996abeaf667e27ed1c2296b31208020ec38b0 Mon Sep 17 00:00:00 2001 From: Anjan Chanda <anjan.chanda@iopsys.eu> Date: Mon, 27 Jul 2020 13:44:46 +0200 Subject: [PATCH] refactor and cleanup codebase --- .gitignore | 13 ++ src/Makefile | 12 +- src/config.c | 150 ++++++++++++ src/config.h | 17 ++ src/debug.c | 45 ++++ src/debug.h | 20 ++ src/hlist.h | 101 ++++++++ src/json_utils.c | 44 ++++ src/json_utils.h | 11 + src/main.c | 110 ++++++++- src/nodes.c | 110 +++++++++ src/nodes.h | 17 ++ src/topo_ieee1905.c | 196 ++++++++++++++++ src/topologyd.c | 558 ++++++++++++++++++++++++++++++++++++++++++++ src/topologyd.h | 102 ++++++++ src/topomap.c | 258 -------------------- src/topomap.h | 33 --- src/topoubus.c | 310 ------------------------ src/topoubus.h | 21 -- src/topoutils.c | 36 --- src/topoutils.h | 36 --- 21 files changed, 1496 insertions(+), 704 deletions(-) create mode 100644 .gitignore create mode 100644 src/config.c create mode 100644 src/config.h create mode 100644 src/debug.c create mode 100644 src/debug.h create mode 100644 src/hlist.h create mode 100644 src/json_utils.c create mode 100644 src/json_utils.h create mode 100644 src/nodes.c create mode 100644 src/nodes.h create mode 100644 src/topo_ieee1905.c create mode 100644 src/topologyd.c create mode 100644 src/topologyd.h delete mode 100644 src/topomap.c delete mode 100644 src/topomap.h delete mode 100644 src/topoubus.c delete mode 100644 src/topoubus.h delete mode 100644 src/topoutils.c delete mode 100644 src/topoutils.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0a72759 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.built +.built_check +.configured_ +.dep_files +.git_update +.prepared_* +ipkg-* +**/*.o +**/*.so +src/tags +src/topologyd +.configured_* +.pkgdir diff --git a/src/Makefile b/src/Makefile index 53af95c..9d76775 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,18 +1,20 @@ -CFLAGS+=-I. -Iinclude -D_GNU_SOURCE +PROG=topologyd + +CFLAGS+=-I. -D_GNU_SOURCE CFLAGS+= -g -Wall -pthread -OBJS = main.o topomap.o topoubus.o topoutils.o +OBJS = main.o debug.o config.o json_utils.o nodes.o topo_ieee1905.o topologyd.o LIBS = -lubus -lubox -ljson-c -lblobmsg_json -luci -pthread -leasy -lmaputils .PHONY: all check clean FORCE -all: topo1905d +all: $(PROG) %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< -topo1905d: $(OBJS) +$(PROG): $(OBJS) $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) check: FORCE @@ -26,6 +28,6 @@ check: FORCE . 2> cppcheck.out clean: - rm -f *.o src/*.o topo1905d + rm -f *.o src/*.o $(PROG) FORCE: diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..1b11f35 --- /dev/null +++ b/src/config.c @@ -0,0 +1,150 @@ +/* + * config.c - configuration handling + * + * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved. + * + * See LICENSE and CREDITS file for related information. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include <json-c/json.h> +#include <libubox/blobmsg.h> +#include <libubox/blobmsg_json.h> +#include <libubox/uloop.h> +#include <libubox/ustream.h> +#include <libubox/utils.h> +#include <libubus.h> +#include <uci.h> + +#include "debug.h" +#include "topologyd.h" +#include "config.h" + + +void topologyd_config_dump(struct topologyd_config *cfg) +{ + dbg("Topologyd config ---------\n"); + dbg("Enabled : %d\n", cfg->enabled); + dbg("Depth : %d\n", cfg->depth); + dbg("Refresh interval : %d seconds\n", cfg->refresh_int); + dbg("Log entries : %d max\n", cfg->maxlog); + + dbg("---------------------------\n"); +} + +int topologyd_config_defaults(struct topologyd_config *cfg) +{ + if (!cfg) + return -1; + + cfg->enabled = false; + cfg->depth = TOPOLOGY_DEPTH; + cfg->refresh_int = TOPOLOGY_REFRESH_INT; + cfg->maxlog = TOPOLOGY_LOG_MAX; + + return 0; +} + +static int config_get_section_topology(struct topologyd_config *cfg, + struct uci_section *s) +{ + enum { + TOPOLOGY_ATTR_ENABLED, + TOPOLOGY_ATTR_DEPTH, + TOPOLOGY_ATTR_INTERVAL, + TOPOLOGY_ATTR_MAXLOG, + NUM_TOPOLOGY_ATTRS, + }; + const struct uci_parse_option opts[] = { + { .name = "enabled", .type = UCI_TYPE_STRING }, + { .name = "depth", .type = UCI_TYPE_STRING }, + { .name = "interval", .type = UCI_TYPE_STRING }, + { .name = "maxlog", .type = UCI_TYPE_STRING }, + }; + struct uci_option *tb[NUM_TOPOLOGY_ATTRS]; + + + uci_parse_section(s, opts, NUM_TOPOLOGY_ATTRS, tb); + + if (tb[TOPOLOGY_ATTR_ENABLED]) { + const char *val = tb[TOPOLOGY_ATTR_ENABLED]->v.string; + + cfg->enabled = atoi(val) == 1 ? true : false; + } + + if (tb[TOPOLOGY_ATTR_DEPTH]) { + const char *val = tb[TOPOLOGY_ATTR_DEPTH]->v.string; + int v = atoi(val); + + if (v > 0) + cfg->depth = v; + } + + if (tb[TOPOLOGY_ATTR_INTERVAL]) { + const char *val = tb[TOPOLOGY_ATTR_INTERVAL]->v.string; + int v = atoi(val); + + if (v > 0) + cfg->refresh_int = v; + } + + if (tb[TOPOLOGY_ATTR_MAXLOG]) { + const char *val = tb[TOPOLOGY_ATTR_MAXLOG]->v.string; + int v = atoi(val); + + if (v > 0) + cfg->maxlog = v; + } + + return 0; +} + +static int config_get_section_extra(struct topologyd_config *cfg, + struct uci_section *s) +{ + //TODO + + return 0; +} + +int topologyd_config_user(struct topologyd_config *cfg) +{ + struct uci_context *ctx; + struct uci_package *pkg; + struct uci_element *e; + + ctx = uci_alloc_context(); + if (!ctx) + return -1; + + if (uci_load(ctx, TOPOLOGY_CONFIG, &pkg)) { + uci_free_context(ctx); + return -1; + } + + uci_foreach_element(&pkg->sections, e) { + struct uci_section *s = uci_to_section(e); + + if (!strcmp(s->type, "topology")) { + config_get_section_topology(cfg, s); + } else if (!strcmp(s->type, "extra")) { + config_get_section_extra(cfg, s); + } + } + + uci_free_context(ctx); + + topologyd_config_dump(cfg); + + return 0; +} diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..841d0ab --- /dev/null +++ b/src/config.h @@ -0,0 +1,17 @@ +/* + * config.h - configuration header file + * + * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved. + * + * See LICENSE and CREDITS file for related information. + */ +#ifndef CONFIG_H +#define CONFIG_H + + +int topologyd_config_defaults(struct topologyd_config *cfg); +int topologyd_config_user(struct topologyd_config *cfg); +void topologyd_config_dump(struct topologyd_config *cfg); + + +#endif /* CONFIG_H */ diff --git a/src/debug.c b/src/debug.c new file mode 100644 index 0000000..7cdf17a --- /dev/null +++ b/src/debug.c @@ -0,0 +1,45 @@ +/* + * debug.c - for debug and logging + * + * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved. + * + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdarg.h> +#include <syslog.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <time.h> + +#include "debug.h" + +extern bool syslogging; +static const int syslog_level[] = { LOG_ERR, LOG_WARNING, LOG_INFO, LOG_DEBUG }; + +void start_logging(const char *prog) +{ + if (syslogging) + openlog(prog, 0, LOG_DAEMON); +} + +void stop_logging(void) +{ + if (syslogging) + closelog(); +} + +void log_message(int level, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + if (syslogging && level >= 0) + vsyslog(syslog_level[level], fmt, args); + + va_end(args); +} diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 0000000..c3bb189 --- /dev/null +++ b/src/debug.h @@ -0,0 +1,20 @@ +/* + * debug.h - debug and logging header file + * + * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved. + * + */ + +#ifndef DEBUG_H +#define DEBUG_H + +void start_logging(const char *prog); +void stop_logging(void); +void log_message(int level, const char *fmt, ...); + +#define err(...) log_message(0, __VA_ARGS__) +#define warn(...) log_message(1, __VA_ARGS__) +#define info(...) log_message(2, __VA_ARGS__) +#define dbg(...) log_message(3, __VA_ARGS__) + +#endif /* DEBUG_H */ diff --git a/src/hlist.h b/src/hlist.h new file mode 100644 index 0000000..faf0078 --- /dev/null +++ b/src/hlist.h @@ -0,0 +1,101 @@ +/* + * hlist.h - stripped down version of hash list implementation using + * singly linked list. + * Doubly linked list is wastage of space for big hash-tables. If cost of + * iterating a hash list is significant, it means the hash function is NOT + * formulated well and should be revisited. + * + * Copyright (C) 2019 IOPSYS Software Solutions AB. All rights reserved. + * + * Author: anjan.chanda@iopsys.eu + * + */ + +#ifndef _HLIST_H +#define _HLIST_H + +struct hlist_node { + struct hlist_node *next; +}; + +struct hlist_head { + struct hlist_node *first; +}; + +#define HLIST_HEAD_INIT(name) { &(name) } + +#define HLIST_HEAD(name) struct hlist_head name = HLIST_HEAD_INIT(name) + +static inline void INIT_HLIST_HEAD(struct hlist_head *h) +{ + h->first = NULL; +} + +static inline void INIT_HLIST_NODE(struct hlist_node *n) +{ + n->next = NULL; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *prev, struct hlist_node *n) +{ + prev->next = n->next; + n->next = NULL; +} + +static inline void hlist_del(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *p; + + if (h->first == n) { + h->first = NULL; + n->next = NULL; + return; + } + + for (p = h->first; p; p = p->next) { + if (p->next == n) + __hlist_del(p, n); + } +} + +static inline void _hlist_add(struct hlist_node *_new, struct hlist_head *h) +{ + _new->next = h->first; + h->first = _new; +} + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + _hlist_add(n, h); +} + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos ; pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +#define hlist_entry(ptr, type, member) container_of(ptr, type, member) + +#define hlist_entry_safe(ptr, type, member) \ + ({ typeof(ptr) ____ptr = (ptr); \ + ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ + }) + +#define hlist_for_each_entry(pos, head, member) \ + for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member); \ + pos; \ + pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) + +#define hlist_for_each_entry_safe(pos, n, head, member) \ + for (pos = hlist_entry_safe((head)->first, typeof(*pos), member); \ + pos && ({ n = pos->member.next; 1; }); \ + pos = hlist_entry_safe(n, typeof(*pos), member)) + +#endif /* _HLIST_H */ diff --git a/src/json_utils.c b/src/json_utils.c new file mode 100644 index 0000000..f7e2436 --- /dev/null +++ b/src/json_utils.c @@ -0,0 +1,44 @@ +#include <stdio.h> +#include <string.h> + +#include "debug.h" +#include "json_utils.h" + +char *_json_obj_get_string(json_object *j, const char *key) +{ + json_object *t; + + if (j == NULL) + return NULL; + + if (json_object_object_get_ex(j, key, &t)) { + char *str = strdup(json_object_get_string(t)); + return str; + } + + dbg("|%s| not found", key); + + return NULL; +} + +int _json_obj_get_int(json_object *j, const char *key) +{ + json_object *t; + int ret = 0; + + if (j == NULL) + return 0; + + if (json_object_object_get_ex(j, key, &t)) + ret = json_object_get_int(t); + + return ret; +} + +void json_safe_put(json_object *j) +{ + if (j != NULL) { + json_object_put(j); + j = NULL; + } +} diff --git a/src/json_utils.h b/src/json_utils.h new file mode 100644 index 0000000..ee26592 --- /dev/null +++ b/src/json_utils.h @@ -0,0 +1,11 @@ +#ifndef JSON_UTILS_H +#define JSON_UTILS_H + +#include <json-c/json.h> + + +char *_json_obj_get_string(json_object *j, const char *key); +int _json_obj_get_int(json_object *j, const char *key); +void json_safe_put(json_object *j); + +#endif /* JSON_UTILS_H */ diff --git a/src/main.c b/src/main.c index d89674b..2937843 100644 --- a/src/main.c +++ b/src/main.c @@ -1,10 +1,110 @@ -#include "topoubus.h" -#include <syslog.h> +/* + * main.c - topologyd main + * + * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved. + * + * See LICENSE file for license terms. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> + +#include "debug.h" + +extern int topologyd_start(void); +extern int topologyd_stop(void); + +const char *ubus_socket = NULL; +const char *pidfile_path = NULL; +int refresh_int; +bool syslogging = false; +bool daemonize = true; + +void do_daemonize() +{ + char buf[128] = {0}; + int flags; + int f; + + if (daemonize) { + info("daemonizing ...\n"); + daemon(0,0); + } + + pidfile_path = "/var/run/topologyd.pid"; + f = open(pidfile_path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + if (f) { + flags = fcntl(f, F_GETFD); + if (flags != -1) { + flags |= FD_CLOEXEC; + fcntl(f, F_SETFD, flags); + } + if (lockf(f, F_TLOCK, 0) < 0) { + fprintf(stderr, "File '%s' exists. Aborting...\n", + pidfile_path); + exit(-1); + } + ftruncate(f,0); + snprintf(buf, sizeof(buf), "%ld\n", (long)getpid()); + write(f, buf, strlen(buf)); + } +} + +void usage(char *prog) +{ + fprintf(stderr, "Usage: %s [options]\n", prog); + fprintf(stderr, "\n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, " -s <socket path> ubus socket\n"); + fprintf(stderr, " -d, debug mode; i.e. don't daemonize\n"); + fprintf(stderr, " -l, log to syslog\n"); + fprintf(stderr, " -p <pidfile> pid file path\n"); + fprintf(stderr, " -t refresh interval in seconds\n"); + fprintf(stderr, "\n"); +} int main(int argc, char * argv[]) { - openlog("topo1905d", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); - init_topology(); - closelog(); + int ch; + + while ((ch = getopt(argc, argv, "hlt:ds:p:")) != -1) { + switch (ch) { + case 's': + ubus_socket = optarg; + break; + case 't': + refresh_int = atoi(optarg); + break; + case 'l': + syslogging = true; + break; + case 'd': + daemonize = false; + break; + case 'p': + pidfile_path = optarg; + break; + case 'h': + usage(argv[0]); + exit(0); + default: + break; + } + } + + if (daemonize) + syslogging = true; + + do_daemonize(); + start_logging(argv[0]); + + topologyd_start(); + + stop_logging(); + return 0; } diff --git a/src/nodes.c b/src/nodes.c new file mode 100644 index 0000000..72e287d --- /dev/null +++ b/src/nodes.c @@ -0,0 +1,110 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <time.h> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <net/if_arp.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <libubox/list.h> +#include <libubox/uloop.h> +#include <libubus.h> + +#include <easy/easy.h> +#include "debug.h" +#include "hlist.h" +#include "topologyd.h" + + +void node_destroy(struct node *n) +{ + free(n); +} + +struct node *node_create(uint8_t *hwaddr) +{ + struct node *n; + + n = calloc(1, sizeof(struct node)); + if (!n) { + warn("OOM: Node alloc failed!\n"); + return NULL; + } + + memcpy(n->hwaddr, hwaddr, 6); + + return n; +} + +struct node *node_lookup(struct hlist_head *table, uint8_t *hwaddr) +{ + int hidx = node_hash(hwaddr); + struct node *n; + + if (hwaddr_is_zero(hwaddr)) + return NULL; + + hlist_for_each_entry(n, &table[hidx], hlist) { + if (!memcmp(hwaddr, n->hwaddr, 6)) + return n; + } + + return NULL; +} + +int node_del(struct hlist_head *table, uint8_t *hwaddr) +{ + int hidx = node_hash(hwaddr); + struct node *n; + + n = node_lookup(table, hwaddr); + if (!n) + return -1; + + hlist_del(&n->hlist, &table[hidx]); + dbg("Node " MACFMT " removed from topology\n", MAC2STR(n->hwaddr)); + + node_destroy(n); + return 0; +} + +struct node *node_add(struct hlist_head *table, uint8_t *hwaddr) +{ + struct node *n; + + n = node_lookup(table, hwaddr); + if (n) { + dbg("Node " MACFMT " already in topology\n", MAC2STR(hwaddr)); + return n; + } + + n = node_create(hwaddr); + if (n) { + int hidx = node_hash(hwaddr); + + hlist_add_head(&n->hlist, &table[hidx]); + dbg("Node " MACFMT " added to topology\n", MAC2STR(hwaddr)); + } + + return n; +} + +void node_print_all(struct hlist_head *table) +{ + struct node *n; + int i; + + dbg("Nodes:\n"); + for (i = 0; i < NODE_HTABLE_SIZE; i++) { + if (hlist_empty(&table[i])) + continue; + + hlist_for_each_entry(n, &table[i], hlist) { + dbg("Node: " MACFMT "\n", MAC2STR(n->hwaddr)); + } + } +} diff --git a/src/nodes.h b/src/nodes.h new file mode 100644 index 0000000..59ca558 --- /dev/null +++ b/src/nodes.h @@ -0,0 +1,17 @@ + +#ifndef NODES_H +#define NODES_H + +#include <stdint.h> +#include "hlist.h" + + +struct node *node_create(uint8_t *hwaddr); +void node_free(struct node *n); + +struct node *node_add(struct hlist_head *table, uint8_t *hwaddr); +int node_del(struct hlist_head *table, uint8_t *hwaddr); +struct node *node_lookup(struct hlist_head *table, uint8_t *hwaddr); +void node_print_all(struct hlist_head *table); + +#endif /* NODES_H */ diff --git a/src/topo_ieee1905.c b/src/topo_ieee1905.c new file mode 100644 index 0000000..b9a9e8b --- /dev/null +++ b/src/topo_ieee1905.c @@ -0,0 +1,196 @@ +/* + * topo_ieee1905.c - topology for ieee1905 multiap network + * + * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved. + * + * See LICENSE file for license related information. + * + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdbool.h> +#include <errno.h> + +#include <libubox/uloop.h> +#include <libubus.h> + +#include <easy/easy.h> + +#include "debug.h" +#include "topologyd.h" +#include "nodes.h" + + +static int topologyd_copy_update_node(struct node *dest, struct node *src) +{ + if (dest == NULL || src == NULL) + return -1; + + dest->nbr_num = src->nbr_num; + dest->non1905_nbr_num = src->non1905_nbr_num; + + memset(dest->nbrlist, 0, sizeof(dest->nbrlist)); + memset(dest->non1905_nbrlist, 0, sizeof(dest->non1905_nbrlist)); + + + memcpy(dest->nbrlist, src->nbrlist, 6 * src->nbr_num); + memcpy(dest->non1905_nbrlist, src->non1905_nbrlist, + 6 * src->non1905_nbr_num); + + time(&dest->last_recv); + + return 0; +} + +static void topologyd_node_expired(struct uloop_timeout *t) +{ + struct node *p = container_of(t, struct node, validity_timer); + struct topologyd_private *priv = p->priv; + + if (priv) { + node_del(priv->topo.node_htable, p->hwaddr); + } +} + +int topologyd_node_add(struct topologyd_private *priv, struct node *node) +{ + struct node *p = NULL; + + + if (!node || !priv) + return -1; + + if (priv->topo.num_nodes >= TOPOLOGY_NODE_MAX) + return -1; + + if (!memcmp(node->hwaddr, priv->ieee1905_macaddr, 6)) { + p = &priv->selfnode; + topologyd_copy_update_node(p, node); + return 0; + } + + /* Add node if not present in topology. + * + * In case the node is present, update the node's values + * and the timestamp. + */ + p = node_lookup(priv->topo.node_htable, node->hwaddr); + if (!p) { + p = node_add(priv->topo.node_htable, node->hwaddr); + topologyd_copy_update_node(p, node); + + p->validity_timer.cb = topologyd_node_expired; + p->priv = priv; + priv->topo.num_nodes++; + } else { + topologyd_copy_update_node(p, node); + } + + /* reset validity timer for the node */ + uloop_timeout_set(&p->validity_timer, 180 * 1000); + + return 0; +} + +#if 0 +//Here we need to check if the node is a stale node and no response +//has been received for more than TOPOLOGY_VALIDITY +void check_node_validity() +{ + int i =0, j=0; + double diff_t; + time_t curr_time ; + time(&curr_time); + for (i = 0; i < gs_topotree.num_nodes; i++) { + diff_t = difftime(curr_time, gs_topotree.node[i].last_recv); + if (diff_t > TOPOLOGY_VALIDITY) { + //Here we need to delete the node + DEBUG("Deleting the node in index [%d] difftime[%f] ", i, diff_t); + for( j = i; j < gs_topotree.num_nodes -1 ; j++) { + topologyd_copy_update_node(&(gs_topotree.node[j]), &(gs_topotree.node[j+1])); + } + gs_topotree.num_nodes = gs_topotree.num_nodes- 1; + } + } + //Here we may have deleted the node so get self node interfaces + //updated + //get_interface_neighbors(NULL); + topologyd_send_ieee1905_topology_query(priv, NULL); + + return; +} +#endif + +/* Build full topology tree using a dumb but effective algo. + * It uses ieee1905 topology query to probe the neighbor nodes. + * + * Assumption: all nodes keep up-to-date list of their immediate neighbors. + * + * At any node 'P' in the network - + * + * Intial state: + * Nbr(P) = {N0,..Nn} <== immediate neighbors of P. + * G{P, N0,..Nn} <== graph of all known nodes at P. + * + * Step 1: + * for all Ni in G: + * Send Topology Request to Ni. + * + * Step 2: + * Read Topology Response from Ni. + * if Nbr(Ni) is not in G: + * Insert Nbr(Ni) in G + * + * Step 3: + * Repeat Step 1-2 until no new Nbr(Ni) can be inserted in G. + * + */ +void topologyd_algo_run(struct topologyd_private *priv) +{ + struct node *p; + int i, j; + + if (priv->algo_running) + return; + + dbg("\n======Building Topology======\n"); + + priv->algo_running = true; + + if (priv->topo.num_nodes == 0) { + /* send query to own neighbors */ + p = &priv->selfnode; + + if (hwaddr_is_zero(p->hwaddr)) + topologyd_send_ieee1905_topology_query(priv, NULL); + + dbg("Processing " MACFMT " AL\n", MAC2STR(p->hwaddr)); + + for (j = 0; j < p->nbr_num; j++) { + dbg("sending req to " MACFMT "\n", MAC2STR(p->nbrlist[j])); + topologyd_send_ieee1905_topology_query(priv, p->nbrlist[j]); + } + } + + for (i = 0; i < NODE_HTABLE_SIZE; i++) { + if (hlist_empty(&priv->topo.node_htable[i])) + continue; + + hlist_for_each_entry(p, &priv->topo.node_htable[i], hlist) { + + if (hwaddr_is_zero(p->hwaddr)) // TODO: unlikely.. + continue; + + for (j = 0; j < p->nbr_num; j++) { + dbg("sending req to " MACFMT "\n", MAC2STR(p->nbrlist[j])); + topologyd_send_ieee1905_topology_query(priv, p->nbrlist[j]); + } + } + } + + priv->algo_running = false; + + dbg("\n====== Done Building Topology======\n"); +} diff --git a/src/topologyd.c b/src/topologyd.c new file mode 100644 index 0000000..6ebad98 --- /dev/null +++ b/src/topologyd.c @@ -0,0 +1,558 @@ +/* + * topologyd.c - topology for multiap network ubus interface + * + * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved. + * + * See LICENSE file for license related information. + * + */ +#include <stdbool.h> +#include <pthread.h> +#include <json-c/json.h> +#include <libubox/blobmsg.h> +#include <libubox/blobmsg_json.h> +#include <libubox/uloop.h> +#include <libubus.h> + +#include <easy/easy.h> +#include <map1905/map2.h> + +#include "debug.h" +#include "topologyd.h" +#include "config.h" +#include "json_utils.h" + +static int signal_pending; +extern int refresh_int; +extern const char *ubus_socket; + +static void topologyd_sighandler(int sig) +{ + signal_pending = sig; +} + +static void ieee1905_info_response_cb(struct ubus_request *req, + int mtype, struct blob_attr *msg) +{ + struct topologyd_private *p; + json_object *jroot = NULL; + char *mac_str; + char *str; + + if (!msg || !req->priv) + return; + + p = (struct topologyd_private *)req->priv; + + str = blobmsg_format_json_indent(msg, true, -1); + if (str) { + jroot = json_tokener_parse(str); + free(str); + } + + if (jroot) { + //FIXME: "ieee1905id" -> "id" + mac_str = _json_obj_get_string(jroot, "ieee1905id"); + if (mac_str) { + hwaddr_aton(mac_str, p->ieee1905_macaddr); + free(mac_str); + } + + json_safe_put(jroot); + } +} + +int topologyd_get_ieee1905_macaddr(struct topologyd_private *p) +{ + struct blob_buf bb = { 0 }; + int ret = 0; + + blob_buf_init(&bb, 0); + ret = ubus_invoke(p->ctx, p->ieee1905, "info", bb.head, + ieee1905_info_response_cb, p, 1000); + if (ret) + err("Failed to get ieee1905 info\n"); + + blob_buf_free(&bb); + + return ret; +} + +int topologyd_send_ieee1905_topology_query(struct topologyd_private *p, + uint8_t *dest) +{ + char dest_macstr[18] = { 0 }; + struct blob_buf bb = { 0 }; + int ret = 0; + + + blob_buf_init(&bb, 0); + if (dest) { + hwaddr_ntoa(dest, dest_macstr); + blobmsg_add_string(&bb, "remote_mac", dest_macstr); + } + + ret = ubus_invoke(p->ctx, p->ieee1905, "query_topology", bb.head, + NULL, NULL, 1000); + if (ret) + err("Failed to send ieee1905 topology query\n"); + + + blob_buf_free(&bb); + + return ret; +} + +void topologyd_event_handler(struct ubus_context *ctx, + struct ubus_event_handler *ev, const char *type, + struct blob_attr *msg) +{ + char *str; + int i, j; + struct node n = { 0 }; + struct cmdu_cstruct *cstruct; + struct topologyd_private *priv = + container_of(ev, struct topologyd_private, ev); + + if (!msg) + return; + + + str = blobmsg_format_json(msg, true); + if (str == NULL) + return; + + cstruct = map_get_structs(str); // TODO: check progress ? + if (cstruct == NULL) { + free(str); + return; + } + // We get the json_object now str can be freed + free(str); + + // topology response is only required to build the topology tree + if (cstruct->message_type != CMDU_TYPE_TOPOLOGY_RESPONSE) { + map_free_cmdu_cstruct(cstruct); + return; + } + + for (i = 0; i < cstruct->nbr_tlv_cstructs; i++) { + switch (*cstruct->tlv_cstruct_list[i]) { + case TLV_TYPE_DEVICE_INFORMATION_TYPE: + { + struct tlv_device_info *tlv = + (struct tlv_device_info *) cstruct->tlv_cstruct_list[i]; + + memcpy(&n.hwaddr, &tlv->al_mac_address, 6); + } + break; + case TLV_TYPE_NEIGHBOR_DEVICE_LIST: + { + struct tlv_neighbor_device *tlv = + (struct tlv_neighbor_device *) cstruct->tlv_cstruct_list[i]; + + n.nbr_num = tlv->neighbors_nr; + for (j = 0; j < n.nbr_num; j++) { + memcpy(n.nbrlist[j], &tlv->neighbors[j].mac_address, 6); + } + } + break; + case TLV_TYPE_NON_1905_NEIGHBOR_DEVICE_LIST: + { + struct tlv_non1905_neighbor *tlv = + (struct tlv_non1905_neighbor *) cstruct->tlv_cstruct_list[i]; + + n.non1905_nbr_num = tlv->non_1905_neighbors_nr; + for (j = 0; j < n.non1905_nbr_num; j++) { + memcpy(n.non1905_nbrlist[j], &tlv->non_1905_neighbors[j].mac_address, 6); + } + } + break; + case TLV_TYPE_DEVICE_BRIDGING_CAPABILITIES: + case MAP_TLV_SUPPORTED_SERVICE: + case MAP_TLV_AP_OPERATIONAL_BSS: + case MAP_TLV_ASSOCIATED_CLIENTS: + break; + } + } + + if (n.nbr_num || n.non1905_nbr_num) { + dbg("Updating Node" MACFMT " from topology response\n", + MAC2STR(n.hwaddr)); + topologyd_node_add(priv, &n); + } + + map_free_cmdu_cstruct(cstruct); +} + +static int topologyd_refresh(struct ubus_context *ctx, + struct ubus_object *obj, + struct ubus_request_data *req, + const char *method, + struct blob_attr *msg) +{ + struct topologyd_private *priv = + container_of(obj, struct topologyd_private, obj); + + if (!priv->algo_running) + topologyd_algo_run(priv); + + return 0; +} + +void topologyd_dump_tree(struct topologyd_private *priv, struct blob_buf *bb) +{ + void *nodes_array, *table, *nbr_array, *non1905_array = NULL; + char mac_str[18] = { 0x0 }; + struct node *p; + int i, j; + + /* Add details of own node first */ + p = &priv->selfnode; + hwaddr_ntoa(p->hwaddr, mac_str); + + table = blobmsg_open_table(bb, "self"); + blobmsg_add_string(bb, "ieee1905_macaddr", mac_str); + blobmsg_add_u32(bb, "num_neighbors", p->nbr_num); + + nbr_array = blobmsg_open_array(bb, "neighbors"); + for (j = 0; j < p->nbr_num; j++) { + hwaddr_ntoa(p->nbrlist[j], mac_str); + blobmsg_add_string(bb, NULL, mac_str); + } + blobmsg_close_array(bb, nbr_array); + + blobmsg_add_u32(bb, "num_non1905_neighbors", p->non1905_nbr_num); + non1905_array = blobmsg_open_array(bb, "non1905_neighbors"); + for (j = 0; j < p->non1905_nbr_num; j++) { + hwaddr_ntoa(p->non1905_nbrlist[j], mac_str); + blobmsg_add_string(bb, NULL, mac_str); + } + blobmsg_close_array(bb, non1905_array); + blobmsg_close_table(bb, table); + + nodes_array = blobmsg_open_array(bb, "nodes"); + for (i = 0; i < NODE_HTABLE_SIZE; i++) { + if (hlist_empty(&priv->topo.node_htable[i])) + continue; + + hlist_for_each_entry(p, &priv->topo.node_htable[i], hlist) { + + if (hwaddr_is_zero(p->hwaddr)) // TODO: unlikely.. + continue; + + table = blobmsg_open_table(bb, NULL); + + hwaddr_ntoa(p->hwaddr, mac_str); + + blobmsg_add_string(bb, "ieee1905_macaddr", mac_str); + blobmsg_add_u32(bb, "num_neighbors", p->nbr_num); + + nbr_array = blobmsg_open_array(bb, "neighbors"); + for (j = 0; j < p->nbr_num; j++) { + hwaddr_ntoa(p->nbrlist[j], mac_str); + blobmsg_add_string(bb, NULL, mac_str); + } + blobmsg_close_array(bb, nbr_array); + + blobmsg_add_u32(bb, "num_non1905_neighbors", p->non1905_nbr_num); + non1905_array = blobmsg_open_array(bb, "non1905_neighbors"); + for (j = 0; j < p->non1905_nbr_num; j++) { + hwaddr_ntoa(p->non1905_nbrlist[j], mac_str); + blobmsg_add_string(bb, NULL, mac_str); + } + blobmsg_close_array(bb, non1905_array); + blobmsg_close_table(bb, table); + } + } + blobmsg_close_array(bb, nodes_array); +} + +static int topologyd_dump(struct ubus_context *ctx, + struct ubus_object *obj, + struct ubus_request_data *req, + const char *method, + struct blob_attr *msg) +{ + struct blob_buf bb; + struct topologyd_private *priv = + container_of(obj, struct topologyd_private, obj); + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + + topologyd_dump_tree(priv, &bb); + + ubus_send_reply(ctx, req, bb.head); + blob_buf_free(&bb); + + return 0; +} + +void topologyd_dump_changelog(struct topologyd_private *priv, struct blob_buf *bb) +{ + struct topology_changelog *log; + char rpt_ifmacstr[18] = { 0 }; + char rpt_macstr[18] = { 0 }; + char nbr_macstr[18] = { 0 }; + void *a, *t; + int i; + + blobmsg_add_u32(bb, "num_changelog", priv->topo.num_changelog); + + a = blobmsg_open_array(bb, "changelog"); + for (i = 0; i < priv->topo.num_changelog; i++) { + log = &priv->topo.changelog[i]; + + t = blobmsg_open_table(bb, NULL); + + hwaddr_ntoa(log->rpt_macaddr, rpt_macstr); + blobmsg_add_string(bb, "reporter", rpt_macstr); + + hwaddr_ntoa(log->rpt_ifmacaddr, rpt_ifmacstr); + blobmsg_add_string(bb, "reporter_interface", rpt_ifmacstr); + + hwaddr_ntoa(log->nbr_macaddr, nbr_macstr); + blobmsg_add_string(bb, "neighbor", nbr_macstr); + + blobmsg_add_string(bb, "is1905_neighbor", + log->is1905_nbr ? "true" : "false"); + + blobmsg_close_table(bb, t); + } + blobmsg_close_array(bb, a); +} + +static int topologyd_changelog(struct ubus_context *ctx, + struct ubus_object *obj, + struct ubus_request_data *req, + const char *method, + struct blob_attr *msg) +{ + struct blob_buf bb; + struct topologyd_private *priv = + container_of(obj, struct topologyd_private, obj); + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + + topologyd_dump_changelog(priv, &bb); + + ubus_send_reply(ctx, req, bb.head); + blob_buf_free(&bb); + + return 0; +} + +static int topologyd_status(struct ubus_context *ctx, + struct ubus_object *obj, + struct ubus_request_data *req, + const char *method, + struct blob_attr *msg) +{ + struct blob_buf bb; + struct topologyd_private *priv = + container_of(obj, struct topologyd_private, obj); + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + + blobmsg_add_string(&bb, "status", priv->status == AVAILABLE ? + "available" : "incomplete"); + + ubus_send_reply(ctx, req, bb.head); + blob_buf_free(&bb); + + return 0; +} + +static void topologyd_periodic_refresh(struct uloop_timeout *t) +{ + struct topologyd_private *priv = + container_of(t, struct topologyd_private, refresh_timer); + + dbg("Refresh topology...\n"); + + topologyd_algo_run(priv); + + if (priv->refresh_int) + uloop_timeout_set(&priv->refresh_timer, priv->refresh_int * 1000); +} + +static void topologyd_start_heartbeat(struct uloop_timeout *t) +{ + struct topologyd_private *priv = + container_of(t, struct topologyd_private, heartbeat); + + if (!signal_pending) + uloop_timeout_set(&priv->heartbeat, 1 * 1000); + + switch(signal_pending) { + case SIGTERM: + case SIGINT: + //topologyd_exit(priv); + break; + case SIGHUP: + //topologyd_reload(priv); + break; + default: + break; + } +} + +static int topologyd_run(struct topologyd_private *priv) +{ + int ret; + + ret = topologyd_get_ieee1905_macaddr(priv); + ret |= topologyd_send_ieee1905_topology_query(priv, NULL); + + if (ret) { + err("Failed to run topologyd...\n"); + return -1; + } + + topologyd_start_heartbeat(&priv->heartbeat); + topologyd_periodic_refresh(&priv->refresh_timer); + + return 0; +} + +static uint32_t topologyd_get_ieee1905_object(struct topologyd_private *priv) +{ + uint32_t id; + int status; + + status = ubus_lookup_id(priv->ctx, IEEE1905_OBJECT, &id); + if (status != UBUS_STATUS_OK) { + err("object '%s' not present!\n", IEEE1905_OBJECT); + return OBJECT_INVALID; + } + + return id; +} + +int topologyd_publish_object(struct topologyd_private *priv, const char *objname) +{ + struct ubus_object *obj; + struct ubus_object_type *obj_type; + struct ubus_method *obj_methods; + struct ubus_method m[4] = { + UBUS_METHOD_NOARG("refresh", topologyd_refresh), + UBUS_METHOD_NOARG("status", topologyd_status), + UBUS_METHOD_NOARG("dump", topologyd_dump), + UBUS_METHOD_NOARG("changelog", topologyd_changelog), + }; + int num_methods = ARRAY_SIZE(m); + int ret; + + + obj = &priv->obj; + memset(obj, 0, sizeof(*obj)); + + obj_type = calloc(1, sizeof(struct ubus_object_type)); + if (!obj_type) + return -1; + + obj_methods = calloc(num_methods, sizeof(struct ubus_method)); + if (!obj_methods) { + free(obj_type); + return -1; + } + + obj->name = objname; + memcpy(obj_methods, m, num_methods * sizeof(struct ubus_method)); + obj->methods = obj_methods; + obj->n_methods = num_methods; + + obj_type->name = obj->name; + obj_type->n_methods = obj->n_methods; + obj_type->methods = obj->methods; + obj->type = obj_type; + + ret = ubus_add_object(priv->ctx, obj); + if (ret) { + fprintf(stderr, "Failed to add 'obj' err = %s\n", + ubus_strerror(ret)); + free(obj_methods); + free(obj_type); + + return ret; + } + + fprintf(stderr, "Added object '%s'\n", objname); + + return 0; +} + +int topologyd_start(void) +{ + struct topologyd_private *priv; + + signal_pending = 0; + set_sighandler(SIGINT, topologyd_sighandler); + set_sighandler(SIGTERM, topologyd_sighandler); + set_sighandler(SIGHUP, topologyd_sighandler); + set_sighandler(SIGPIPE, SIG_IGN); + + priv = calloc(1, sizeof(*priv)); + if (!priv) + return -ENOMEM; + + info("Starting topologyd..."); + + uloop_init(); + priv->ctx = ubus_connect(ubus_socket); + if (!priv->ctx) { + err("Failed to connect to ubus\n"); + free(priv); + return -1; + } + + ubus_add_uloop(priv->ctx); + + priv->ieee1905 = topologyd_get_ieee1905_object(priv); + if (priv->ieee1905 == OBJECT_INVALID) + goto out_and_exit; + + //topologyd_load_extras(); //TODO + + topologyd_config_defaults(&priv->config); + topologyd_config_user(&priv->config); + + priv->ev.cb = topologyd_event_handler; + ubus_register_event_handler(priv->ctx, &priv->ev, IEEE1905_EVENTS); + + priv->refresh_timer.cb = topologyd_periodic_refresh; + priv->heartbeat.cb = topologyd_start_heartbeat; + + if (!priv->config.enabled) { + info("topologyd not enabled.\n"); + } else { + topologyd_publish_object(priv, TOPOLOGY_OBJECT); + topologyd_run(priv); + } + + uloop_run(); + + ubus_unregister_event_handler(priv->ctx, &priv->ev); + //topologyd_remove_object(priv->ctx); //TODO +out_and_exit: + ubus_free(priv->ctx); + uloop_done(); + free(priv); + + return 0; +} + +void topologyd_stop(struct topologyd_private *priv) +{ + if (!priv) + exit(0); + + ubus_unregister_event_handler(priv->ctx, &priv->ev); + //topologyd_remove_object(priv->ctx); + ubus_free(priv->ctx); + uloop_done(); + free(priv); +} diff --git a/src/topologyd.h b/src/topologyd.h new file mode 100644 index 0000000..04987b6 --- /dev/null +++ b/src/topologyd.h @@ -0,0 +1,102 @@ +/* + * topologyd.h - topologyd header file + * + * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved. + * + * Author: anjan.chanda@iopsys.eu + * + */ +#ifndef TOPOLOGYD_H +#define TOPOLOGYD_H + +#include <time.h> +#include "hlist.h" + +#define IEEE1905_OBJECT "ieee1905" +#define IEEE1905_EVENTS "ieee1905*" +#define TOPOLOGY_OBJECT "topology" + +#define TOPOLOGY_CONFIG "topology" + + +#define TOPOLOGY_NODE_MAX 32 +#define TOPOLOGY_NEIGHBOR_MAX 32 +#define TOPOLOGY_VALIDITY 120 // 120 sec + +typedef uint32_t ieee1905_object_t; + +#define OBJECT_INVALID (uint32_t)-1 + +#define TOPOLOGY_DEPTH 16 /* max depth */ +#define TOPOLOGY_REFRESH_INT 120 /* default refresh interval in secs */ +#define TOPOLOGY_LOG_MAX 32 /* max entries in topology changelog */ + +struct node { + uint8_t hwaddr[6]; + void *priv; + struct hlist_node hlist; + uint32_t nbr_num; + time_t last_recv; + struct uloop_timeout validity_timer; + uint32_t non1905_nbr_num; + uint8_t nbrlist[TOPOLOGY_NEIGHBOR_MAX][6]; + uint8_t non1905_nbrlist[TOPOLOGY_NEIGHBOR_MAX][6]; +}; + +struct topology_changelog { + uint8_t rpt_macaddr[6]; + uint8_t rpt_ifmacaddr[6]; + enum { NBR_NODE_ADD, NBR_NODE_DEL } type; + bool is1905_nbr; + uint8_t nbr_macaddr[6]; + time_t timestamp; +}; + +#define NODE_HTABLE_SIZE 128 +#define node_hash(n) \ + ((n[0] ^ n[1] ^ n[2] ^ n[3] ^ n[4] ^ n[5]) % NODE_HTABLE_SIZE) + + +struct topology { + void *priv; + uint32_t state; + int32_t num_nodes; + uint32_t num_changelog; + struct topology_changelog changelog[TOPOLOGY_LOG_MAX]; + struct hlist_head node_htable[NODE_HTABLE_SIZE]; +}; + +struct topologyd_config { + bool enabled; + uint32_t depth; + uint32_t refresh_int; + uint32_t maxlog; +}; + +struct topologyd_private { + int debug; + uint32_t refresh_int; + bool algo_running; + enum { INCOMPLETE, AVAILABLE } status; + struct ubus_context *ctx; + struct ubus_event_handler ev; + struct uloop_timeout heartbeat; + struct uloop_timeout refresh_timer; + struct ubus_object obj; + struct topologyd_config config; + ieee1905_object_t ieee1905; + uint8_t ieee1905_macaddr[6]; + struct node selfnode; + struct topology topo; +}; + + +void topologyd_algo_run(struct topologyd_private *p); +int topologyd_node_add(struct topologyd_private *priv, struct node *n); + +int topologyd_get_ieee1905_macaddr(struct topologyd_private *p); +int topologyd_send_ieee1905_topology_query(struct topologyd_private *p, + uint8_t *dest); + + +#endif /* TOPOLOGYD_H */ diff --git a/src/topomap.c b/src/topomap.c deleted file mode 100644 index 136c0e1..0000000 --- a/src/topomap.c +++ /dev/null @@ -1,258 +0,0 @@ -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <stdbool.h> -#include <errno.h> - -#include "topomap.h" -#include "topoutils.h" - -static struct topo1905 gs_topotree; -static struct node1905 gs_selfnode; -static uint8_t gs_self_al_mac[6]; - -bool topomap_init() -{ - uint8_t *al = gs_self_al_mac; - get_al_mac(al); - get_interface_neighbors(NULL); - memset(&gs_topotree, 0, sizeof(struct topo1905)); - return true; -} - -static bool _copy_node1905(struct node1905 *dest, struct node1905 *src) -{ - uint8_t i; - - if (dest == NULL || src == NULL) - return false; - - //Here we memset the dest node first before copying - memset(dest,0, sizeof(struct node1905)); - - memcpy(dest->hwaddr, src->hwaddr, 6); - dest->nbr_num = src->nbr_num; - dest->non1905_nbr_num = src->non1905_nbr_num; - - for (i = 0; i < dest->nbr_num; i++) { - memcpy(dest->nbrlist[i], src->nbrlist[i], 6); - } - - for (i = 0; i < dest->non1905_nbr_num; i++) { - memcpy(dest->non1905_nbrlist[i], src->non1905_nbrlist[i], 6); - } - - return true; -} - -static bool topomap_node_present(uint8_t *almac, int *index) -{ - int i; - - for (i = 0; i < gs_topotree.num_nodes; i++) { - if (!memcmp(gs_topotree.node[i].hwaddr, almac, 6)) { - *index = i; - return true; - } - } - - return false; -} - -int topomap_node_add(struct node1905 *node) -{ - bool node_present = true; - int index =0; - struct node1905 *p = NULL; - - if (node == NULL) - return -1; - - if (gs_topotree.num_nodes >= NODE_MAX_NUM) - return -1; - - if (memcmp(node->hwaddr, gs_self_al_mac, 6) == 0) { - p = &gs_selfnode; - _copy_node1905(p, node); - time(&(p->last_recv)); - return 0; - } - // Add the node if already not present update the recv time - // In case the node is already present update the node values and the - // last recv time - node_present = topomap_node_present(node->hwaddr, &index); - if (node_present == false) { - p = &(gs_topotree.node[gs_topotree.num_nodes]); - _copy_node1905(p, node); - //As the node is newly added set the timestamp - time(&(p->last_recv)); - gs_topotree.num_nodes++; - } - else { - //As the node is already present get the index of the node - p = &(gs_topotree.node[index]); - _copy_node1905(p, node); - //Here we update the time at which the node was last received - time(&(p->last_recv)); - } - return 0; -} - - -//Here we need to check if the node is a stale node and no response -//has been received for more than TOPOLOGY_VALIDITY -void check_node_validity() -{ - int i =0, j=0; - double diff_t; - time_t curr_time ; - time(&curr_time); - for (i = 0; i < gs_topotree.num_nodes; i++) { - diff_t = difftime(curr_time, gs_topotree.node[i].last_recv); - if (diff_t > TOPOLOGY_VALIDITY) { - //Here we need to delete the node - DEBUG("Deleting the node in index [%d] difftime[%f] ", i, diff_t); - for( j = i; j < gs_topotree.num_nodes -1 ; j++) { - _copy_node1905(&(gs_topotree.node[j]), &(gs_topotree.node[j+1])); - } - gs_topotree.num_nodes = gs_topotree.num_nodes- 1; - } - } - //Here we may have deleted the node so get self node interfaces - //updated - get_interface_neighbors(NULL); - return; -} - -/* Build full topology tree using a dumb but effective algo. - * - * Assumption: all nodes keep up-to-date list of their immediate neighbors. - * - * At any node 'P' in the network - - * - * Intial state: - * Nbr(P) = {N0,..Nn} <== immediate neighbors of P. - * G{P, N0,..Nn} <== graph of all known nodes at P. - * - * Step 1: - * for all Ni in G: - * Send Topology Request to Ni. - * - * Step 2: - * Read Topology Response from Ni. - * if Nbr(Ni) is not in G: - * Insert Nbr(Ni) in G - * - * Step 3: - * Repeat Step 1-2 until no new Nbr(Ni) can be inserted in G. - * - */ -void topomap_build_thread() -{ - struct node1905 *p; - int i, j; - char addr[18] = {0}; - - DEBUG("\n======Building Topology Tree======\n"); - //Here we call a function first to check the stale node - check_node_validity(); - - if (gs_topotree.num_nodes == 0) { - // send query to own neighbors - p = &gs_selfnode; - - if (hwaddr_is_zero(p->hwaddr)) { - get_interface_neighbors(NULL); - } - - hwaddr_ntoa(p->hwaddr, addr); - DEBUG("Processing (%s) AL", addr); - - for (j = 0; j < p->nbr_num; j++) { - hwaddr_ntoa(p->nbrlist[j], addr); - DEBUG("sending req to (%s)", addr); - get_interface_neighbors(p->nbrlist[j]); - } - } - - for (i = 0; i < gs_topotree.num_nodes; i++) { - p = &gs_topotree.node[i]; - - if (hwaddr_is_zero(p->hwaddr)) - continue; - - hwaddr_ntoa(p->hwaddr, addr); - DEBUG("Processing (%s) AL", addr); - - for (j = 0; j < p->nbr_num; j++) { - hwaddr_ntoa(p->nbrlist[j], addr); - DEBUG("sending req to (%s)", addr); - get_interface_neighbors(p->nbrlist[j]); - } - } - - DEBUG("\n====== Done Building Topology Tree======\n"); -} - -void dump_topology_tree(struct blob_buf *bb) -{ - char mac_str[18] = { 0x0 }; - struct node1905 *p; - int i, j; - void *nodes_array, *table, *nbr_array, *non1905_array = NULL; - - // Add details of own node first - p = &gs_selfnode; - hwaddr_ntoa(p->hwaddr, mac_str); - - table = blobmsg_open_table(bb, "self"); - blobmsg_add_string(bb, "al_mac", mac_str); - blobmsg_add_u32(bb, "neighbors_nr", p->nbr_num); - - nbr_array = blobmsg_open_array(bb, "neighbors"); - for (j = 0; j < p->nbr_num; j++) { - hwaddr_ntoa(p->nbrlist[j], mac_str); - blobmsg_add_string(bb, NULL, mac_str); - } - blobmsg_close_array(bb, nbr_array); - - blobmsg_add_u32(bb, "non_1905_neighbors_nr", p->non1905_nbr_num); - non1905_array = blobmsg_open_array(bb, "non_1905_neighbors"); - for (j = 0; j < p->non1905_nbr_num; j++) { - hwaddr_ntoa(p->non1905_nbrlist[j], mac_str); - blobmsg_add_string(bb, NULL, mac_str); - } - blobmsg_close_array(bb, non1905_array); - blobmsg_close_table(bb, table); - - nodes_array = blobmsg_open_array(bb, "Nodes"); - for (i = 0; i < gs_topotree.num_nodes; i++) { - p = &gs_topotree.node[i]; - if (hwaddr_is_zero(p->hwaddr)) - continue; - - table = blobmsg_open_table(bb, NULL); - - hwaddr_ntoa(p->hwaddr, mac_str); - - blobmsg_add_string(bb, "al_mac", mac_str); - blobmsg_add_u32(bb, "neighbors_nr", p->nbr_num); - - nbr_array = blobmsg_open_array(bb, "neighbors"); - for (j = 0; j < p->nbr_num; j++) { - hwaddr_ntoa(p->nbrlist[j], mac_str); - blobmsg_add_string(bb, NULL, mac_str); - } - blobmsg_close_array(bb, nbr_array); - - blobmsg_add_u32(bb, "non_1905_neighbors_nr", p->non1905_nbr_num); - non1905_array = blobmsg_open_array(bb, "non_1905_neighbors"); - for (j = 0; j < p->non1905_nbr_num; j++) { - hwaddr_ntoa(p->non1905_nbrlist[j], mac_str); - blobmsg_add_string(bb, NULL, mac_str); - } - blobmsg_close_array(bb, non1905_array); - blobmsg_close_table(bb, table); - } - blobmsg_close_array(bb, nodes_array); -} diff --git a/src/topomap.h b/src/topomap.h deleted file mode 100644 index 2b1722d..0000000 --- a/src/topomap.h +++ /dev/null @@ -1,33 +0,0 @@ -#include "topoubus.h" -#include <libubox/blobmsg.h> -#include <time.h> - -#ifndef TOPOMAP_H -#define TOPOMAP_H - -#define NODE_MAX_NUM 32 -#define NEIGHBOR_MAX_NUM 32 -#define TOPOLOGY_VALIDITY 120 // 120 sec - -struct node1905 { - uint8_t hwaddr[6]; - uint32_t nbr_num; - time_t last_recv; - uint32_t non1905_nbr_num; - uint8_t nbrlist[NEIGHBOR_MAX_NUM][6]; - uint8_t non1905_nbrlist[NEIGHBOR_MAX_NUM][6]; -}; - -struct topo1905 { - uint32_t state; - int32_t num_nodes; - struct node1905 node[NODE_MAX_NUM]; -}; - -// Topology build thread function. For internal use. -void topomap_build_thread(); -bool topomap_init(); -int topomap_node_add(struct node1905 *node); -void dump_topology_tree(struct blob_buf *bb); - -#endif /* TOPOMAP_H */ diff --git a/src/topoubus.c b/src/topoubus.c deleted file mode 100644 index f283bc6..0000000 --- a/src/topoubus.c +++ /dev/null @@ -1,310 +0,0 @@ -#include "topoubus.h" -#include "topomap.h" -#include "topoutils.h" - -#include <stdbool.h> -#include <pthread.h> -#include <json-c/json.h> -#include <libubox/blobmsg.h> -#include <libubox/blobmsg_json.h> -#include <libubox/uloop.h> -#include <libubus.h> - -#include <map1905/map2.h> - -static void topology_schedule(); - - -static void al_mac_cb(struct ubus_request *req, - int mtype __attribute__((unused)), - struct blob_attr *msg) -{ - char *str; - uint8_t *al_mac; - - if (!msg) - return; - - al_mac = (uint8_t *) req->priv; - - if (al_mac == NULL) - return; - - str = blobmsg_format_json_indent(msg, true, -1); - if (str == NULL) - return; - - json_object *jroot = json_tokener_parse(str); - free(str); - - if (jroot == NULL) - return; - - char *mac_str = _json_obj_get_string(jroot, "ieee1905id"); - - if (mac_str) { - hwaddr_aton(mac_str, al_mac); - } - - free(mac_str); - json_safe_put(jroot); -} - -int get_al_mac(uint8_t *al_mac) -{ - int ret = 0; - unsigned int id; - struct ubus_context *ctx = NULL; - struct blob_buf bb; - - ctx = ubus_connect(NULL); - if (!ctx) { - ERROR("ubus connect failed\n"); - return -1; - } - - if (UBUS_STATUS_OK != ubus_lookup_id(ctx, GET_TOPOLOGY_OBJECT, &id)) { - ERROR("lookup Object %s failed\n", GET_TOPOLOGY_OBJECT); - return -1; - } - - - memset(&bb, 0, sizeof(struct blob_buf)); - blob_buf_init(&bb, 0); - - ret = ubus_invoke(ctx, id, "info", bb.head, al_mac_cb, al_mac, 1000); - if (ret) { - ERROR("Failed to get ieee1905 topology\n"); - } - - blob_buf_free(&bb); - ubus_free(ctx); - return ret; -} - -int get_interface_neighbors(uint8_t *dmac) -{ - int ret = 0; - unsigned int id; - char macstr[18] = {0x0}; - struct ubus_context *ctx = NULL; - struct blob_buf bb; - - ctx = ubus_connect(NULL); - if (!ctx) { - ERROR("ubus connect failed\n"); - return -1; - } - - if (UBUS_STATUS_OK != ubus_lookup_id(ctx, GET_TOPOLOGY_OBJECT, &id)) { - ERROR("lookup Object %s failed\n", GET_TOPOLOGY_OBJECT); - return -1; - } - - - memset(&bb, 0, sizeof(struct blob_buf)); - blob_buf_init(&bb, 0); - - if (dmac) { - hwaddr_ntoa(dmac, macstr); - blobmsg_add_string(&bb, "remote_mac", macstr); - } - - ret = ubus_invoke(ctx, id, GET_TOPOLOGY, bb.head, NULL, NULL, 1000); - if (ret) { - ERROR("Failed to get ieee1905 topology\n"); - } - - blob_buf_free(&bb); - ubus_free(ctx); - return ret; -} - -void ieee1905_event_handler(struct ubus_context *ctx, - struct ubus_event_handler *ev, - const char *type, struct blob_attr *msg) -{ - char *str; - int i, j; - struct node1905 node; - struct cmdu_cstruct *cstruct; - - if (!msg) - return; - - memset(&node, 0, sizeof(struct node1905)); - - str = blobmsg_format_json(msg, true); - if (str == NULL) - return; - - cstruct = map_get_structs(str); - - if (cstruct == NULL) { - free(str); - return; - } - // We get the json_object now str can be freed - free(str); - - // topology response is only required to build the topology tree - if (cstruct->message_type != CMDU_TYPE_TOPOLOGY_RESPONSE) { - map_free_cmdu_cstruct(cstruct); - return; - } - - for (i = 0; i < cstruct->nbr_tlv_cstructs; i++) { - switch (*cstruct->tlv_cstruct_list[i]) { - case TLV_TYPE_DEVICE_INFORMATION_TYPE: - { - struct tlv_device_info *tlv = - (struct tlv_device_info *) cstruct->tlv_cstruct_list[i]; - - memcpy(&node.hwaddr, &tlv->al_mac_address, 6); - } - break; - case TLV_TYPE_NEIGHBOR_DEVICE_LIST: - { - struct tlv_neighbor_device *tlv = - (struct tlv_neighbor_device *) cstruct->tlv_cstruct_list[i]; - - node.nbr_num = tlv->neighbors_nr; - for (j = 0; j < node.nbr_num; j++) { - memcpy(node.nbrlist[j], &tlv->neighbors[j].mac_address, 6); - } - } - break; - case TLV_TYPE_NON_1905_NEIGHBOR_DEVICE_LIST: - { - struct tlv_non1905_neighbor *tlv = - (struct tlv_non1905_neighbor *) cstruct->tlv_cstruct_list[i]; - - node.non1905_nbr_num = tlv->non_1905_neighbors_nr; - for (j = 0; j < node.non1905_nbr_num; j++) { - memcpy(node.non1905_nbrlist[j], &tlv->non_1905_neighbors[j].mac_address, 6); - } - } - break; - case TLV_TYPE_DEVICE_BRIDGING_CAPABILITIES: - case MAP_TLV_SUPPORTED_SERVICE: - case MAP_TLV_AP_OPERATIONAL_BSS: - case MAP_TLV_ASSOCIATED_CLIENTS: - break; - } - } - if (node.nbr_num || node.non1905_nbr_num) { - DEBUG("updating topology response \n"); - topomap_node_add(&node); - } - map_free_cmdu_cstruct(cstruct); -} - -static void topology_schedule_cb(struct uloop_timeout *timeout) -{ - DEBUG("Building topology tree \n"); - topomap_build_thread(); - uloop_timeout_set(timeout, TOPOLOGY_TIMEOUT); -} - -static void topology_schedule() -{ - struct uloop_timeout topo_scheduler; - - memset(&topo_scheduler, 0, sizeof(struct uloop_timeout)); - - topo_scheduler.cb = topology_schedule_cb; - uloop_timeout_set(&topo_scheduler, TOPOLOGY_TIMEOUT); -} - -static int topo1905_build_tree(struct ubus_context *ectx, struct ubus_object *obj __attribute__ ((unused)), - struct ubus_request_data *req, const char *method __attribute__ ((unused)), - struct blob_attr *msg __attribute__ ((unused))) -{ - struct blob_buf bb; - - memset(&bb, 0, sizeof(struct blob_buf)); - blob_buf_init(&bb, 0); - - topomap_build_thread(); - - blobmsg_add_u8(&bb, "status", true); - ubus_send_reply(ectx, req, bb.head); - blob_buf_free(&bb); - return 0; -} - -static int topo1905_dump_tree(struct ubus_context *ectx, struct ubus_object *obj __attribute__ ((unused)), - struct ubus_request_data *req, const char *method __attribute__ ((unused)), - struct blob_attr *msg __attribute__ ((unused))) -{ - struct blob_buf bb; - - memset(&bb, 0, sizeof(struct blob_buf)); - blob_buf_init(&bb, 0); - - dump_topology_tree(&bb); - - ubus_send_reply(ectx, req, bb.head); - blob_buf_free(&bb); - return 0; -} - -static const struct ubus_method topo1905_methods[] = { - UBUS_METHOD_NOARG("build_tree", topo1905_build_tree), - UBUS_METHOD_NOARG("dump_tree", topo1905_dump_tree), -}; - -static struct ubus_object_type topo1905_object_type = - UBUS_OBJECT_TYPE("topo1905", topo1905_methods); - -static struct ubus_object topo1905_object = { - .name = "topo1905", - .type = &topo1905_object_type, - .methods = topo1905_methods, - .n_methods = ARRAY_SIZE(topo1905_methods), -}; - -int init_topology() -{ - int ret; - struct ubus_event_handler listener; - struct ubus_context *ectx; - - uloop_init(); - ectx = ubus_connect(NULL); - if (!ectx) { - ERROR("ubus connect failed\n"); - return -1; - } - - ubus_add_uloop(ectx); - - memset(&listener, 0, sizeof(struct ubus_event_handler)); - listener.cb = ieee1905_event_handler; - - ret = ubus_register_event_handler(ectx, &listener, IEEE1905_EVENT); - if (0 != ret) { - ERROR("ieee1905 event failed(%s)!\n", ubus_strerror(ret)); - return -1; - } - - ret = ubus_add_object(ectx, &topo1905_object); - if (ret) { - fprintf(stderr, "Failed to add object: %s\n", - ubus_strerror(ret)); - - return -1; - } - - if (topomap_init() == false) { - ERROR("Topology init failed"); - return -1; - } - - topology_schedule(); - uloop_run(); - ubus_free(ectx); - uloop_done(); - - return 0; -} diff --git a/src/topoubus.h b/src/topoubus.h deleted file mode 100644 index 4c6596a..0000000 --- a/src/topoubus.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef TOPOUBUS_H -#define TOPOUBUS_H - -#include <libubus.h> - -#define IEEE1905_EVENT "ieee1905.event" -#define GET_TOPOLOGY_OBJECT "ieee1905" -#define GET_TOPOLOGY "topology" -#define TOPOLOGY_TIMEOUT 120000 // 120 sec - -#define MAX_RESPONSE_NUM 32 -#define TLV_NAME_LEN 128 -#define MAX_NBRS 32 -#define NAME_LEN 64 -#define MAX_MID 32 - -int init_topology(); -int get_interface_neighbors(uint8_t *dmac); -int get_al_mac(uint8_t *al_mac); - -#endif diff --git a/src/topoutils.c b/src/topoutils.c deleted file mode 100644 index debb893..0000000 --- a/src/topoutils.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "topoutils.h" - -char* _json_obj_get_string(json_object *j, const char *key) -{ - if(j == NULL) - return NULL; - - json_object *t; - if(json_object_object_get_ex(j, key, &t)) { - char *str = strdup(json_object_get_string(t)); - return(str); - } - DEBUG("|%s| not found", key); - return NULL; -} - -int _json_obj_get_int(json_object *j, const char *key) -{ - int ret = 0; - if(j == NULL) - return 0; - - json_object *t; - if(json_object_object_get_ex(j, key, &t)) { - ret = json_object_get_int(t); - } - return(ret); -} - -void json_safe_put(json_object *j) { - if(j != NULL) { - json_object_put(j); - } - j = NULL; -} - diff --git a/src/topoutils.h b/src/topoutils.h deleted file mode 100644 index e87c0b0..0000000 --- a/src/topoutils.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef TOPOUTILS_H -#define TOPOUTILS_H - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> -#include <syslog.h> -#include <json-c/json.h> - -#include <easy/easy.h> -#include <stdbool.h> - -char* _json_obj_get_string(json_object *j, const char *key); -int _json_obj_get_int(json_object *j, const char *key); -void json_safe_put(json_object *j); -void print_info(const char *format, ...); - -#define DEBUG_ENABLED 0 -#define DEBUG(fmt, args...) \ -do { \ - if (DEBUG_ENABLED) \ - syslog(LOG_DEBUG, "[%s:%d] " fmt, __func__, __LINE__, ##args); \ -} while (0) - -#define INFO(fmt, args...) \ -do { \ - syslog(LOG_INFO, "[%s:%d] " fmt, __func__, __LINE__, ##args); \ -} while (0) - -#define ERROR(fmt, args...) \ -do { \ - syslog(LOG_ERR, "[%s:%d] " fmt, __func__, __LINE__, ##args); \ -} while (0) - -#endif -- GitLab