diff options
author | Dimitri Staessens <[email protected]> | 2019-07-25 12:50:46 +0200 |
---|---|---|
committer | Sander Vrijders <[email protected]> | 2019-07-29 19:36:45 +0200 |
commit | dae15c284248d49079ad5f8a3d8ff30e217f419e (patch) | |
tree | ea7942e940396c0c78304fef8b43fb25c5aebba8 /src/ipcpd/normal | |
parent | c9232acef855b51d1bc199a68c03c0695ac11192 (diff) | |
download | ouroboros-dae15c284248d49079ad5f8a3d8ff30e217f419e.tar.gz ouroboros-dae15c284248d49079ad5f8a3d8ff30e217f419e.zip |
build: Refactor normal to unicast
This completes the renaming of the normal IPCP to the unicast IPCP in
the sources, to get everything consistent with the documentation.
Signed-off-by: Dimitri Staessens <[email protected]>
Signed-off-by: Sander Vrijders <[email protected]>
Diffstat (limited to 'src/ipcpd/normal')
41 files changed, 0 insertions, 10036 deletions
diff --git a/src/ipcpd/normal/CMakeLists.txt b/src/ipcpd/normal/CMakeLists.txt deleted file mode 100644 index d1585395..00000000 --- a/src/ipcpd/normal/CMakeLists.txt +++ /dev/null @@ -1,69 +0,0 @@ -get_filename_component(CURRENT_SOURCE_PARENT_DIR - ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY) -get_filename_component(CURRENT_BINARY_PARENT_DIR - ${CMAKE_CURRENT_BINARY_DIR} DIRECTORY) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) - -include_directories(${CURRENT_SOURCE_PARENT_DIR}) -include_directories(${CURRENT_BINARY_PARENT_DIR}) - -include_directories(${CMAKE_SOURCE_DIR}/include) -include_directories(${CMAKE_BINARY_DIR}/include) - -set(IPCP_NORMAL_TARGET ipcpd-normal CACHE INTERNAL "") - -protobuf_generate_c(KAD_PROTO_SRCS KAD_PROTO_HDRS kademlia.proto) - -math(EXPR PFT_EXPR "1 << 12") -set(PFT_SIZE ${PFT_EXPR} CACHE STRING - "Size of the PDU forwarding table") -if (HAVE_FUSE) - set(IPCP_FLOW_STATS TRUE CACHE BOOL - "Enable flow statistics tracking in IPCP") - if (IPCP_FLOW_STATS) - message(STATUS "IPCP flow statistics enabled") - else () - message(STATUS "IPCP flow statistics disabled") - endif () -endif () - - -set(SOURCE_FILES - # Add source files here - addr_auth.c - connmgr.c - dht.c - dir.c - dt.c - enroll.c - fa.c - main.c - pff.c - routing.c - psched.c - # Add policies last - pol/alternate_pff.c - pol/flat.c - pol/link_state.c - pol/graph.c - pol/simple_pff.c - ) - -add_executable(ipcpd-normal ${SOURCE_FILES} ${IPCP_SOURCES} - ${KAD_PROTO_SRCS} ${LAYER_CONFIG_PROTO_SRCS}) -target_link_libraries(ipcpd-normal LINK_PUBLIC ouroboros-dev) - -include(AddCompileFlags) -if (CMAKE_BUILD_TYPE MATCHES "Debug*") - add_compile_flags(ipcpd-normal -DCONFIG_OUROBOROS_DEBUG) -endif () - -install(TARGETS ipcpd-normal RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}) - -add_subdirectory(pol/tests) - -if (NOT GNU) - add_subdirectory(tests) -endif () diff --git a/src/ipcpd/normal/addr_auth.c b/src/ipcpd/normal/addr_auth.c deleted file mode 100644 index 50c56055..00000000 --- a/src/ipcpd/normal/addr_auth.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Address authority - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#define OUROBOROS_PREFIX "addr_auth" - -#include <ouroboros/logs.h> - -#include "addr_auth.h" -#include "pol-addr-auth-ops.h" -#include "pol/flat.h" - -#include <stdlib.h> - -struct pol_addr_auth_ops * ops; - -int addr_auth_init(enum pol_addr_auth type, - const void * info) -{ - switch (type) { - case ADDR_AUTH_FLAT_RANDOM: - ops = &flat_ops; - break; - default: - log_err("Unknown address authority type."); - return -1; - } - - return ops->init(info); -} - -uint64_t addr_auth_address(void) -{ - return ops->address(); -} - -int addr_auth_fini(void) -{ - return ops->fini(); -} diff --git a/src/ipcpd/normal/addr_auth.h b/src/ipcpd/normal/addr_auth.h deleted file mode 100644 index e205b50a..00000000 --- a/src/ipcpd/normal/addr_auth.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Address authority - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_ADDR_AUTH_H -#define OUROBOROS_IPCPD_NORMAL_ADDR_AUTH_H - -#include <ouroboros/ipcp.h> - -#include <stdint.h> - -int addr_auth_init(enum pol_addr_auth type, - const void * info); - -int addr_auth_fini(void); - -uint64_t addr_auth_address(void); - -#endif /* OUROBOROS_IPCPD_NORMAL_ADDR_AUTH_H */ diff --git a/src/ipcpd/normal/comp.h b/src/ipcpd/normal/comp.h deleted file mode 100644 index 029c2d7a..00000000 --- a/src/ipcpd/normal/comp.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Components for the normal IPC process - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_COMP_H -#define OUROBOROS_IPCPD_NORMAL_COMP_H - -#include <ouroboros/cacep.h> - -#include "dt.h" - -#define DST_MAX_STRLEN 64 - -enum comp_id { - COMPID_DT = 0, - COMPID_ENROLL, - COMPID_MGMT, - COMPID_MAX -}; - -struct conn { - struct conn_info conn_info; - struct { - char dst[DST_MAX_STRLEN + 1]; - int fd; - qosspec_t qs; - } flow_info; -}; - -#endif /* OUROBOROS_IPCPD_NORMAL_COMP_H */ diff --git a/src/ipcpd/normal/connmgr.c b/src/ipcpd/normal/connmgr.c deleted file mode 100644 index 7c1280c3..00000000 --- a/src/ipcpd/normal/connmgr.c +++ /dev/null @@ -1,525 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Handles connections between components - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#if defined(__linux__) || defined(__CYGWIN__) -#define _DEFAULT_SOURCE -#else -#define _POSIX_C_SOURCE 200112L -#endif - -#define OUROBOROS_PREFIX "connection-manager" - -#include <ouroboros/dev.h> -#include <ouroboros/cacep.h> -#include <ouroboros/errno.h> -#include <ouroboros/list.h> -#include <ouroboros/logs.h> -#include <ouroboros/notifier.h> - -#include "comp.h" -#include "connmgr.h" -#include "dir.h" -#include "enroll.h" -#include "ipcp.h" - -#include <pthread.h> -#include <string.h> -#include <stdlib.h> -#include <assert.h> - -enum connmgr_state { - CONNMGR_NULL = 0, - CONNMGR_INIT, - CONNMGR_RUNNING -}; - -struct conn_el { - struct list_head next; - struct conn conn; -}; - -struct comp { - struct conn_info info; - - struct list_head conns; - struct list_head pending; - - pthread_cond_t cond; - pthread_mutex_t lock; -}; - -struct { - struct comp comps[COMPID_MAX]; - enum connmgr_state state; - - pthread_t acceptor; -} connmgr; - -static int get_id_by_name(const char * name) -{ - enum comp_id i; - - for (i = 0; i < COMPID_MAX; ++i) - if (strcmp(name, connmgr.comps[i].info.comp_name) == 0) - return i; - - return -1; -} - -static int get_conn_by_fd(int fd, - enum comp_id id, - struct conn * conn) -{ - struct list_head * p; - - pthread_mutex_lock(&connmgr.comps[id].lock); - - list_for_each(p, &connmgr.comps[id].conns) { - struct conn_el * c = - list_entry(p, struct conn_el, next); - if (c->conn.flow_info.fd == fd) { - *conn = c->conn; - pthread_mutex_unlock(&connmgr.comps[id].lock); - return 0; - } - } - - pthread_mutex_unlock(&connmgr.comps[id].lock); - - return -1; -} - -static int add_comp_conn(enum comp_id id, - int fd, - qosspec_t qs, - struct conn_info * rcv_info) -{ - struct conn_el * el; - - el = malloc(sizeof(*el)); - if (el == NULL) { - log_err("Not enough memory."); - return -1; - } - - el->conn.conn_info = *rcv_info; - el->conn.flow_info.fd = fd; - el->conn.flow_info.qs = qs; - - pthread_mutex_lock(&connmgr.comps[id].lock); - - list_add(&el->next, &connmgr.comps[id].pending); - pthread_cond_signal(&connmgr.comps[id].cond); - - pthread_mutex_unlock(&connmgr.comps[id].lock); - - return 0; -} - -static void * flow_acceptor(void * o) -{ - int fd; - qosspec_t qs; - struct conn_info rcv_info; - struct conn_info fail_info; - - (void) o; - - memset(&fail_info, 0, sizeof(fail_info)); - - while (true) { - int id; - - fd = flow_accept(&qs, NULL); - if (fd < 0) { - if (fd != -EIRMD) - log_warn("Flow accept failed: %d", fd); - continue; - } - - if (cacep_rcv(fd, &rcv_info)) { - log_dbg("Error establishing application connection."); - flow_dealloc(fd); - continue; - } - - id = get_id_by_name(rcv_info.comp_name); - if (id < 0) { - log_dbg("Connection request for unknown component %s.", - rcv_info.comp_name); - cacep_snd(fd, &fail_info); - flow_dealloc(fd); - continue; - } - - assert(id < COMPID_MAX); - - if (cacep_snd(fd, &connmgr.comps[id].info)) { - log_dbg("Failed to respond to request."); - flow_dealloc(fd); - continue; - } - - if (add_comp_conn(id, fd, qs, &rcv_info)) { - log_dbg("Failed to add new connection."); - flow_dealloc(fd); - continue; - } - } - - return (void *) 0; -} - -static void handle_event(void * self, - int event, - const void * o) -{ - struct conn conn; - - (void) self; - - if (!(event == NOTIFY_DT_FLOW_UP || - event == NOTIFY_DT_FLOW_DOWN || - event == NOTIFY_DT_FLOW_DEALLOC)) - return; - - if (get_conn_by_fd(*((int *) o), COMPID_DT, &conn)) - return; - - switch (event) { - case NOTIFY_DT_FLOW_UP: - notifier_event(NOTIFY_DT_CONN_UP, &conn); - break; - case NOTIFY_DT_FLOW_DOWN: - notifier_event(NOTIFY_DT_CONN_DOWN, &conn); - break; - case NOTIFY_DT_FLOW_DEALLOC: - notifier_event(NOTIFY_DT_CONN_DEL, &conn); - break; - default: - break; - } -} - -int connmgr_init(void) -{ - connmgr.state = CONNMGR_INIT; - - if (notifier_reg(handle_event, NULL)) - return -1; - - return 0; -} - -void connmgr_fini(void) -{ - int i; - - notifier_unreg(handle_event); - - if (connmgr.state == CONNMGR_RUNNING) - pthread_join(connmgr.acceptor, NULL); - - for (i = 0; i < COMPID_MAX; ++i) - connmgr_comp_fini(i); -} - -int connmgr_start(void) -{ - if (pthread_create(&connmgr.acceptor, NULL, flow_acceptor, NULL)) - return -1; - - connmgr.state = CONNMGR_RUNNING; - - return 0; -} - -void connmgr_stop(void) -{ - if (connmgr.state == CONNMGR_RUNNING) - pthread_cancel(connmgr.acceptor); -} - -int connmgr_comp_init(enum comp_id id, - const struct conn_info * info) -{ - struct comp * comp; - - assert(id >= 0 && id < COMPID_MAX); - - comp = connmgr.comps + id; - - if (pthread_mutex_init(&comp->lock, NULL)) - return -1; - - if (pthread_cond_init(&comp->cond, NULL)) { - pthread_mutex_destroy(&comp->lock); - return -1; - } - - list_head_init(&comp->conns); - list_head_init(&comp->pending); - - memcpy(&connmgr.comps[id].info, info, sizeof(connmgr.comps[id].info)); - - return 0; -} - -void connmgr_comp_fini(enum comp_id id) -{ - struct list_head * p; - struct list_head * h; - struct comp * comp; - - assert(id >= 0 && id < COMPID_MAX); - - if (strlen(connmgr.comps[id].info.comp_name) == 0) - return; - - comp = connmgr.comps + id; - - pthread_mutex_lock(&comp->lock); - - list_for_each_safe(p, h, &comp->conns) { - struct conn_el * e = list_entry(p, struct conn_el, next); - list_del(&e->next); - free(e); - } - - list_for_each_safe(p, h, &comp->pending) { - struct conn_el * e = list_entry(p, struct conn_el, next); - list_del(&e->next); - free(e); - } - - pthread_mutex_unlock(&comp->lock); - - pthread_cond_destroy(&comp->cond); - pthread_mutex_destroy(&comp->lock); - - memset(&connmgr.comps[id].info, 0, sizeof(connmgr.comps[id].info)); -} - -int connmgr_ipcp_connect(const char * dst, - const char * component, - qosspec_t qs) -{ - struct conn_el * ce; - int id; - - assert(dst); - assert(component); - - ce = malloc(sizeof(*ce)); - if (ce == NULL) { - log_dbg("Out of memory."); - return -1; - } - - id = get_id_by_name(component); - if (id < 0) { - log_dbg("No such component: %s", component); - free(ce); - return -1; - } - - if (connmgr_alloc(id, dst, &qs, &ce->conn)) { - free(ce); - return -1; - } - - if (strlen(dst) > DST_MAX_STRLEN) { - log_warn("Truncating dst length for connection."); - memcpy(ce->conn.flow_info.dst, dst, DST_MAX_STRLEN); - ce->conn.flow_info.dst[DST_MAX_STRLEN] = '\0'; - } else { - strcpy(ce->conn.flow_info.dst, dst); - } - - pthread_mutex_lock(&connmgr.comps[id].lock); - - list_add(&ce->next, &connmgr.comps[id].conns); - - pthread_mutex_unlock(&connmgr.comps[id].lock); - - return 0; -} - -int connmgr_ipcp_disconnect(const char * dst, - const char * component) -{ - struct list_head * p; - struct list_head * h; - int id; - - assert(dst); - assert(component); - - id = get_id_by_name(component); - if (id < 0) - return -1; - - pthread_mutex_lock(&connmgr.comps[id].lock); - - list_for_each_safe(p,h, &connmgr.comps[id].conns) { - struct conn_el * el = list_entry(p, struct conn_el, next); - if (strcmp(el->conn.flow_info.dst, dst) == 0) { - int ret; - pthread_mutex_unlock(&connmgr.comps[id].lock); - list_del(&el->next); - ret = connmgr_dealloc(id, &el->conn); - free(el); - return ret; - } - } - - pthread_mutex_unlock(&connmgr.comps[id].lock); - - return 0; -} - -int connmgr_alloc(enum comp_id id, - const char * dst, - qosspec_t * qs, - struct conn * conn) -{ - assert(id >= 0 && id < COMPID_MAX); - assert(dst); - - conn->flow_info.fd = flow_alloc(dst, qs, NULL); - if (conn->flow_info.fd < 0) { - log_dbg("Failed to allocate flow to %s.", dst); - return -1; - } - - if (qs != NULL) - conn->flow_info.qs = *qs; - else - memset(&conn->flow_info.qs, 0, sizeof(conn->flow_info.qs)); - - log_dbg("Sending cacep info for protocol %s to fd %d.", - connmgr.comps[id].info.protocol, conn->flow_info.fd); - - if (cacep_snd(conn->flow_info.fd, &connmgr.comps[id].info)) { - log_dbg("Failed to create application connection."); - flow_dealloc(conn->flow_info.fd); - return -1; - } - - if (cacep_rcv(conn->flow_info.fd, &conn->conn_info)) { - log_dbg("Failed to connect to application."); - flow_dealloc(conn->flow_info.fd); - return -1; - } - - if (strcmp(connmgr.comps[id].info.protocol, conn->conn_info.protocol)) { - log_dbg("Unknown protocol (requested %s, got %s).", - connmgr.comps[id].info.protocol, - conn->conn_info.protocol); - flow_dealloc(conn->flow_info.fd); - return -1; - } - - if (connmgr.comps[id].info.pref_version != - conn->conn_info.pref_version) { - log_dbg("Unknown protocol version."); - flow_dealloc(conn->flow_info.fd); - return -1; - } - - if (connmgr.comps[id].info.pref_syntax != conn->conn_info.pref_syntax) { - log_dbg("Unknown protocol syntax."); - flow_dealloc(conn->flow_info.fd); - return -1; - } - - switch (id) { - case COMPID_DT: - notifier_event(NOTIFY_DT_CONN_ADD, conn); -#ifdef IPCP_CONN_WAIT_DIR - dir_wait_running(); -#endif - break; - case COMPID_MGMT: - notifier_event(NOTIFY_MGMT_CONN_ADD, conn); - break; - default: - break; - } - - return 0; -} - -int connmgr_dealloc(enum comp_id id, - struct conn * conn) -{ - switch (id) { - case COMPID_DT: - notifier_event(NOTIFY_DT_CONN_DEL, conn); - break; - case COMPID_MGMT: - notifier_event(NOTIFY_MGMT_CONN_DEL, conn); - break; - default: - break; - } - - return flow_dealloc(conn->flow_info.fd); -} - - -int connmgr_wait(enum comp_id id, - struct conn * conn) -{ - struct conn_el * el; - struct comp * comp; - - assert(id >= 0 && id < COMPID_MAX); - assert(conn); - - comp = connmgr.comps + id; - - pthread_mutex_lock(&comp->lock); - - pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock, - (void *) &comp->lock); - - while (list_is_empty(&comp->pending)) - pthread_cond_wait(&comp->cond, &comp->lock); - - pthread_cleanup_pop(false); - - el = list_first_entry((&comp->pending), struct conn_el, next); - if (el == NULL) { - pthread_mutex_unlock(&comp->lock); - return -1; - } - - *conn = el->conn; - - list_del(&el->next); - list_add(&el->next, &connmgr.comps[id].conns); - - pthread_mutex_unlock(&comp->lock); - - return 0; -} diff --git a/src/ipcpd/normal/connmgr.h b/src/ipcpd/normal/connmgr.h deleted file mode 100644 index 4f81ff9d..00000000 --- a/src/ipcpd/normal/connmgr.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Handles the different AP connections - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_CONNMGR_H -#define OUROBOROS_IPCPD_NORMAL_CONNMGR_H - -#include <ouroboros/cacep.h> -#include <ouroboros/qos.h> - -#include "comp.h" - -#define NOTIFY_DT_CONN_ADD 0x00D0 -#define NOTIFY_DT_CONN_DEL 0x00D1 -#define NOTIFY_DT_CONN_QOS 0x00D2 -#define NOTIFY_DT_CONN_UP 0x00D3 -#define NOTIFY_DT_CONN_DOWN 0x00D4 -#define NOTIFY_DT_FLOW_UP 0x00D5 -#define NOTIFY_DT_FLOW_DOWN 0x00D6 -#define NOTIFY_DT_FLOW_DEALLOC 0x00D7 - -#define NOTIFY_MGMT_CONN_ADD 0x00F0 -#define NOTIFY_MGMT_CONN_DEL 0x00F1 - -int connmgr_init(void); - -void connmgr_fini(void); - -int connmgr_start(void); - -void connmgr_stop(void); - -int connmgr_comp_init(enum comp_id id, - const struct conn_info * info); - -void connmgr_comp_fini(enum comp_id id); - -int connmgr_ipcp_connect(const char * dst, - const char * component, - qosspec_t qs); - -int connmgr_ipcp_disconnect(const char * dst, - const char * component); - -int connmgr_alloc(enum comp_id id, - const char * dst, - qosspec_t * qs, - struct conn * conn); - -int connmgr_dealloc(enum comp_id id, - struct conn * conn); - -int connmgr_wait(enum comp_id id, - struct conn * conn); - -#endif /* OUROBOROS_IPCPD_NORMAL_CONNMGR_H */ diff --git a/src/ipcpd/normal/dht.c b/src/ipcpd/normal/dht.c deleted file mode 100644 index f24a2c51..00000000 --- a/src/ipcpd/normal/dht.c +++ /dev/null @@ -1,2840 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Distributed Hash Table based on Kademlia - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * version 2.1 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#if defined(__linux__) || defined(__CYGWIN__) -#define _DEFAULT_SOURCE -#else -#define _POSIX_C_SOURCE 200112L -#endif - -#include "config.h" - -#define DHT "dht" -#define OUROBOROS_PREFIX DHT - -#include <ouroboros/hash.h> -#include <ouroboros/ipcp-dev.h> -#include <ouroboros/bitmap.h> -#include <ouroboros/errno.h> -#include <ouroboros/logs.h> -#include <ouroboros/list.h> -#include <ouroboros/notifier.h> -#include <ouroboros/random.h> -#include <ouroboros/time_utils.h> -#include <ouroboros/tpm.h> -#include <ouroboros/utils.h> - -#include "connmgr.h" -#include "dht.h" -#include "dt.h" - -#include <pthread.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <inttypes.h> -#include <limits.h> - -#include "kademlia.pb-c.h" -typedef KadMsg kad_msg_t; -typedef KadContactMsg kad_contact_msg_t; - -#ifndef CLOCK_REALTIME_COARSE -#define CLOCK_REALTIME_COARSE CLOCK_REALTIME -#endif - -#define DHT_MAX_REQS 2048 /* KAD recommends rnd(), bmp can be changed. */ -#define KAD_ALPHA 3 /* Parallel factor, proven optimal value. */ -#define KAD_K 8 /* Replication factor, MDHT value. */ -#define KAD_T_REPL 900 /* Replication time, tied to k. MDHT value. */ -#define KAD_T_REFR 900 /* Refresh time stale bucket, MDHT value. */ -#define KAD_T_JOIN 8 /* Response time to wait for a join. */ -#define KAD_T_RESP 5 /* Response time to wait for a response. */ -#define KAD_R_PING 2 /* Ping retries before declaring peer dead. */ -#define KAD_QUEER 15 /* Time to declare peer questionable. */ -#define KAD_BETA 8 /* Bucket split factor, must be 1, 2, 4 or 8. */ -#define KAD_RESP_RETR 6 /* Number of retries on sending a response. */ -#define KAD_JOIN_RETR 8 /* Number of retries sending a join. */ -#define KAD_JOIN_INTV 1 /* Time (seconds) between join retries. */ -#define HANDLE_TIMEO 1000 /* Timeout for dht_handle_packet tpm check (ms) */ -#define DHT_RETR_ADDR 1 /* Number of addresses to return on retrieve */ - -enum dht_state { - DHT_INIT = 0, - DHT_SHUTDOWN, - DHT_JOINING, - DHT_RUNNING, -}; - -enum kad_code { - KAD_JOIN = 0, - KAD_FIND_NODE, - KAD_FIND_VALUE, - /* Messages without a response below. */ - KAD_STORE, - KAD_RESPONSE -}; - -enum kad_req_state { - REQ_NULL = 0, - REQ_INIT, - REQ_PENDING, - REQ_RESPONSE, - REQ_DONE, - REQ_DESTROY -}; - -enum lookup_state { - LU_NULL = 0, - LU_INIT, - LU_PENDING, - LU_UPDATE, - LU_COMPLETE, - LU_DESTROY -}; - -struct kad_req { - struct list_head next; - - uint32_t cookie; - enum kad_code code; - uint8_t * key; - uint64_t addr; - - enum kad_req_state state; - pthread_cond_t cond; - pthread_mutex_t lock; - - time_t t_exp; -}; - -struct cookie_el { - struct list_head next; - - uint32_t cookie; -}; - -struct lookup { - struct list_head next; - - struct list_head cookies; - - uint8_t * key; - - struct list_head contacts; - size_t n_contacts; - - uint64_t * addrs; - size_t n_addrs; - - enum lookup_state state; - pthread_cond_t cond; - pthread_mutex_t lock; -}; - -struct val { - struct list_head next; - - uint64_t addr; - - time_t t_exp; - time_t t_rep; -}; - -struct ref_entry { - struct list_head next; - - uint8_t * key; - - time_t t_rep; -}; - -struct dht_entry { - struct list_head next; - - uint8_t * key; - size_t n_vals; - struct list_head vals; -}; - -struct contact { - struct list_head next; - - uint8_t * id; - uint64_t addr; - - size_t fails; - time_t t_seen; -}; - -struct bucket { - struct list_head contacts; - size_t n_contacts; - - struct list_head alts; - size_t n_alts; - - time_t t_refr; - - size_t depth; - uint8_t mask; - - struct bucket * parent; - struct bucket * children[1L << KAD_BETA]; -}; - -struct cmd { - struct list_head next; - - struct shm_du_buff * sdb; -}; - -struct dht { - size_t alpha; - size_t b; - size_t k; - - time_t t_expire; - time_t t_refresh; - time_t t_replic; - time_t t_repub; - - uint8_t * id; - uint64_t addr; - - struct bucket * buckets; - - struct list_head entries; - - struct list_head refs; - - struct list_head lookups; - - struct list_head requests; - struct bmp * cookies; - - enum dht_state state; - struct list_head cmds; - pthread_cond_t cond; - pthread_mutex_t mtx; - - pthread_rwlock_t lock; - - int fd; - - struct tpm * tpm; - - pthread_t worker; -}; - -struct join_info { - struct dht * dht; - uint64_t addr; -}; - -struct packet_info { - struct dht * dht; - struct shm_du_buff * sdb; -}; - -static uint8_t * dht_dup_key(const uint8_t * key, - size_t len) -{ - uint8_t * dup; - - dup = malloc(sizeof(*dup) * len); - if (dup == NULL) - return NULL; - - memcpy(dup, key, len); - - return dup; -} - -static enum dht_state dht_get_state(struct dht * dht) -{ - enum dht_state state; - - pthread_mutex_lock(&dht->mtx); - - state = dht->state; - - pthread_mutex_unlock(&dht->mtx); - - return state; -} - -static int dht_set_state(struct dht * dht, - enum dht_state state) -{ - pthread_mutex_lock(&dht->mtx); - - if (state == DHT_JOINING && dht->state != DHT_INIT) { - pthread_mutex_unlock(&dht->mtx); - return -1; - } - - dht->state = state; - - pthread_cond_broadcast(&dht->cond); - - pthread_mutex_unlock(&dht->mtx); - - return 0; -} - -int dht_wait_running(struct dht * dht) -{ - int ret = 0; - - pthread_mutex_lock(&dht->mtx); - - pthread_cleanup_push((void *)(void *) pthread_mutex_unlock, - &dht->mtx); - - while (dht->state == DHT_JOINING) - pthread_cond_wait(&dht->cond, &dht->mtx); - - if (dht->state != DHT_RUNNING) - ret = -1; - - pthread_cleanup_pop(true); - - return ret; -} - -static uint8_t * create_id(size_t len) -{ - uint8_t * id; - - id = malloc(len); - if (id == NULL) - return NULL; - - if (random_buffer(id, len) < 0) { - free(id); - return NULL; - } - - return id; -} - -static void kad_req_create(struct dht * dht, - kad_msg_t * msg, - uint64_t addr) -{ - struct kad_req * req; - pthread_condattr_t cattr; - struct timespec t; - size_t b; - - req = malloc(sizeof(*req)); - if (req == NULL) - return; - - list_head_init(&req->next); - - clock_gettime(CLOCK_REALTIME_COARSE, &t); - - req->t_exp = t.tv_sec + KAD_T_RESP; - req->addr = addr; - req->state = REQ_INIT; - req->cookie = msg->cookie; - req->code = msg->code; - req->key = NULL; - - pthread_rwlock_rdlock(&dht->lock); - b = dht->b; - pthread_rwlock_unlock(&dht->lock); - - if (msg->has_key) { - req->key = dht_dup_key(msg->key.data, b); - if (req->key == NULL) { - free(req); - return; - } - } - - if (pthread_mutex_init(&req->lock, NULL)) { - free(req->key); - free(req); - return; - } - - pthread_condattr_init(&cattr); -#ifndef __APPLE__ - pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK); -#endif - - if (pthread_cond_init(&req->cond, &cattr)) { - pthread_condattr_destroy(&cattr); - pthread_mutex_destroy(&req->lock); - free(req->key); - free(req); - return; - } - - pthread_condattr_destroy(&cattr); - - pthread_rwlock_wrlock(&dht->lock); - - list_add(&req->next, &dht->requests); - - pthread_rwlock_unlock(&dht->lock); -} - -static void cancel_req_destroy(void * o) -{ - struct kad_req * req = (struct kad_req *) o; - - pthread_mutex_unlock(&req->lock); - - pthread_cond_destroy(&req->cond); - pthread_mutex_destroy(&req->lock); - - if (req->key != NULL) - free(req->key); - - free(req); -} - -static void kad_req_destroy(struct kad_req * req) -{ - assert(req); - - pthread_mutex_lock(&req->lock); - - switch (req->state) { - case REQ_DESTROY: - pthread_mutex_unlock(&req->lock); - return; - case REQ_PENDING: - req->state = REQ_DESTROY; - pthread_cond_signal(&req->cond); - break; - case REQ_INIT: - case REQ_DONE: - req->state = REQ_NULL; - break; - case REQ_RESPONSE: - case REQ_NULL: - default: - break; - } - - pthread_cleanup_push(cancel_req_destroy, req); - - while (req->state != REQ_NULL && req->state != REQ_DONE) - pthread_cond_wait(&req->cond, &req->lock); - - pthread_cleanup_pop(true); -} - -static int kad_req_wait(struct kad_req * req, - time_t t) -{ - struct timespec timeo = {t, 0}; - struct timespec abs; - int ret = 0; - - assert(req); - - clock_gettime(PTHREAD_COND_CLOCK, &abs); - - ts_add(&abs, &timeo, &abs); - - pthread_mutex_lock(&req->lock); - - req->state = REQ_PENDING; - - pthread_cleanup_push((void *)(void *) pthread_mutex_unlock, - &req->lock); - - while (req->state == REQ_PENDING && ret != -ETIMEDOUT) - ret = -pthread_cond_timedwait(&req->cond, &req->lock, &abs); - - switch(req->state) { - case REQ_DESTROY: - ret = -1; - req->state = REQ_NULL; - pthread_cond_signal(&req->cond); - break; - case REQ_PENDING: /* ETIMEDOUT */ - case REQ_RESPONSE: - req->state = REQ_DONE; - pthread_cond_broadcast(&req->cond); - break; - default: - break; - } - - pthread_cleanup_pop(true); - - return ret; -} - -static void kad_req_respond(struct kad_req * req) -{ - pthread_mutex_lock(&req->lock); - - req->state = REQ_RESPONSE; - pthread_cond_signal(&req->cond); - - pthread_mutex_unlock(&req->lock); -} - -static struct contact * contact_create(const uint8_t * id, - size_t len, - uint64_t addr) -{ - struct contact * c; - struct timespec t; - - c = malloc(sizeof(*c)); - if (c == NULL) - return NULL; - - list_head_init(&c->next); - - clock_gettime(CLOCK_REALTIME_COARSE, &t); - - c->addr = addr; - c->fails = 0; - c->t_seen = t.tv_sec; - c->id = dht_dup_key(id, len); - if (c->id == NULL) { - free(c); - return NULL; - } - - return c; -} - -static void contact_destroy(struct contact * c) -{ - if (c != NULL) - free(c->id); - - free(c); -} - -static struct bucket * iter_bucket(struct bucket * b, - const uint8_t * id) -{ - uint8_t byte; - uint8_t mask; - - assert(b); - - if (b->children[0] == NULL) - return b; - - byte = id[(b->depth * KAD_BETA) / CHAR_BIT]; - - mask = ((1L << KAD_BETA) - 1) & 0xFF; - - byte >>= (CHAR_BIT - KAD_BETA) - - (((b->depth) * KAD_BETA) & (CHAR_BIT - 1)); - - return iter_bucket(b->children[(byte & mask)], id); -} - -static struct bucket * dht_get_bucket(struct dht * dht, - const uint8_t * id) -{ - assert(dht->buckets); - - return iter_bucket(dht->buckets, id); -} - -/* - * If someone builds a network where the n (n > k) closest nodes all - * have IDs starting with the same 64 bits: by all means, change this. - */ -static uint64_t dist(const uint8_t * src, - const uint8_t * dst) -{ - return betoh64(*((uint64_t *) src) ^ *((uint64_t *) dst)); -} - -static size_t list_add_sorted(struct list_head * l, - struct contact * c, - const uint8_t * key) -{ - struct list_head * p; - - assert(l); - assert(c); - assert(key); - assert(c->id); - - list_for_each(p, l) { - struct contact * e = list_entry(p, struct contact, next); - if (dist(c->id, key) > dist(e->id, key)) - break; - } - - list_add_tail(&c->next, p); - - return 1; -} - -static size_t dht_contact_list(struct dht * dht, - struct list_head * l, - const uint8_t * key) -{ - struct list_head * p; - struct bucket * b; - size_t len = 0; - size_t i; - struct timespec t; - - assert(l); - assert(dht); - assert(key); - assert(list_is_empty(l)); - - clock_gettime(CLOCK_REALTIME_COARSE, &t); - - b = dht_get_bucket(dht, key); - if (b == NULL) - return 0; - - b->t_refr = t.tv_sec + KAD_T_REFR; - - if (b->n_contacts == dht->k || b->parent == NULL) { - list_for_each(p, &b->contacts) { - struct contact * c; - c = list_entry(p, struct contact, next); - c = contact_create(c->id, dht->b, c->addr); - if (list_add_sorted(l, c, key) == 1) - if (++len == dht->k) - break; - } - } else { - struct bucket * d = b->parent; - for (i = 0; i < (1L << KAD_BETA) && len < dht->k; ++i) { - list_for_each(p, &d->children[i]->contacts) { - struct contact * c; - c = list_entry(p, struct contact, next); - c = contact_create(c->id, dht->b, c->addr); - if (c == NULL) - continue; - if (list_add_sorted(l, c, key) == 1) - if (++len == dht->k) - break; - } - } - } - - assert(len == dht->k || b->parent == NULL); - - return len; -} - -static struct lookup * lookup_create(struct dht * dht, - const uint8_t * id) -{ - struct lookup * lu; - pthread_condattr_t cattr; - - assert(dht); - assert(id); - - lu = malloc(sizeof(*lu)); - if (lu == NULL) - goto fail_malloc; - - list_head_init(&lu->contacts); - list_head_init(&lu->cookies); - - lu->state = LU_INIT; - lu->addrs = NULL; - lu->n_addrs = 0; - lu->key = dht_dup_key(id, dht->b); - if (lu->key == NULL) - goto fail_id; - - if (pthread_mutex_init(&lu->lock, NULL)) - goto fail_mutex; - - pthread_condattr_init(&cattr); -#ifndef __APPLE__ - pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK); -#endif - - if (pthread_cond_init(&lu->cond, &cattr)) - goto fail_cond; - - pthread_condattr_destroy(&cattr); - - pthread_rwlock_wrlock(&dht->lock); - - list_add(&lu->next, &dht->lookups); - - lu->n_contacts = dht_contact_list(dht, &lu->contacts, id); - - pthread_rwlock_unlock(&dht->lock); - - return lu; - - fail_cond: - pthread_condattr_destroy(&cattr); - pthread_mutex_destroy(&lu->lock); - fail_mutex: - free(lu->key); - fail_id: - free(lu); - fail_malloc: - return NULL; -} - -static void cancel_lookup_destroy(void * o) -{ - struct lookup * lu; - struct list_head * p; - struct list_head * h; - - lu = (struct lookup *) o; - - if (lu->key != NULL) - free(lu->key); - if (lu->addrs != NULL) - free(lu->addrs); - - list_for_each_safe(p, h, &lu->contacts) { - struct contact * c = list_entry(p, struct contact, next); - list_del(&c->next); - contact_destroy(c); - } - - list_for_each_safe(p, h, &lu->cookies) { - struct cookie_el * c = list_entry(p, struct cookie_el, next); - list_del(&c->next); - free(c); - } - - pthread_mutex_unlock(&lu->lock); - - pthread_mutex_destroy(&lu->lock); - - free(lu); -} - -static void lookup_destroy(struct lookup * lu) -{ - assert(lu); - - pthread_mutex_lock(&lu->lock); - - switch (lu->state) { - case LU_DESTROY: - pthread_mutex_unlock(&lu->lock); - return; - case LU_PENDING: - lu->state = LU_DESTROY; - pthread_cond_broadcast(&lu->cond); - break; - case LU_INIT: - case LU_UPDATE: - case LU_COMPLETE: - lu->state = LU_NULL; - break; - case LU_NULL: - default: - break; - } - - pthread_cleanup_push(cancel_lookup_destroy, lu); - - while (lu->state != LU_NULL) - pthread_cond_wait(&lu->cond, &lu->lock); - - pthread_cleanup_pop(true); -} - -static void lookup_update(struct dht * dht, - struct lookup * lu, - kad_msg_t * msg) -{ - struct list_head * p = NULL; - struct list_head * h; - struct contact * c = NULL; - size_t n; - size_t pos = 0; - bool mod = false; - - assert(lu); - assert(msg); - - if (dht_get_state(dht) != DHT_RUNNING) - return; - - pthread_mutex_lock(&lu->lock); - - list_for_each_safe(p, h, &lu->cookies) { - struct cookie_el * e = list_entry(p, struct cookie_el, next); - if (e->cookie == msg->cookie) { - list_del(&e->next); - free(e); - break; - } - } - - if (lu->state == LU_COMPLETE) { - pthread_mutex_unlock(&lu->lock); - return; - } - - if (msg->n_addrs > 0) { - if (lu->addrs == NULL) { - lu->addrs = malloc(sizeof(*lu->addrs) * msg->n_addrs); - for (n = 0; n < msg->n_addrs; ++n) - lu->addrs[n] = msg->addrs[n]; - lu->n_addrs = msg->n_addrs; - } - - lu->state = LU_COMPLETE; - pthread_cond_broadcast(&lu->cond); - pthread_mutex_unlock(&lu->lock); - return; - } - - pthread_cleanup_push((void *)(void *) pthread_mutex_unlock, - &lu->lock); - - while (lu->state == LU_INIT) { - pthread_rwlock_unlock(&dht->lock); - pthread_cond_wait(&lu->cond, &lu->lock); - pthread_rwlock_rdlock(&dht->lock); - } - - pthread_cleanup_pop(false); - - for (n = 0; n < msg->n_contacts; ++n) { - c = contact_create(msg->contacts[n]->id.data, - dht->b, msg->contacts[n]->addr); - if (c == NULL) - continue; - - pos = 0; - - list_for_each(p, &lu->contacts) { - struct contact * e; - e = list_entry(p, struct contact, next); - if (!memcmp(e->id, c->id, dht->b)) { - contact_destroy(c); - c = NULL; - break; - } - - if (dist(c->id, lu->key) > dist(e->id, lu->key)) - break; - - pos++; - } - - if (c == NULL) - continue; - - if (lu->n_contacts < dht->k) { - list_add_tail(&c->next, p); - ++lu->n_contacts; - mod = true; - } else if (pos == dht->k) { - contact_destroy(c); - } else { - struct contact * d; - list_add_tail(&c->next, p); - d = list_last_entry(&lu->contacts, - struct contact, next); - list_del(&d->next); - assert(lu->contacts.prv != &d->next); - contact_destroy(d); - mod = true; - } - } - - if (list_is_empty(&lu->cookies) && !mod) - lu->state = LU_COMPLETE; - else - lu->state = LU_UPDATE; - - pthread_cond_broadcast(&lu->cond); - pthread_mutex_unlock(&lu->lock); - return; -} - -static ssize_t lookup_get_addrs(struct lookup * lu, - uint64_t * addrs) -{ - ssize_t n; - - assert(lu); - - pthread_mutex_lock(&lu->lock); - - for (n = 0; (size_t) n < lu->n_addrs; ++n) - addrs[n] = lu->addrs[n]; - - assert((size_t) n == lu->n_addrs); - - pthread_mutex_unlock(&lu->lock); - - return n; -} - -static ssize_t lookup_contact_addrs(struct lookup * lu, - uint64_t * addrs) -{ - struct list_head * p; - ssize_t n = 0; - - assert(lu); - assert(addrs); - - pthread_mutex_lock(&lu->lock); - - list_for_each(p, &lu->contacts) { - struct contact * c = list_entry(p, struct contact, next); - addrs[n] = c->addr; - n++; - } - - pthread_mutex_unlock(&lu->lock); - - return n; -} - -static void lookup_new_addrs(struct lookup * lu, - uint64_t * addrs) -{ - struct list_head * p; - size_t n = 0; - - assert(lu); - assert(addrs); - - pthread_mutex_lock(&lu->lock); - - /* Uses fails to check if the contact has been contacted. */ - list_for_each(p, &lu->contacts) { - struct contact * c = list_entry(p, struct contact, next); - if (c->fails == 0) { - c->fails = 1; - addrs[n] = c->addr; - n++; - } - - if (n == KAD_ALPHA) - break; - } - - assert(n <= KAD_ALPHA); - - addrs[n] = 0; - - pthread_mutex_unlock(&lu->lock); -} - -static void lookup_set_state(struct lookup * lu, - enum lookup_state state) -{ - pthread_mutex_lock(&lu->lock); - - lu->state = state; - pthread_cond_broadcast(&lu->cond); - - pthread_mutex_unlock(&lu->lock); -} - -static void cleanup_wait(void * o) -{ - struct lookup * lu = (struct lookup *) o; - lu->state = LU_NULL; - pthread_mutex_unlock(&lu->lock); - lookup_destroy(lu); -} - -static enum lookup_state lookup_wait(struct lookup * lu) -{ - struct timespec timeo = {KAD_T_RESP, 0}; - struct timespec abs; - enum lookup_state state; - int ret = 0; - - clock_gettime(PTHREAD_COND_CLOCK, &abs); - - ts_add(&abs, &timeo, &abs); - - pthread_mutex_lock(&lu->lock); - - if (lu->state == LU_INIT || lu->state == LU_UPDATE) - lu->state = LU_PENDING; - - pthread_cleanup_push(cleanup_wait, lu); - - while (lu->state == LU_PENDING && ret != -ETIMEDOUT) - ret = -pthread_cond_timedwait(&lu->cond, &lu->lock, &abs); - - pthread_cleanup_pop(false); - - if (ret == -ETIMEDOUT) - lu->state = LU_COMPLETE; - - state = lu->state; - - pthread_mutex_unlock(&lu->lock); - - return state; -} - -static struct kad_req * dht_find_request(struct dht * dht, - kad_msg_t * msg) -{ - struct list_head * p; - - assert(dht); - assert(msg); - - list_for_each(p, &dht->requests) { - struct kad_req * r = list_entry(p, struct kad_req, next); - if (r->cookie == msg->cookie) - return r; - } - - return NULL; -} - -static struct lookup * dht_find_lookup(struct dht * dht, - uint32_t cookie) -{ - struct list_head * p; - struct list_head * p2; - struct list_head * h2; - - assert(dht); - assert(cookie > 0); - - list_for_each(p, &dht->lookups) { - struct lookup * l = list_entry(p, struct lookup, next); - pthread_mutex_lock(&l->lock); - list_for_each_safe(p2, h2, &l->cookies) { - struct cookie_el * e; - e = list_entry(p2, struct cookie_el, next); - if (e->cookie == cookie) { - list_del(&e->next); - free(e); - pthread_mutex_unlock(&l->lock); - return l; - } - } - pthread_mutex_unlock(&l->lock); - } - - return NULL; -} - -static struct val * val_create(uint64_t addr, - time_t exp) -{ - struct val * v; - struct timespec t; - - v = malloc(sizeof(*v)); - if (v == NULL) - return NULL; - - list_head_init(&v->next); - v->addr = addr; - - clock_gettime(CLOCK_REALTIME_COARSE, &t); - - v->t_exp = t.tv_sec + exp; - v->t_rep = t.tv_sec + KAD_T_REPL; - - return v; -} - -static void val_destroy(struct val * v) -{ - assert(v); - - free(v); -} - -static struct ref_entry * ref_entry_create(struct dht * dht, - const uint8_t * key) -{ - struct ref_entry * e; - struct timespec t; - - assert(dht); - assert(key); - - e = malloc(sizeof(*e)); - if (e == NULL) - return NULL; - - e->key = dht_dup_key(key, dht->b); - if (e->key == NULL) { - free(e); - return NULL; - } - - clock_gettime(CLOCK_REALTIME_COARSE, &t); - - e->t_rep = t.tv_sec + dht->t_repub; - - return e; -} - -static void ref_entry_destroy(struct ref_entry * e) -{ - free(e->key); - free(e); -} - -static struct dht_entry * dht_entry_create(struct dht * dht, - const uint8_t * key) -{ - struct dht_entry * e; - - assert(dht); - assert(key); - - e = malloc(sizeof(*e)); - if (e == NULL) - return NULL; - - list_head_init(&e->next); - list_head_init(&e->vals); - - e->n_vals = 0; - - e->key = dht_dup_key(key, dht->b); - if (e->key == NULL) { - free(e); - return NULL; - } - - return e; -} - -static void dht_entry_destroy(struct dht_entry * e) -{ - struct list_head * p; - struct list_head * h; - - assert(e); - - list_for_each_safe(p, h, &e->vals) { - struct val * v = list_entry(p, struct val, next); - list_del(&v->next); - val_destroy(v); - } - - free(e->key); - - free(e); -} - -static int dht_entry_add_addr(struct dht_entry * e, - uint64_t addr, - time_t exp) -{ - struct list_head * p; - struct val * val; - struct timespec t; - - clock_gettime(CLOCK_REALTIME_COARSE, &t); - - list_for_each(p, &e->vals) { - struct val * v = list_entry(p, struct val, next); - if (v->addr == addr) { - if (v->t_exp < t.tv_sec + exp) { - v->t_exp = t.tv_sec + exp; - v->t_rep = t.tv_sec + KAD_T_REPL; - } - - return 0; - } - } - - val = val_create(addr, exp); - if (val == NULL) - return -ENOMEM; - - list_add(&val->next, &e->vals); - ++e->n_vals; - - return 0; -} - - -static void dht_entry_del_addr(struct dht_entry * e, - uint64_t addr) -{ - struct list_head * p; - struct list_head * h; - - assert(e); - - list_for_each_safe(p, h, &e->vals) { - struct val * v = list_entry(p, struct val, next); - if (v->addr == addr) { - list_del(&v->next); - val_destroy(v); - --e->n_vals; - } - } - - if (e->n_vals == 0) { - list_del(&e->next); - dht_entry_destroy(e); - } -} - -static uint64_t dht_entry_get_addr(struct dht * dht, - struct dht_entry * e) -{ - struct list_head * p; - - assert(e); - assert(!list_is_empty(&e->vals)); - - list_for_each(p, &e->vals) { - struct val * v = list_entry(p, struct val, next); - if (v->addr != dht->addr) - return v->addr; - } - - return 0; -} - -/* Forward declaration. */ -static struct lookup * kad_lookup(struct dht * dht, - const uint8_t * key, - enum kad_code code); - - -/* Build a refresh list. */ -static void bucket_refresh(struct dht * dht, - struct bucket * b, - time_t t, - struct list_head * r) -{ - size_t i; - - if (*b->children != NULL) - for (i = 0; i < (1L << KAD_BETA); ++i) - bucket_refresh(dht, b->children[i], t, r); - - if (b->n_contacts == 0) - return; - - if (t > b->t_refr) { - struct contact * c; - struct contact * d; - c = list_first_entry(&b->contacts, struct contact, next); - d = contact_create(c->id, dht->b, c->addr); - if (c != NULL) - list_add(&d->next, r); - return; - } -} - - -static struct bucket * bucket_create(void) -{ - struct bucket * b; - struct timespec t; - size_t i; - - b = malloc(sizeof(*b)); - if (b == NULL) - return NULL; - - list_head_init(&b->contacts); - b->n_contacts = 0; - - list_head_init(&b->alts); - b->n_alts = 0; - - clock_gettime(CLOCK_REALTIME_COARSE, &t); - b->t_refr = t.tv_sec + KAD_T_REFR; - - for (i = 0; i < (1L << KAD_BETA); ++i) - b->children[i] = NULL; - - b->parent = NULL; - b->depth = 0; - - return b; -} - -static void bucket_destroy(struct bucket * b) -{ - struct list_head * p; - struct list_head * h; - size_t i; - - assert(b); - - for (i = 0; i < (1L << KAD_BETA); ++i) - if (b->children[i] != NULL) - bucket_destroy(b->children[i]); - - list_for_each_safe(p, h, &b->contacts) { - struct contact * c = list_entry(p, struct contact, next); - list_del(&c->next); - contact_destroy(c); - --b->n_contacts; - } - - list_for_each_safe(p, h, &b->alts) { - struct contact * c = list_entry(p, struct contact, next); - list_del(&c->next); - contact_destroy(c); - --b->n_contacts; - } - - free(b); -} - -static bool bucket_has_id(struct bucket * b, - const uint8_t * id) -{ - uint8_t mask; - uint8_t byte; - - if (b->depth == 0) - return true; - - byte = id[(b->depth * KAD_BETA) / CHAR_BIT]; - - mask = ((1L << KAD_BETA) - 1) & 0xFF; - - byte >>= (CHAR_BIT - KAD_BETA) - - (((b->depth - 1) * KAD_BETA) & (CHAR_BIT - 1)); - - return ((byte & mask) == b->mask); -} - -static int split_bucket(struct bucket * b) -{ - struct list_head * p; - struct list_head * h; - uint8_t mask = 0; - size_t i; - size_t c; - - assert(b); - assert(b->n_alts == 0); - assert(b->n_contacts); - assert(b->children[0] == NULL); - - c = b->n_contacts; - - for (i = 0; i < (1L << KAD_BETA); ++i) { - b->children[i] = bucket_create(); - if (b->children[i] == NULL) { - size_t j; - for (j = 0; j < i; ++j) - bucket_destroy(b->children[j]); - return -1; - } - - b->children[i]->depth = b->depth + 1; - b->children[i]->mask = mask; - b->children[i]->parent = b; - - list_for_each_safe(p, h, &b->contacts) { - struct contact * c; - c = list_entry(p, struct contact, next); - if (bucket_has_id(b->children[i], c->id)) { - list_del(&c->next); - --b->n_contacts; - list_add(&c->next, &b->children[i]->contacts); - ++b->children[i]->n_contacts; - } - } - - mask++; - } - - for (i = 0; i < (1L << KAD_BETA); ++i) - if (b->children[i]->n_contacts == c) - split_bucket(b->children[i]); - - return 0; -} - -/* Locked externally to mandate update as (final) part of join transaction. */ -static int dht_update_bucket(struct dht * dht, - const uint8_t * id, - uint64_t addr) -{ - struct list_head * p; - struct list_head * h; - struct bucket * b; - struct contact * c; - - assert(dht); - - b = dht_get_bucket(dht, id); - if (b == NULL) - return -1; - - c = contact_create(id, dht->b, addr); - if (c == NULL) - return -1; - - list_for_each_safe(p, h, &b->contacts) { - struct contact * d = list_entry(p, struct contact, next); - if (d->addr == addr) { - list_del(&d->next); - contact_destroy(d); - --b->n_contacts; - } - } - - if (b->n_contacts == dht->k) { - if (bucket_has_id(b, dht->id)) { - list_add_tail(&c->next, &b->contacts); - ++b->n_contacts; - if (split_bucket(b)) { - list_del(&c->next); - contact_destroy(c); - --b->n_contacts; - } - } else if (b->n_alts == dht->k) { - struct contact * d; - d = list_first_entry(&b->alts, struct contact, next); - list_del(&d->next); - contact_destroy(d); - list_add_tail(&c->next, &b->alts); - } else { - list_add_tail(&c->next, &b->alts); - ++b->n_alts; - } - } else { - list_add_tail(&c->next, &b->contacts); - ++b->n_contacts; - } - - return 0; -} - -static int send_msg(struct dht * dht, - kad_msg_t * msg, - uint64_t addr) -{ -#ifndef __DHT_TEST__ - struct shm_du_buff * sdb; - size_t len; -#endif - int retr = 0; - - if (msg->code == KAD_RESPONSE) - retr = KAD_RESP_RETR; - - pthread_rwlock_wrlock(&dht->lock); - - if (dht->id != NULL) { - msg->has_s_id = true; - msg->s_id.data = dht->id; - msg->s_id.len = dht->b; - } - - msg->s_addr = dht->addr; - - if (msg->code < KAD_STORE) { - msg->cookie = bmp_allocate(dht->cookies); - if (!bmp_is_id_valid(dht->cookies, msg->cookie)) { - pthread_rwlock_unlock(&dht->lock); - goto fail_bmp_alloc; - } - } - - pthread_rwlock_unlock(&dht->lock); - -#ifndef __DHT_TEST__ - len = kad_msg__get_packed_size(msg); - if (len == 0) - goto fail_msg; - - while (true) { - if (ipcp_sdb_reserve(&sdb, len)) - goto fail_msg; - - kad_msg__pack(msg, shm_du_buff_head(sdb)); - - if (dt_write_packet(addr, QOS_CUBE_BE, dht->fd, sdb) == 0) - break; - - ipcp_sdb_release(sdb); - - sleep(1); - - if (--retr < 0) - goto fail_msg; - } - -#else - (void) addr; - (void) retr; -#endif /* __DHT_TEST__ */ - - if (msg->code < KAD_STORE && dht_get_state(dht) != DHT_SHUTDOWN) - kad_req_create(dht, msg, addr); - - return msg->cookie; -#ifndef __DHT_TEST__ - fail_msg: - pthread_rwlock_wrlock(&dht->lock); - bmp_release(dht->cookies, msg->cookie); - pthread_rwlock_unlock(&dht->lock); -#endif /* !__DHT_TEST__ */ - fail_bmp_alloc: - return -1; -} - -static struct dht_entry * dht_find_entry(struct dht * dht, - const uint8_t * key) -{ - struct list_head * p; - - list_for_each(p, &dht->entries) { - struct dht_entry * e = list_entry(p, struct dht_entry, next); - if (!memcmp(key, e->key, dht->b)) - return e; - } - - return NULL; -} - -static int kad_add(struct dht * dht, - const kad_contact_msg_t * contacts, - ssize_t n, - time_t exp) -{ - struct dht_entry * e; - - pthread_rwlock_wrlock(&dht->lock); - - while (n-- > 0) { - if (contacts[n].id.len != dht->b) - log_warn("Bad key length in contact data."); - - e = dht_find_entry(dht, contacts[n].id.data); - if (e != NULL) { - if (dht_entry_add_addr(e, contacts[n].addr, exp)) - goto fail; - } else { - e = dht_entry_create(dht, contacts[n].id.data); - if (e == NULL) - goto fail; - - if (dht_entry_add_addr(e, contacts[n].addr, exp)) { - dht_entry_destroy(e); - goto fail; - } - - list_add(&e->next, &dht->entries); - } - } - - pthread_rwlock_unlock(&dht->lock); - return 0; - - fail: - pthread_rwlock_unlock(&dht->lock); - return -ENOMEM; -} - -static int wait_resp(struct dht * dht, - kad_msg_t * msg, - time_t timeo) -{ - struct kad_req * req; - - assert(dht); - assert(msg); - - pthread_rwlock_rdlock(&dht->lock); - - req = dht_find_request(dht, msg); - if (req == NULL) { - pthread_rwlock_unlock(&dht->lock); - return -EPERM; - } - - pthread_rwlock_unlock(&dht->lock); - - return kad_req_wait(req, timeo); -} - -static int kad_store(struct dht * dht, - const uint8_t * key, - uint64_t addr, - uint64_t r_addr, - time_t ttl) -{ - kad_msg_t msg = KAD_MSG__INIT; - kad_contact_msg_t cmsg = KAD_CONTACT_MSG__INIT; - kad_contact_msg_t * cmsgp[1]; - - cmsg.id.data = (uint8_t *) key; - cmsg.addr = addr; - - pthread_rwlock_rdlock(&dht->lock); - - cmsg.id.len = dht->b; - - pthread_rwlock_unlock(&dht->lock); - - cmsgp[0] = &cmsg; - - msg.code = KAD_STORE; - msg.has_t_expire = true; - msg.t_expire = ttl; - msg.n_contacts = 1; - msg.contacts = cmsgp; - - if (send_msg(dht, &msg, r_addr) < 0) - return -1; - - return 0; -} - -static ssize_t kad_find(struct dht * dht, - struct lookup * lu, - const uint64_t * addrs, - enum kad_code code) -{ - kad_msg_t msg = KAD_MSG__INIT; - ssize_t sent = 0; - - assert(dht); - assert(lu->key); - - msg.code = code; - - msg.has_key = true; - msg.key.data = (uint8_t *) lu->key; - msg.key.len = dht->b; - - while (*addrs != 0) { - struct cookie_el * c; - int ret; - - if (*addrs == dht->addr) { - ++addrs; - continue; - } - - ret = send_msg(dht, &msg, *addrs); - if (ret < 0) - break; - - c = malloc(sizeof(*c)); - if (c == NULL) - break; - - c->cookie = (uint32_t) ret; - - pthread_mutex_lock(&lu->lock); - - list_add_tail(&c->next, &lu->cookies); - - pthread_mutex_unlock(&lu->lock); - - ++sent; - ++addrs; - } - - return sent; -} - -static void lookup_detach(struct dht * dht, - struct lookup * lu) -{ - pthread_rwlock_wrlock(&dht->lock); - - list_del(&lu->next); - - pthread_rwlock_unlock(&dht->lock); -} - -static struct lookup * kad_lookup(struct dht * dht, - const uint8_t * id, - enum kad_code code) -{ - uint64_t addrs[KAD_ALPHA + 1]; - enum lookup_state state; - struct lookup * lu; - - lu = lookup_create(dht, id); - if (lu == NULL) - return NULL; - - lookup_new_addrs(lu, addrs); - - if (addrs[0] == 0) { - lookup_detach(dht, lu); - lookup_destroy(lu); - return NULL; - } - - if (kad_find(dht, lu, addrs, code) == 0) { - lookup_detach(dht, lu); - return lu; - } - - while ((state = lookup_wait(lu)) != LU_COMPLETE) { - switch (state) { - case LU_UPDATE: - lookup_new_addrs(lu, addrs); - if (addrs[0] == 0) - break; - - kad_find(dht, lu, addrs, code); - break; - case LU_DESTROY: - lookup_detach(dht, lu); - lookup_set_state(lu, LU_NULL); - return NULL; - default: - break; - } - } - - assert(state = LU_COMPLETE); - - lookup_detach(dht, lu); - - return lu; -} - -static void kad_publish(struct dht * dht, - const uint8_t * key, - uint64_t addr, - time_t exp) -{ - struct lookup * lu; - uint64_t * addrs; - ssize_t n; - size_t k; - time_t t_expire; - - - assert(dht); - assert(key); - - pthread_rwlock_rdlock(&dht->lock); - - k = dht->k; - t_expire = dht->t_expire; - - pthread_rwlock_unlock(&dht->lock); - - addrs = malloc(k * sizeof(*addrs)); - if (addrs == NULL) - return; - - lu = kad_lookup(dht, key, KAD_FIND_NODE); - if (lu == NULL) { - free(addrs); - return; - } - - n = lookup_contact_addrs(lu, addrs); - - while (n-- > 0) { - if (addrs[n] == dht->addr) { - kad_contact_msg_t msg = KAD_CONTACT_MSG__INIT; - msg.id.data = (uint8_t *) key; - msg.id.len = dht->b; - msg.addr = addr; - kad_add(dht, &msg, 1, exp); - } else { - if (kad_store(dht, key, addr, addrs[n], t_expire)) - log_warn("Failed to send store message."); - } - } - - lookup_destroy(lu); - - free(addrs); -} - -static int kad_join(struct dht * dht, - uint64_t addr) -{ - kad_msg_t msg = KAD_MSG__INIT; - - msg.code = KAD_JOIN; - - msg.has_alpha = true; - msg.has_b = true; - msg.has_k = true; - msg.has_t_refresh = true; - msg.has_t_replicate = true; - msg.alpha = KAD_ALPHA; - msg.k = KAD_K; - msg.t_refresh = KAD_T_REFR; - msg.t_replicate = KAD_T_REPL; - - pthread_rwlock_rdlock(&dht->lock); - - msg.b = dht->b; - - pthread_rwlock_unlock(&dht->lock); - - if (send_msg(dht, &msg, addr) < 0) - return -1; - - if (wait_resp(dht, &msg, KAD_T_JOIN) < 0) - return -1; - - dht->id = create_id(dht->b); - if (dht->id == NULL) - return -1; - - pthread_rwlock_wrlock(&dht->lock); - - dht_update_bucket(dht, dht->id, dht->addr); - - pthread_rwlock_unlock(&dht->lock); - - return 0; -} - -static void dht_dead_peer(struct dht * dht, - uint8_t * key, - uint64_t addr) -{ - struct list_head * p; - struct list_head * h; - struct bucket * b; - - b = dht_get_bucket(dht, key); - - list_for_each_safe(p, h, &b->contacts) { - struct contact * c = list_entry(p, struct contact, next); - if (b->n_contacts + b->n_alts <= dht->k) { - ++c->fails; - return; - } - - if (c->addr == addr) { - list_del(&c->next); - contact_destroy(c); - --b->n_contacts; - break; - } - } - - while (b->n_contacts < dht->k && b->n_alts > 0) { - struct contact * c; - c = list_first_entry(&b->alts, struct contact, next); - list_del(&c->next); - --b->n_alts; - list_add(&c->next, &b->contacts); - ++b->n_contacts; - } -} - -static int dht_del(struct dht * dht, - const uint8_t * key, - uint64_t addr) -{ - struct dht_entry * e; - - pthread_rwlock_wrlock(&dht->lock); - - e = dht_find_entry(dht, key); - if (e == NULL) { - pthread_rwlock_unlock(&dht->lock); - return -EPERM; - } - - dht_entry_del_addr(e, addr); - - pthread_rwlock_unlock(&dht->lock); - - return 0; -} - -static buffer_t dht_retrieve(struct dht * dht, - const uint8_t * key) -{ - struct dht_entry * e; - struct list_head * p; - buffer_t buf; - uint64_t * pos; - size_t addrs = 0; - - pthread_rwlock_rdlock(&dht->lock); - - e = dht_find_entry(dht, key); - if (e == NULL) - goto fail; - - buf.len = MIN(DHT_RETR_ADDR, e->n_vals); - if (buf.len == 0) - goto fail; - - pos = malloc(sizeof(dht->addr) * buf.len); - if (pos == NULL) - goto fail; - - buf.data = (uint8_t *) pos; - - list_for_each(p, &e->vals) { - struct val * v = list_entry(p, struct val, next); - *pos++ = v->addr; - if (++addrs >= buf.len) - break; - } - - pthread_rwlock_unlock(&dht->lock); - - return buf; - - fail: - pthread_rwlock_unlock(&dht->lock); - buf.len = 0; - - return buf; -} - -static ssize_t dht_get_contacts(struct dht * dht, - const uint8_t * key, - kad_contact_msg_t *** msgs) -{ - struct list_head l; - struct list_head * p; - struct list_head * h; - size_t len; - size_t i = 0; - - list_head_init(&l); - - pthread_rwlock_wrlock(&dht->lock); - - len = dht_contact_list(dht, &l, key); - if (len == 0) { - pthread_rwlock_unlock(&dht->lock); - return 0; - } - - *msgs = malloc(len * sizeof(**msgs)); - if (*msgs == NULL) { - pthread_rwlock_unlock(&dht->lock); - return 0; - } - - list_for_each_safe(p, h, &l) { - struct contact * c = list_entry(p, struct contact, next); - (*msgs)[i] = malloc(sizeof(***msgs)); - if ((*msgs)[i] == NULL) { - pthread_rwlock_unlock(&dht->lock); - while (i > 0) - free(*msgs[--i]); - free(*msgs); - return 0; - } - - kad_contact_msg__init((*msgs)[i]); - - (*msgs)[i]->id.data = c->id; - (*msgs)[i]->id.len = dht->b; - (*msgs)[i++]->addr = c->addr; - list_del(&c->next); - free(c); - } - - pthread_rwlock_unlock(&dht->lock); - - return i; -} - -static time_t gcd(time_t a, - time_t b) -{ - if (a == 0) - return b; - - return gcd(b % a, a); -} - -static void * work(void * o) -{ - struct dht * dht; - struct timespec now; - struct list_head * p; - struct list_head * h; - struct list_head reflist; - time_t intv; - struct lookup * lu; - - dht = (struct dht *) o; - - pthread_rwlock_rdlock(&dht->lock); - - intv = gcd(dht->t_expire, dht->t_repub); - intv = gcd(intv, gcd(KAD_T_REPL, KAD_T_REFR)) / 2; - - pthread_rwlock_unlock(&dht->lock); - - list_head_init(&reflist); - - while (true) { - clock_gettime(CLOCK_REALTIME_COARSE, &now); - - pthread_rwlock_wrlock(&dht->lock); - - /* Republish registered hashes. */ - list_for_each(p, &dht->refs) { - struct ref_entry * e; - uint8_t * key; - uint64_t addr; - time_t t_expire; - e = list_entry(p, struct ref_entry, next); - if (now.tv_sec > e->t_rep) { - key = dht_dup_key(e->key, dht->b); - if (key == NULL) - continue; - addr = dht->addr; - t_expire = dht->t_expire; - e->t_rep = now.tv_sec + dht->t_repub; - - pthread_rwlock_unlock(&dht->lock); - kad_publish(dht, key, addr, t_expire); - pthread_rwlock_wrlock(&dht->lock); - free(key); - } - } - - /* Remove stale entries and republish if necessary. */ - list_for_each_safe(p, h, &dht->entries) { - struct list_head * p1; - struct list_head * h1; - struct dht_entry * e; - uint8_t * key; - time_t t_expire; - e = list_entry (p, struct dht_entry, next); - list_for_each_safe(p1, h1, &e->vals) { - struct val * v; - uint64_t addr; - v = list_entry(p1, struct val, next); - if (now.tv_sec > v->t_exp) { - list_del(&v->next); - val_destroy(v); - continue; - } - - if (now.tv_sec > v->t_rep) { - key = dht_dup_key(e->key, dht->b); - addr = v->addr; - t_expire = dht->t_expire = now.tv_sec; - v->t_rep = now.tv_sec + dht->t_replic; - pthread_rwlock_unlock(&dht->lock); - kad_publish(dht, key, addr, t_expire); - pthread_rwlock_wrlock(&dht->lock); - free(key); - } - } - } - - /* Check the requests list for unresponsive nodes. */ - list_for_each_safe(p, h, &dht->requests) { - struct kad_req * r; - r = list_entry(p, struct kad_req, next); - if (now.tv_sec > r->t_exp) { - list_del(&r->next); - bmp_release(dht->cookies, r->cookie); - dht_dead_peer(dht, r->key, r->addr); - kad_req_destroy(r); - } - } - - /* Refresh unaccessed buckets. */ - bucket_refresh(dht, dht->buckets, now.tv_sec, &reflist); - - pthread_rwlock_unlock(&dht->lock); - - list_for_each_safe(p, h, &reflist) { - struct contact * c; - c = list_entry(p, struct contact, next); - lu = kad_lookup(dht, c->id, KAD_FIND_NODE); - if (lu != NULL) - lookup_destroy(lu); - list_del(&c->next); - contact_destroy(c); - } - - sleep(intv); - } - - return (void *) 0; -} - -static int kad_handle_join_resp(struct dht * dht, - struct kad_req * req, - kad_msg_t * msg) -{ - assert(dht); - assert(req); - assert(msg); - - /* We might send version numbers later to warn of updates if needed. */ - if (!(msg->has_alpha && msg->has_b && msg->has_k && msg->has_t_expire && - msg->has_t_refresh && msg->has_t_replicate)) { - log_warn("Join refused by remote."); - return -1; - } - - if (msg->b < sizeof(uint64_t)) { - log_err("Hash sizes less than 8 bytes unsupported."); - return -1; - } - - pthread_rwlock_wrlock(&dht->lock); - - dht->buckets = bucket_create(); - if (dht->buckets == NULL) { - pthread_rwlock_unlock(&dht->lock); - return -1; - } - - /* Likely corrupt packet. The member will refuse, we might here too. */ - if (msg->alpha != KAD_ALPHA || msg->k != KAD_K) - log_warn("Different kademlia parameters detected."); - - if (msg->t_replicate != KAD_T_REPL) - log_warn("Different kademlia replication time detected."); - - if (msg->t_refresh != KAD_T_REFR) - log_warn("Different kademlia refresh time detected."); - - dht->k = msg->k; - dht->b = msg->b; - dht->t_expire = msg->t_expire; - dht->t_repub = MAX(1, dht->t_expire - 10); - - if (pthread_create(&dht->worker, NULL, work, dht)) { - bucket_destroy(dht->buckets); - pthread_rwlock_unlock(&dht->lock); - return -1; - } - - kad_req_respond(req); - - dht_update_bucket(dht, msg->s_id.data, msg->s_addr); - - pthread_rwlock_unlock(&dht->lock); - - log_dbg("Enrollment of DHT completed."); - - return 0; -} - -static int kad_handle_find_resp(struct dht * dht, - struct kad_req * req, - kad_msg_t * msg) -{ - struct lookup * lu; - - assert(dht); - assert(req); - assert(msg); - - pthread_rwlock_rdlock(&dht->lock); - - lu = dht_find_lookup(dht, req->cookie); - if (lu == NULL) { - pthread_rwlock_unlock(&dht->lock); - return -1; - } - - lookup_update(dht, lu, msg); - - pthread_rwlock_unlock(&dht->lock); - - return 0; -} - -static void kad_handle_response(struct dht * dht, - kad_msg_t * msg) -{ - struct kad_req * req; - - assert(dht); - assert(msg); - - pthread_rwlock_wrlock(&dht->lock); - - req = dht_find_request(dht, msg); - if (req == NULL) { - pthread_rwlock_unlock(&dht->lock); - return; - } - - bmp_release(dht->cookies, req->cookie); - list_del(&req->next); - - pthread_rwlock_unlock(&dht->lock); - - switch(req->code) { - case KAD_JOIN: - if (kad_handle_join_resp(dht, req, msg)) - log_err("Enrollment of DHT failed."); - break; - case KAD_FIND_VALUE: - case KAD_FIND_NODE: - if (dht_get_state(dht) != DHT_RUNNING) - break; - kad_handle_find_resp(dht, req, msg); - break; - default: - break; - } - - kad_req_destroy(req); -} - -int dht_bootstrap(struct dht * dht, - size_t b, - time_t t_expire) -{ - assert(dht); - - pthread_rwlock_wrlock(&dht->lock); - - dht->id = create_id(b); - if (dht->id == NULL) - goto fail_id; - - dht->buckets = bucket_create(); - if (dht->buckets == NULL) - goto fail_buckets; - - dht->buckets->depth = 0; - dht->buckets->mask = 0; - - dht->b = b / CHAR_BIT; - dht->t_expire = MAX(2, t_expire); - dht->t_repub = MAX(1, t_expire - 10); - dht->k = KAD_K; - - if (pthread_create(&dht->worker, NULL, work, dht)) - goto fail_pthread_create; - - dht->state = DHT_RUNNING; - - dht_update_bucket(dht, dht->id, dht->addr); - - pthread_rwlock_unlock(&dht->lock); - - return 0; - - fail_pthread_create: - bucket_destroy(dht->buckets); - dht->buckets = NULL; - fail_buckets: - free(dht->id); - dht->id = NULL; - fail_id: - pthread_rwlock_unlock(&dht->lock); - return -1; -} - -static struct ref_entry * ref_entry_get(struct dht * dht, - const uint8_t * key) -{ - struct list_head * p; - - list_for_each(p, &dht->refs) { - struct ref_entry * r = list_entry(p, struct ref_entry, next); - if (!memcmp(key, r->key, dht-> b) ) - return r; - } - - return NULL; -} - -int dht_reg(struct dht * dht, - const uint8_t * key) -{ - struct ref_entry * e; - uint64_t addr; - time_t t_expire; - - assert(dht); - assert(key); - assert(dht->addr != 0); - - if (dht_wait_running(dht)) - return -1; - - pthread_rwlock_wrlock(&dht->lock); - - if (ref_entry_get(dht, key) != NULL) { - log_dbg("Name already registered."); - pthread_rwlock_unlock(&dht->lock); - return 0; - } - - e = ref_entry_create(dht, key); - if (e == NULL) { - pthread_rwlock_unlock(&dht->lock); - return -ENOMEM; - } - - list_add(&e->next, &dht->refs); - - t_expire = dht->t_expire; - addr = dht->addr; - - pthread_rwlock_unlock(&dht->lock); - - kad_publish(dht, key, addr, t_expire); - - return 0; -} - -int dht_unreg(struct dht * dht, - const uint8_t * key) -{ - struct list_head * p; - struct list_head * h; - - assert(dht); - assert(key); - - if (dht_get_state(dht) != DHT_RUNNING) - return -1; - - pthread_rwlock_wrlock(&dht->lock); - - list_for_each_safe(p, h, &dht->refs) { - struct ref_entry * r = list_entry(p, struct ref_entry, next); - if (!memcmp(key, r->key, dht-> b) ) { - list_del(&r->next); - ref_entry_destroy(r); - } - } - - dht_del(dht, key, dht->addr); - - pthread_rwlock_unlock(&dht->lock); - - return 0; -} - -uint64_t dht_query(struct dht * dht, - const uint8_t * key) -{ - struct dht_entry * e; - struct lookup * lu; - uint64_t addrs[KAD_K]; - size_t n; - - addrs[0] = 0; - - if (dht_wait_running(dht)) - return 0; - - pthread_rwlock_rdlock(&dht->lock); - - e = dht_find_entry(dht, key); - if (e != NULL) - addrs[0] = dht_entry_get_addr(dht, e); - - pthread_rwlock_unlock(&dht->lock); - - if (addrs[0] != 0) - return addrs[0]; - - lu = kad_lookup(dht, key, KAD_FIND_VALUE); - if (lu == NULL) - return 0; - - n = lookup_get_addrs(lu, addrs); - if (n == 0) { - lookup_destroy(lu); - return 0; - } - - lookup_destroy(lu); - - /* Current behaviour is anycast and return the first peer address. */ - if (addrs[0] != dht->addr) - return addrs[0]; - - if (n > 1) - return addrs[1]; - - return 0; -} - -static void * dht_handle_packet(void * o) -{ - struct dht * dht = (struct dht *) o; - - assert(dht); - - while (true) { - kad_msg_t * msg; - kad_contact_msg_t ** cmsgs; - kad_msg_t resp_msg = KAD_MSG__INIT; - uint64_t addr; - buffer_t buf; - size_t i; - size_t b; - size_t t_expire; - struct cmd * cmd; - - pthread_mutex_lock(&dht->mtx); - - pthread_cleanup_push((void *)(void *) pthread_mutex_unlock, - &dht->mtx); - - while (list_is_empty(&dht->cmds)) - pthread_cond_wait(&dht->cond, &dht->mtx); - - cmd = list_last_entry(&dht->cmds, struct cmd, next); - list_del(&cmd->next); - - pthread_cleanup_pop(true); - - i = shm_du_buff_tail(cmd->sdb) - shm_du_buff_head(cmd->sdb); - - msg = kad_msg__unpack(NULL, i, shm_du_buff_head(cmd->sdb)); -#ifndef __DHT_TEST__ - ipcp_sdb_release(cmd->sdb); -#endif - free(cmd); - - if (msg == NULL) { - log_err("Failed to unpack message."); - continue; - } - - if (msg->code != KAD_RESPONSE && dht_wait_running(dht)) { - kad_msg__free_unpacked(msg, NULL); - log_dbg("Got a request message when not running."); - continue; - } - - pthread_rwlock_rdlock(&dht->lock); - - b = dht->b; - t_expire = dht->t_expire; - - pthread_rwlock_unlock(&dht->lock); - - if (msg->has_key && msg->key.len != b) { - kad_msg__free_unpacked(msg, NULL); - log_warn("Bad key in message."); - continue; - } - - if (msg->has_s_id && !msg->has_b && msg->s_id.len != b) { - kad_msg__free_unpacked(msg, NULL); - log_warn("Bad source ID in message of type %d.", - msg->code); - continue; - } - - tpm_dec(dht->tpm); - - addr = msg->s_addr; - - resp_msg.code = KAD_RESPONSE; - resp_msg.cookie = msg->cookie; - - switch(msg->code) { - case KAD_JOIN: - /* Refuse enrollee on check fails. */ - if (msg->alpha != KAD_ALPHA || msg->k != KAD_K) { - log_warn("Parameter mismatch. " - "DHT enrolment refused."); - break; - } - - if (msg->t_replicate != KAD_T_REPL) { - log_warn("Replication time mismatch. " - "DHT enrolment refused."); - - break; - } - - if (msg->t_refresh != KAD_T_REFR) { - log_warn("Refresh time mismatch. " - "DHT enrolment refused."); - break; - } - - resp_msg.has_alpha = true; - resp_msg.has_b = true; - resp_msg.has_k = true; - resp_msg.has_t_expire = true; - resp_msg.has_t_refresh = true; - resp_msg.has_t_replicate = true; - resp_msg.alpha = KAD_ALPHA; - resp_msg.b = b; - resp_msg.k = KAD_K; - resp_msg.t_expire = t_expire; - resp_msg.t_refresh = KAD_T_REFR; - resp_msg.t_replicate = KAD_T_REPL; - break; - case KAD_FIND_VALUE: - buf = dht_retrieve(dht, msg->key.data); - if (buf.len != 0) { - resp_msg.n_addrs = buf.len; - resp_msg.addrs = (uint64_t *) buf.data; - break; - } - /* FALLTHRU */ - case KAD_FIND_NODE: - /* Return k closest contacts. */ - resp_msg.n_contacts = - dht_get_contacts(dht, msg->key.data, &cmsgs); - resp_msg.contacts = cmsgs; - break; - case KAD_STORE: - if (msg->n_contacts < 1) { - log_warn("No contacts in store message."); - break; - } - - if (!msg->has_t_expire) { - log_warn("No expiry time in store message."); - break; - } - - kad_add(dht, *msg->contacts, msg->n_contacts, - msg->t_expire); - break; - case KAD_RESPONSE: - kad_handle_response(dht, msg); - break; - default: - assert(false); - break; - } - - if (msg->code != KAD_JOIN) { - pthread_rwlock_wrlock(&dht->lock); - if (dht_get_state(dht) == DHT_JOINING && - dht->buckets == NULL) { - pthread_rwlock_unlock(&dht->lock); - break; - } - - if (dht_update_bucket(dht, msg->s_id.data, addr)) - log_warn("Failed to update bucket."); - pthread_rwlock_unlock(&dht->lock); - } - - if (msg->code < KAD_STORE && send_msg(dht, &resp_msg, addr) < 0) - log_warn("Failed to send response."); - - kad_msg__free_unpacked(msg, NULL); - - if (resp_msg.n_addrs > 0) - free(resp_msg.addrs); - - if (resp_msg.n_contacts == 0) { - tpm_inc(dht->tpm); - continue; - } - - for (i = 0; i < resp_msg.n_contacts; ++i) - kad_contact_msg__free_unpacked(resp_msg.contacts[i], - NULL); - free(resp_msg.contacts); - - tpm_inc(dht->tpm); - } - - return (void *) 0; -} - -static void dht_post_packet(void * comp, - struct shm_du_buff * sdb) -{ - struct cmd * cmd; - struct dht * dht = (struct dht *) comp; - - if (dht_get_state(dht) == DHT_SHUTDOWN) { -#ifndef __DHT_TEST__ - ipcp_sdb_release(sdb); -#endif - return; - } - - cmd = malloc(sizeof(*cmd)); - if (cmd == NULL) { - log_err("Command failed. Out of memory."); - return; - } - - cmd->sdb = sdb; - - pthread_mutex_lock(&dht->mtx); - - list_add(&cmd->next, &dht->cmds); - - pthread_cond_signal(&dht->cond); - - pthread_mutex_unlock(&dht->mtx); -} - -void dht_destroy(struct dht * dht) -{ - struct list_head * p; - struct list_head * h; - - if (dht == NULL) - return; - -#ifndef __DHT_TEST__ - tpm_stop(dht->tpm); - - tpm_destroy(dht->tpm); -#endif - if (dht_get_state(dht) == DHT_RUNNING) { - dht_set_state(dht, DHT_SHUTDOWN); - pthread_cancel(dht->worker); - pthread_join(dht->worker, NULL); - } - - pthread_rwlock_wrlock(&dht->lock); - - list_for_each_safe(p, h, &dht->cmds) { - struct cmd * c = list_entry(p, struct cmd, next); - list_del(&c->next); -#ifndef __DHT_TEST__ - ipcp_sdb_release(c->sdb); -#endif - free(c); - } - - list_for_each_safe(p, h, &dht->entries) { - struct dht_entry * e = list_entry(p, struct dht_entry, next); - list_del(&e->next); - dht_entry_destroy(e); - } - - list_for_each_safe(p, h, &dht->requests) { - struct kad_req * r = list_entry(p, struct kad_req, next); - list_del(&r->next); - kad_req_destroy(r); - } - - list_for_each_safe(p, h, &dht->refs) { - struct ref_entry * e = list_entry(p, struct ref_entry, next); - list_del(&e->next); - ref_entry_destroy(e); - } - - list_for_each_safe(p, h, &dht->lookups) { - struct lookup * l = list_entry(p, struct lookup, next); - list_del(&l->next); - lookup_destroy(l); - } - - pthread_rwlock_unlock(&dht->lock); - - if (dht->buckets != NULL) - bucket_destroy(dht->buckets); - - bmp_destroy(dht->cookies); - - pthread_mutex_destroy(&dht->mtx); - - pthread_rwlock_destroy(&dht->lock); - - free(dht->id); - - free(dht); -} - -static void * join_thr(void * o) -{ - struct join_info * info = (struct join_info *) o; - struct lookup * lu; - size_t retr = 0; - - assert(info); - - while (kad_join(info->dht, info->addr)) { - if (dht_get_state(info->dht) == DHT_SHUTDOWN) { - log_dbg("DHT enrollment aborted."); - goto finish; - } - - if (retr++ == KAD_JOIN_RETR) { - dht_set_state(info->dht, DHT_INIT); - log_warn("DHT enrollment attempt failed."); - goto finish; - } - - sleep(KAD_JOIN_INTV); - } - - dht_set_state(info->dht, DHT_RUNNING); - - lu = kad_lookup(info->dht, info->dht->id, KAD_FIND_NODE); - if (lu != NULL) - lookup_destroy(lu); - - finish: - free(info); - - return (void *) 0; -} - -static void handle_event(void * self, - int event, - const void * o) -{ - struct dht * dht = (struct dht *) self; - - if (event == NOTIFY_DT_CONN_ADD) { - pthread_t thr; - struct join_info * inf; - struct conn * c = (struct conn *) o; - struct timespec slack = {0, DHT_ENROLL_SLACK * MILLION}; - - /* Give the pff some time to update for the new link. */ - nanosleep(&slack, NULL); - - switch(dht_get_state(dht)) { - case DHT_INIT: - inf = malloc(sizeof(*inf)); - if (inf == NULL) - break; - - inf->dht = dht; - inf->addr = c->conn_info.addr; - - if (dht_set_state(dht, DHT_JOINING) == 0 || - dht_wait_running(dht)) { - if (pthread_create(&thr, NULL, join_thr, inf)) { - dht_set_state(dht, DHT_INIT); - free(inf); - return; - } - pthread_detach(thr); - } else { - free(inf); - } - break; - case DHT_RUNNING: - /* - * FIXME: this lookup for effiency reasons - * causes a SEGV when stressed with rapid - * enrollments. - * lu = kad_lookup(dht, dht->id, KAD_FIND_NODE); - * if (lu != NULL) - * lookup_destroy(lu); - */ - break; - default: - break; - } - } -} - -struct dht * dht_create(uint64_t addr) -{ - struct dht * dht; - - dht = malloc(sizeof(*dht)); - if (dht == NULL) - goto fail_malloc; - - dht->buckets = NULL; - - list_head_init(&dht->entries); - list_head_init(&dht->requests); - list_head_init(&dht->refs); - list_head_init(&dht->lookups); - list_head_init(&dht->cmds); - - if (pthread_rwlock_init(&dht->lock, NULL)) - goto fail_rwlock; - - if (pthread_mutex_init(&dht->mtx, NULL)) - goto fail_mutex; - - if (pthread_cond_init(&dht->cond, NULL)) - goto fail_cond; - - dht->cookies = bmp_create(DHT_MAX_REQS, 1); - if (dht->cookies == NULL) - goto fail_bmp; - - dht->b = 0; - dht->addr = addr; - dht->id = NULL; -#ifndef __DHT_TEST__ - dht->tpm = tpm_create(2, 1, dht_handle_packet, dht); - if (dht->tpm == NULL) - goto fail_tpm_create; - - if (tpm_start(dht->tpm)) - goto fail_tpm_start; - - dht->fd = dt_reg_comp(dht, &dht_post_packet, DHT); - notifier_reg(handle_event, dht); -#else - (void) handle_event; - (void) dht_handle_packet; - (void) dht_post_packet; -#endif - dht->state = DHT_INIT; - - return dht; -#ifndef __DHT_TEST__ - fail_tpm_start: - tpm_destroy(dht->tpm); - fail_tpm_create: - bmp_destroy(dht->cookies); -#endif - fail_bmp: - pthread_cond_destroy(&dht->cond); - fail_cond: - pthread_mutex_destroy(&dht->mtx); - fail_mutex: - pthread_rwlock_destroy(&dht->lock); - fail_rwlock: - free(dht); - fail_malloc: - return NULL; -} diff --git a/src/ipcpd/normal/dht.h b/src/ipcpd/normal/dht.h deleted file mode 100644 index 519b29d4..00000000 --- a/src/ipcpd/normal/dht.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Distributed Hash Table based on Kademlia - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * version 2.1 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_DHT_H -#define OUROBOROS_IPCPD_NORMAL_DHT_H - -#include <ouroboros/ipcp-dev.h> - -#include <stdint.h> -#include <sys/types.h> - -struct dht; - -struct dht * dht_create(uint64_t addr); - -int dht_bootstrap(struct dht * dht, - size_t b, - time_t t_expire); - -void dht_destroy(struct dht * dht); - -int dht_reg(struct dht * dht, - const uint8_t * key); - -int dht_unreg(struct dht * dht, - const uint8_t * key); - -uint64_t dht_query(struct dht * dht, - const uint8_t * key); - -int dht_wait_running(struct dht * dht); - -#endif /* OUROBOROS_IPCPD_NORMAL_DHT_H */ diff --git a/src/ipcpd/normal/dir.c b/src/ipcpd/normal/dir.c deleted file mode 100644 index 3b0446fa..00000000 --- a/src/ipcpd/normal/dir.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Directory - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#if defined(__linux__) || defined(__CYGWIN__) -#define _DEFAULT_SOURCE -#else -#define _POSIX_C_SOURCE 200112L -#endif - -#define OUROBOROS_PREFIX "directory" - -#include <ouroboros/endian.h> -#include <ouroboros/errno.h> -#include <ouroboros/logs.h> -#include <ouroboros/utils.h> - -#include "dir.h" -#include "dht.h" -#include "ipcp.h" - -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <inttypes.h> -#include <limits.h> - -#define KAD_B (hash_len(ipcpi.dir_hash_algo) * CHAR_BIT) - -struct dht * dht; - -int dir_init(void) -{ - dht = dht_create(ipcpi.dt_addr); - if (dht == NULL) - return -ENOMEM; - - return 0; -} - -void dir_fini(void) -{ - dht_destroy(dht); -} - -int dir_bootstrap(void) { - log_dbg("Bootstrapping directory."); - - /* TODO: get parameters for bootstrap from IRM tool. */ - if (dht_bootstrap(dht, KAD_B, 86400)) { - dht_destroy(dht); - return -ENOMEM; - } - - log_info("Directory bootstrapped."); - - return 0; -} - -int dir_reg(const uint8_t * hash) -{ - return dht_reg(dht, hash); -} - -int dir_unreg(const uint8_t * hash) -{ - return dht_unreg(dht, hash); -} - -uint64_t dir_query(const uint8_t * hash) -{ - return dht_query(dht, hash); -} - -int dir_wait_running(void) -{ - if (dht_wait_running(dht)) { - log_warn("Directory did not bootstrap."); - return -1; - } - - return 0; -} diff --git a/src/ipcpd/normal/dir.h b/src/ipcpd/normal/dir.h deleted file mode 100644 index 78e82e33..00000000 --- a/src/ipcpd/normal/dir.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Directory - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_DIR_H -#define OUROBOROS_IPCPD_NORMAL_DIR_H - -int dir_init(void); - -void dir_fini(void); - -int dir_bootstrap(void); - -int dir_reg(const uint8_t * hash); - -int dir_unreg(const uint8_t * hash); - -uint64_t dir_query(const uint8_t * hash); - -int dir_wait_running(void); - -#endif /* OUROBOROS_IPCPD_NORMAL_DIR_H */ diff --git a/src/ipcpd/normal/dt.c b/src/ipcpd/normal/dt.c deleted file mode 100644 index 2fd3c060..00000000 --- a/src/ipcpd/normal/dt.c +++ /dev/null @@ -1,913 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Data Transfer Component - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#if defined(__linux__) || defined(__CYGWIN__) -#define _DEFAULT_SOURCE -#else -#define _POSIX_C_SOURCE 200112L -#endif - -#include "config.h" - -#define DT "dt" -#define OUROBOROS_PREFIX DT - -#include <ouroboros/bitmap.h> -#include <ouroboros/errno.h> -#include <ouroboros/logs.h> -#include <ouroboros/dev.h> -#include <ouroboros/notifier.h> -#include <ouroboros/rib.h> -#ifdef IPCP_FLOW_STATS -#include <ouroboros/fccntl.h> -#endif - -#include "connmgr.h" -#include "ipcp.h" -#include "dt.h" -#include "pff.h" -#include "routing.h" -#include "psched.h" -#include "comp.h" -#include "fa.h" - -#include <stdlib.h> -#include <stdbool.h> -#include <pthread.h> -#include <string.h> -#include <inttypes.h> -#include <assert.h> - -#define QOS_BLOCK_LEN 672 -#define STAT_FILE_LEN (189 + QOS_BLOCK_LEN * QOS_CUBE_MAX) - -#ifndef CLOCK_REALTIME_COARSE -#define CLOCK_REALTIME_COARSE CLOCK_REALTIME -#endif - -struct comp_info { - void (* post_packet)(void * comp, struct shm_du_buff * sdb); - void * comp; - char * name; -}; - -/* Fixed field lengths */ -#define TTL_LEN 1 -#define QOS_LEN 1 -#define ECN_LEN 1 - -struct dt_pci { - uint64_t dst_addr; - qoscube_t qc; - uint8_t ttl; - uint8_t ecn; - uint32_t eid; -}; - -struct { - uint8_t addr_size; - uint8_t eid_size; - size_t head_size; - - /* Offsets */ - size_t qc_o; - size_t ttl_o; - size_t ecn_o; - size_t eid_o; - - /* Initial TTL value */ - uint8_t max_ttl; -} dt_pci_info; - -static int dt_pci_ser(struct shm_du_buff * sdb, - struct dt_pci * dt_pci) -{ - uint8_t * head; - uint8_t ttl = dt_pci_info.max_ttl; - - assert(sdb); - assert(dt_pci); - - head = shm_du_buff_head_alloc(sdb, dt_pci_info.head_size); - if (head == NULL) - return -EPERM; - - /* FIXME: Add check and operations for Big Endian machines. */ - memcpy(head, &dt_pci->dst_addr, dt_pci_info.addr_size); - memcpy(head + dt_pci_info.qc_o, &dt_pci->qc, QOS_LEN); - memcpy(head + dt_pci_info.ttl_o, &ttl, TTL_LEN); - memcpy(head + dt_pci_info.ecn_o, &dt_pci->ecn, ECN_LEN); - memcpy(head + dt_pci_info.eid_o, &dt_pci->eid, dt_pci_info.eid_size); - - return 0; -} - -static void dt_pci_des(struct shm_du_buff * sdb, - struct dt_pci * dt_pci) -{ - uint8_t * head; - - assert(sdb); - assert(dt_pci); - - head = shm_du_buff_head(sdb); - - /* Decrease TTL */ - --*(head + dt_pci_info.ttl_o); - - /* FIXME: Add check and operations for Big Endian machines. */ - memcpy(&dt_pci->dst_addr, head, dt_pci_info.addr_size); - memcpy(&dt_pci->qc, head + dt_pci_info.qc_o, QOS_LEN); - memcpy(&dt_pci->ttl, head + dt_pci_info.ttl_o, TTL_LEN); - memcpy(&dt_pci->ecn, head + dt_pci_info.ecn_o, ECN_LEN); - memcpy(&dt_pci->eid, head + dt_pci_info.eid_o, dt_pci_info.eid_size); -} - -static void dt_pci_shrink(struct shm_du_buff * sdb) -{ - assert(sdb); - - shm_du_buff_head_release(sdb, dt_pci_info.head_size); -} - -struct { - struct psched * psched; - - struct pff * pff[QOS_CUBE_MAX]; - struct routing_i * routing[QOS_CUBE_MAX]; -#ifdef IPCP_FLOW_STATS - struct { - time_t stamp; - uint64_t addr; - size_t snd_pkt[QOS_CUBE_MAX]; - size_t rcv_pkt[QOS_CUBE_MAX]; - size_t snd_bytes[QOS_CUBE_MAX]; - size_t rcv_bytes[QOS_CUBE_MAX]; - size_t lcl_r_pkt[QOS_CUBE_MAX]; - size_t lcl_r_bytes[QOS_CUBE_MAX]; - size_t lcl_w_pkt[QOS_CUBE_MAX]; - size_t lcl_w_bytes[QOS_CUBE_MAX]; - size_t r_drp_pkt[QOS_CUBE_MAX]; - size_t r_drp_bytes[QOS_CUBE_MAX]; - size_t w_drp_pkt[QOS_CUBE_MAX]; - size_t w_drp_bytes[QOS_CUBE_MAX]; - size_t f_nhp_pkt[QOS_CUBE_MAX]; - size_t f_nhp_bytes[QOS_CUBE_MAX]; - pthread_mutex_t lock; - } stat[PROG_MAX_FLOWS]; - - size_t n_flows; -#endif - struct bmp * res_fds; - struct comp_info comps[PROG_RES_FDS]; - pthread_rwlock_t lock; - - pthread_t listener; -} dt; - -static int dt_stat_read(const char * path, - char * buf, - size_t len) -{ -#ifdef IPCP_FLOW_STATS - int fd; - int i; - char str[QOS_BLOCK_LEN + 1]; - char addrstr[20]; - char tmstr[20]; - size_t rxqlen = 0; - size_t txqlen = 0; - struct tm * tm; - - /* NOTE: we may need stronger checks. */ - fd = atoi(path); - - if (len < STAT_FILE_LEN) - return 0; - - buf[0] = '\0'; - - pthread_mutex_lock(&dt.stat[fd].lock); - - if (dt.stat[fd].stamp == 0) { - pthread_mutex_unlock(&dt.stat[fd].lock); - return 0; - } - - if (dt.stat[fd].addr == ipcpi.dt_addr) - sprintf(addrstr, "%s", dt.comps[fd].name); - else - sprintf(addrstr, "%" PRIu64, dt.stat[fd].addr); - - tm = localtime(&dt.stat[fd].stamp); - strftime(tmstr, sizeof(tmstr), "%F %T", tm); - - if (fd >= PROG_RES_FDS) { - fccntl(fd, FLOWGRXQLEN, &rxqlen); - fccntl(fd, FLOWGTXQLEN, &txqlen); - } - - sprintf(buf, - "Flow established at: %20s\n" - "Endpoint address: %20s\n" - "Queued packets (rx): %20zu\n" - "Queued packets (tx): %20zu\n\n", - tmstr, addrstr, rxqlen, txqlen); - - for (i = 0; i < QOS_CUBE_MAX; ++i) { - sprintf(str, - "Qos cube %3d:\n" - " sent (packets): %20zu\n" - " sent (bytes): %20zu\n" - " rcvd (packets): %20zu\n" - " rcvd (bytes): %20zu\n" - " local sent (packets): %20zu\n" - " local sent (bytes): %20zu\n" - " local rcvd (packets): %20zu\n" - " local rcvd (bytes): %20zu\n" - " dropped ttl (packets): %20zu\n" - " dropped ttl (bytes): %20zu\n" - " failed writes (packets): %20zu\n" - " failed writes (bytes): %20zu\n" - " failed nhop (packets): %20zu\n" - " failed nhop (bytes): %20zu\n", - i, - dt.stat[fd].snd_pkt[i], - dt.stat[fd].snd_bytes[i], - dt.stat[fd].rcv_pkt[i], - dt.stat[fd].rcv_bytes[i], - dt.stat[fd].lcl_w_pkt[i], - dt.stat[fd].lcl_w_bytes[i], - dt.stat[fd].lcl_r_pkt[i], - dt.stat[fd].lcl_r_bytes[i], - dt.stat[fd].r_drp_pkt[i], - dt.stat[fd].r_drp_bytes[i], - dt.stat[fd].w_drp_pkt[i], - dt.stat[fd].w_drp_bytes[i], - dt.stat[fd].f_nhp_pkt[i], - dt.stat[fd].f_nhp_bytes[i] - ); - strcat(buf, str); - } - - pthread_mutex_unlock(&dt.stat[fd].lock); - - return STAT_FILE_LEN; -#else - (void) path; - (void) buf; - (void) len; - return 0; -#endif -} - -static int dt_stat_readdir(char *** buf) -{ -#ifdef IPCP_FLOW_STATS - char entry[RIB_PATH_LEN + 1]; - size_t i; - int idx = 0; - - pthread_rwlock_rdlock(&dt.lock); - - if (dt.n_flows < 1) { - pthread_rwlock_unlock(&dt.lock); - return 0; - } - - *buf = malloc(sizeof(**buf) * dt.n_flows); - if (*buf == NULL) { - pthread_rwlock_unlock(&dt.lock); - return -ENOMEM; - } - - for (i = 0; i < PROG_MAX_FLOWS; ++i) { - pthread_mutex_lock(&dt.stat[i].lock); - - if (dt.stat[i].stamp == 0) { - pthread_mutex_unlock(&dt.stat[i].lock); - /* Optimization: skip unused res_fds. */ - if (i < PROG_RES_FDS) - i = PROG_RES_FDS; - continue; - } - - sprintf(entry, "%zu", i); - - (*buf)[idx] = malloc(strlen(entry) + 1); - if ((*buf)[idx] == NULL) { - while (idx-- > 0) - free((*buf)[idx]); - free(buf); - pthread_mutex_unlock(&dt.stat[i].lock); - pthread_rwlock_unlock(&dt.lock); - return -ENOMEM; - } - - strcpy((*buf)[idx++], entry); - - pthread_mutex_unlock(&dt.stat[i].lock); - } - - pthread_rwlock_unlock(&dt.lock); - - assert((size_t) idx == dt.n_flows); - - return idx; -#else - (void) buf; - return 0; -#endif -} - -static int dt_stat_getattr(const char * path, - struct stat * st) -{ -#ifdef IPCP_FLOW_STATS - int fd; - - fd = atoi(path); - - st->st_mode = S_IFREG | 0755; - st->st_nlink = 1; - st->st_uid = getuid(); - st->st_gid = getgid(); - - pthread_mutex_lock(&dt.stat[fd].lock); - - if (dt.stat[fd].stamp != -1) { - st->st_size = STAT_FILE_LEN; - st->st_mtime = dt.stat[fd].stamp; - } else { - st->st_size = 0; - st->st_mtime = 0; - } - - pthread_mutex_unlock(&dt.stat[fd].lock); -#else - (void) path; - (void) st; -#endif - return 0; -} - -static struct rib_ops r_ops = { - .read = dt_stat_read, - .readdir = dt_stat_readdir, - .getattr = dt_stat_getattr -}; - -#ifdef IPCP_FLOW_STATS - -static void stat_used(int fd, - uint64_t addr) -{ - struct timespec now; - - clock_gettime(CLOCK_REALTIME_COARSE, &now); - - pthread_mutex_lock(&dt.stat[fd].lock); - - memset(&dt.stat[fd], 0, sizeof(dt.stat[fd])); - - dt.stat[fd].stamp = (addr != INVALID_ADDR) ? now.tv_sec : 0; - dt.stat[fd].addr = addr; - - pthread_mutex_unlock(&dt.stat[fd].lock); - - pthread_rwlock_wrlock(&dt.lock); - - (addr != INVALID_ADDR) ? ++dt.n_flows : --dt.n_flows; - - pthread_rwlock_unlock(&dt.lock); -} -#endif - -static void handle_event(void * self, - int event, - const void * o) -{ - struct conn * c; - - (void) self; - - c = (struct conn *) o; - - switch (event) { - case NOTIFY_DT_CONN_ADD: -#ifdef IPCP_FLOW_STATS - stat_used(c->flow_info.fd, c->conn_info.addr); -#endif - psched_add(dt.psched, c->flow_info.fd); - log_dbg("Added fd %d to packet scheduler.", c->flow_info.fd); - break; - case NOTIFY_DT_CONN_DEL: -#ifdef IPCP_FLOW_STATS - stat_used(c->flow_info.fd, INVALID_ADDR); -#endif - psched_del(dt.psched, c->flow_info.fd); - log_dbg("Removed fd %d from " - "packet scheduler.", c->flow_info.fd); - break; - default: - break; - } -} - -static void packet_handler(int fd, - qoscube_t qc, - struct shm_du_buff * sdb) -{ - struct dt_pci dt_pci; - int ret; - int ofd; -#ifdef IPCP_FLOW_STATS - size_t len; -#else - (void) fd; -#endif - -#ifdef IPCP_FLOW_STATS - len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb); -#endif - memset(&dt_pci, 0, sizeof(dt_pci)); - dt_pci_des(sdb, &dt_pci); - if (dt_pci.dst_addr != ipcpi.dt_addr) { - if (dt_pci.ttl == 0) { - log_dbg("TTL was zero."); - ipcp_sdb_release(sdb); -#ifdef IPCP_FLOW_STATS - pthread_mutex_lock(&dt.stat[fd].lock); - - ++dt.stat[fd].rcv_pkt[qc]; - dt.stat[fd].rcv_bytes[qc] += len; - ++dt.stat[fd].r_drp_pkt[qc]; - dt.stat[fd].r_drp_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[fd].lock); -#endif - return; - } - - /* FIXME: Use qoscube from PCI instead of incoming flow. */ - ofd = pff_nhop(dt.pff[qc], dt_pci.dst_addr); - if (ofd < 0) { - log_dbg("No next hop for %" PRIu64, dt_pci.dst_addr); - ipcp_sdb_release(sdb); -#ifdef IPCP_FLOW_STATS - pthread_mutex_lock(&dt.stat[fd].lock); - - ++dt.stat[fd].rcv_pkt[qc]; - dt.stat[fd].rcv_bytes[qc] += len; - ++dt.stat[fd].f_nhp_pkt[qc]; - dt.stat[fd].f_nhp_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[fd].lock); -#endif - return; - } - - ret = ipcp_flow_write(ofd, sdb); - if (ret < 0) { - log_dbg("Failed to write packet to fd %d.", ofd); - if (ret == -EFLOWDOWN) - notifier_event(NOTIFY_DT_FLOW_DOWN, &ofd); - ipcp_sdb_release(sdb); -#ifdef IPCP_FLOW_STATS - pthread_mutex_lock(&dt.stat[fd].lock); - - ++dt.stat[fd].rcv_pkt[qc]; - dt.stat[fd].rcv_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[fd].lock); - pthread_mutex_lock(&dt.stat[ofd].lock); - - ++dt.stat[ofd].w_drp_pkt[qc]; - dt.stat[ofd].w_drp_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[ofd].lock); -#endif - return; - } -#ifdef IPCP_FLOW_STATS - pthread_mutex_lock(&dt.stat[fd].lock); - - ++dt.stat[fd].rcv_pkt[qc]; - dt.stat[fd].rcv_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[fd].lock); - pthread_mutex_lock(&dt.stat[ofd].lock); - - ++dt.stat[ofd].snd_pkt[qc]; - dt.stat[ofd].snd_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[ofd].lock); -#endif - } else { - dt_pci_shrink(sdb); - if (dt_pci.eid >= PROG_RES_FDS) { - if (ipcp_flow_write(dt_pci.eid, sdb)) { - ipcp_sdb_release(sdb); -#ifdef IPCP_FLOW_STATS - pthread_mutex_lock(&dt.stat[fd].lock); - ++dt.stat[fd].rcv_pkt[qc]; - dt.stat[fd].rcv_bytes[qc] += len; - pthread_mutex_unlock(&dt.stat[fd].lock); - - pthread_mutex_lock(&dt.stat[dt_pci.eid].lock); - ++dt.stat[dt_pci.eid].w_drp_pkt[qc]; - dt.stat[dt_pci.eid].w_drp_bytes[qc] += len; - pthread_mutex_unlock(&dt.stat[dt_pci.eid].lock); -#endif - - } -#ifdef IPCP_FLOW_STATS - pthread_mutex_lock(&dt.stat[fd].lock); - - ++dt.stat[fd].rcv_pkt[qc]; - dt.stat[fd].rcv_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[fd].lock); - pthread_mutex_lock(&dt.stat[dt_pci.eid].lock); - - ++dt.stat[dt_pci.eid].rcv_pkt[qc]; - dt.stat[dt_pci.eid].rcv_bytes[qc] += len; - ++dt.stat[dt_pci.eid].lcl_r_pkt[qc]; - dt.stat[dt_pci.eid].lcl_r_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[dt_pci.eid].lock); -#endif - return; - } - - if (dt.comps[dt_pci.eid].post_packet == NULL) { - log_err("No registered component on eid %d.", - dt_pci.eid); - ipcp_sdb_release(sdb); -#ifdef IPCP_FLOW_STATS - pthread_mutex_lock(&dt.stat[fd].lock); - - ++dt.stat[fd].rcv_pkt[qc]; - dt.stat[fd].rcv_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[fd].lock); - pthread_mutex_lock(&dt.stat[dt_pci.eid].lock); - - ++dt.stat[dt_pci.eid].w_drp_pkt[qc]; - dt.stat[dt_pci.eid].w_drp_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[dt_pci.eid].lock); -#endif - return; - } -#ifdef IPCP_FLOW_STATS - pthread_mutex_lock(&dt.stat[fd].lock); - - ++dt.stat[fd].rcv_pkt[qc]; - dt.stat[fd].rcv_bytes[qc] += len; - ++dt.stat[fd].lcl_r_pkt[qc]; - dt.stat[fd].lcl_r_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[fd].lock); - pthread_mutex_lock(&dt.stat[dt_pci.eid].lock); - - ++dt.stat[dt_pci.eid].snd_pkt[qc]; - dt.stat[dt_pci.eid].snd_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[dt_pci.eid].lock); -#endif - dt.comps[dt_pci.eid].post_packet(dt.comps[dt_pci.eid].comp, - sdb); - } -} - -static void * dt_conn_handle(void * o) -{ - struct conn conn; - - (void) o; - - while (true) { - if (connmgr_wait(COMPID_DT, &conn)) { - log_err("Failed to get next DT connection."); - continue; - } - - /* NOTE: connection acceptance policy could be here. */ - - notifier_event(NOTIFY_DT_CONN_ADD, &conn); - } - - return 0; -} - -int dt_init(enum pol_routing pr, - enum pol_pff pp, - uint8_t addr_size, - uint8_t eid_size, - uint8_t max_ttl) -{ - int i; - int j; - char dtstr[256]; - struct conn_info info; - - memset(&info, 0, sizeof(info)); - - strcpy(info.comp_name, DT_COMP); - strcpy(info.protocol, DT_PROTO); - info.pref_version = 1; - info.pref_syntax = PROTO_FIXED; - info.addr = ipcpi.dt_addr; - - dt_pci_info.addr_size = addr_size; - dt_pci_info.eid_size = eid_size; - dt_pci_info.max_ttl = max_ttl; - - dt_pci_info.qc_o = dt_pci_info.addr_size; - dt_pci_info.ttl_o = dt_pci_info.qc_o + QOS_LEN; - dt_pci_info.ecn_o = dt_pci_info.ttl_o + TTL_LEN; - dt_pci_info.eid_o = dt_pci_info.ecn_o + ECN_LEN; - dt_pci_info.head_size = dt_pci_info.eid_o + dt_pci_info.eid_size; - - if (notifier_reg(handle_event, NULL)) { - log_err("Failed to register with notifier."); - goto fail_notifier_reg; - } - - if (connmgr_comp_init(COMPID_DT, &info)) { - log_err("Failed to register with connmgr."); - goto fail_connmgr_comp_init; - } - - if (routing_init(pr)) { - log_err("Failed to init routing."); - goto fail_routing; - } - - for (i = 0; i < QOS_CUBE_MAX; ++i) { - dt.pff[i] = pff_create(pp); - if (dt.pff[i] == NULL) { - log_err("Failed to create a PFF."); - for (j = 0; j < i; ++j) - pff_destroy(dt.pff[j]); - goto fail_pff; - } - } - - for (i = 0; i < QOS_CUBE_MAX; ++i) { - dt.routing[i] = routing_i_create(dt.pff[i]); - if (dt.routing[i] == NULL) { - for (j = 0; j < i; ++j) - routing_i_destroy(dt.routing[j]); - goto fail_routing_i; - } - } - - if (pthread_rwlock_init(&dt.lock, NULL)) { - log_err("Failed to init rwlock."); - goto fail_rwlock_init; - } - - dt.res_fds = bmp_create(PROG_RES_FDS, 0); - if (dt.res_fds == NULL) - goto fail_res_fds; -#ifdef IPCP_FLOW_STATS - memset(dt.stat, 0, sizeof(dt.stat)); - - for (i = 0; i < PROG_MAX_FLOWS; ++i) - if (pthread_mutex_init(&dt.stat[i].lock, NULL)) { - for (j = 0; j < i; ++j) - pthread_mutex_destroy(&dt.stat[j].lock); - goto fail_stat_lock; - } - - dt.n_flows = 0; -#endif - sprintf(dtstr, "%s.%" PRIu64, DT, ipcpi.dt_addr); - if (rib_reg(dtstr, &r_ops)) - goto fail_rib_reg; - - return 0; - - fail_rib_reg: -#ifdef IPCP_FLOW_STATS - for (i = 0; i < PROG_MAX_FLOWS; ++i) - pthread_mutex_destroy(&dt.stat[i].lock); - fail_stat_lock: -#endif - bmp_destroy(dt.res_fds); - fail_res_fds: - pthread_rwlock_destroy(&dt.lock); - fail_rwlock_init: - for (j = 0; j < QOS_CUBE_MAX; ++j) - routing_i_destroy(dt.routing[j]); - fail_routing_i: - for (i = 0; i < QOS_CUBE_MAX; ++i) - pff_destroy(dt.pff[i]); - fail_pff: - routing_fini(); - fail_routing: - connmgr_comp_fini(COMPID_DT); - fail_connmgr_comp_init: - notifier_unreg(&handle_event); - fail_notifier_reg: - return -1; -} - -void dt_fini(void) -{ - int i; - - rib_unreg(DT); -#ifdef IPCP_FLOW_STATS - for (i = 0; i < PROG_MAX_FLOWS; ++i) - pthread_mutex_destroy(&dt.stat[i].lock); -#endif - bmp_destroy(dt.res_fds); - - pthread_rwlock_destroy(&dt.lock); - - for (i = 0; i < QOS_CUBE_MAX; ++i) - routing_i_destroy(dt.routing[i]); - - for (i = 0; i < QOS_CUBE_MAX; ++i) - pff_destroy(dt.pff[i]); - - routing_fini(); - - connmgr_comp_fini(COMPID_DT); - - notifier_unreg(&handle_event); -} - -int dt_start(void) -{ - dt.psched = psched_create(packet_handler); - if (dt.psched == NULL) { - log_err("Failed to create N-1 packet scheduler."); - return -1; - } - - if (pthread_create(&dt.listener, NULL, dt_conn_handle, NULL)) { - log_err("Failed to create listener thread."); - psched_destroy(dt.psched); - return -1; - } - - return 0; -} - -void dt_stop(void) -{ - pthread_cancel(dt.listener); - pthread_join(dt.listener, NULL); - psched_destroy(dt.psched); -} - -int dt_reg_comp(void * comp, - void (* func)(void * func, struct shm_du_buff *), - char * name) -{ - int res_fd; - - assert(func); - - pthread_rwlock_wrlock(&dt.lock); - - res_fd = bmp_allocate(dt.res_fds); - if (!bmp_is_id_valid(dt.res_fds, res_fd)) { - log_warn("Reserved fds depleted."); - pthread_rwlock_unlock(&dt.lock); - return -EBADF; - } - - assert(dt.comps[res_fd].post_packet == NULL); - assert(dt.comps[res_fd].comp == NULL); - assert(dt.comps[res_fd].name == NULL); - - dt.comps[res_fd].post_packet = func; - dt.comps[res_fd].comp = comp; - dt.comps[res_fd].name = name; - - pthread_rwlock_unlock(&dt.lock); -#ifdef IPCP_FLOW_STATS - stat_used(res_fd, ipcpi.dt_addr); -#endif - return res_fd; -} - -int dt_write_packet(uint64_t dst_addr, - qoscube_t qc, - int np1_fd, - struct shm_du_buff * sdb) -{ - int fd; - struct dt_pci dt_pci; - int ret; -#ifdef IPCP_FLOW_STATS - size_t len; -#endif - assert(sdb); - assert(dst_addr != ipcpi.dt_addr); - - fd = pff_nhop(dt.pff[qc], dst_addr); - if (fd < 0) { - log_dbg("Could not get nhop for addr %" PRIu64 ".", dst_addr); -#ifdef IPCP_FLOW_STATS - len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb); - - pthread_mutex_lock(&dt.stat[np1_fd].lock); - - ++dt.stat[np1_fd].lcl_r_pkt[qc]; - dt.stat[np1_fd].lcl_r_bytes[qc] += len; - ++dt.stat[np1_fd].f_nhp_pkt[qc]; - dt.stat[np1_fd].f_nhp_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[np1_fd].lock); -#endif - return -1; - } - - dt_pci.dst_addr = dst_addr; - dt_pci.qc = qc; - dt_pci.eid = np1_fd; - dt_pci.ecn = 0; - - if (dt_pci_ser(sdb, &dt_pci)) { - log_dbg("Failed to serialize PDU."); -#ifdef IPCP_FLOW_STATS - len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb); -#endif - goto fail_write; - } -#ifdef IPCP_FLOW_STATS - len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb); -#endif - ret = ipcp_flow_write(fd, sdb); - if (ret < 0) { - log_dbg("Failed to write packet to fd %d.", fd); - if (ret == -EFLOWDOWN) - notifier_event(NOTIFY_DT_FLOW_DOWN, &fd); - goto fail_write; - } -#ifdef IPCP_FLOW_STATS - pthread_mutex_lock(&dt.stat[np1_fd].lock); - - ++dt.stat[np1_fd].lcl_r_pkt[qc]; - dt.stat[np1_fd].lcl_r_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[np1_fd].lock); - pthread_mutex_lock(&dt.stat[fd].lock); - - if (dt_pci.eid < PROG_RES_FDS) { - ++dt.stat[fd].lcl_w_pkt[qc]; - dt.stat[fd].lcl_w_bytes[qc] += len; - } - ++dt.stat[fd].snd_pkt[qc]; - dt.stat[fd].snd_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[fd].lock); -#endif - return 0; - - fail_write: -#ifdef IPCP_FLOW_STATS - pthread_mutex_lock(&dt.stat[np1_fd].lock); - - ++dt.stat[np1_fd].lcl_w_pkt[qc]; - dt.stat[np1_fd].lcl_w_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[np1_fd].lock); - pthread_mutex_lock(&dt.stat[fd].lock); - - if (dt_pci.eid < PROG_RES_FDS) { - ++dt.stat[fd].lcl_w_pkt[qc]; - dt.stat[fd].lcl_w_bytes[qc] += len; - } - ++dt.stat[fd].w_drp_pkt[qc]; - dt.stat[fd].w_drp_bytes[qc] += len; - - pthread_mutex_unlock(&dt.stat[fd].lock); -#endif - return -1; -} diff --git a/src/ipcpd/normal/dt.h b/src/ipcpd/normal/dt.h deleted file mode 100644 index 89610471..00000000 --- a/src/ipcpd/normal/dt.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Data Transfer component - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_DT_H -#define OUROBOROS_IPCPD_NORMAL_DT_H - -#include <ouroboros/ipcp.h> -#include <ouroboros/qoscube.h> -#include <ouroboros/shm_rdrbuff.h> - -#define DT_COMP "Data Transfer" -#define DT_PROTO "dtp" -#define INVALID_ADDR 0 - -int dt_init(enum pol_routing pr, - enum pol_pff pp, - uint8_t addr_size, - uint8_t eid_size, - uint8_t max_ttl -); - -void dt_fini(void); - -int dt_start(void); - -void dt_stop(void); - -int dt_reg_comp(void * comp, - void (* func)(void * comp, struct shm_du_buff * sdb), - char * name); - -int dt_write_packet(uint64_t dst_addr, - qoscube_t qc, - int res_fd, - struct shm_du_buff * sdb); - -#endif /* OUROBOROS_IPCPD_NORMAL_DT_H */ diff --git a/src/ipcpd/normal/enroll.c b/src/ipcpd/normal/enroll.c deleted file mode 100644 index b572f89d..00000000 --- a/src/ipcpd/normal/enroll.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Enrollment Task - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#if defined(__linux__) || defined(__CYGWIN__) -#define _DEFAULT_SOURCE -#else -#define _POSIX_C_SOURCE 199309L -#endif - -#define OUROBOROS_PREFIX "enrollment" - -#include <ouroboros/endian.h> -#include <ouroboros/errno.h> -#include <ouroboros/time_utils.h> -#include <ouroboros/dev.h> -#include <ouroboros/logs.h> -#include <ouroboros/errno.h> -#include <ouroboros/sockets.h> - -#include "connmgr.h" -#include "enroll.h" -#include "ipcp.h" - -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include <pthread.h> - -#include "ipcp_config.pb-c.h" -typedef EnrollMsg enroll_msg_t; - -#define ENROLL_COMP "Enrollment" -#define ENROLL_PROTO "OEP" /* Ouroboros enrollment protocol */ -#define ENROLL_WARN_TIME_OFFSET 20 -#define ENROLL_BUF_LEN 1024 - -enum enroll_state { - ENROLL_NULL = 0, - ENROLL_INIT, - ENROLL_RUNNING -}; - -struct { - struct ipcp_config conf; - enum enroll_state state; - pthread_t listener; -} enroll; - -static int send_rcv_enroll_msg(int fd) -{ - enroll_msg_t req = ENROLL_MSG__INIT; - enroll_msg_t * reply; - uint8_t buf[ENROLL_BUF_LEN]; - ssize_t len; - ssize_t delta_t; - struct timespec t0; - struct timespec rtt; - - req.code = ENROLL_CODE__ENROLL_REQ; - - len = enroll_msg__get_packed_size(&req); - if (len < 0) { - log_dbg("Failed pack request message."); - return -1; - } - - enroll_msg__pack(&req, buf); - - clock_gettime(CLOCK_REALTIME, &t0); - - if (flow_write(fd, buf, len)) { - log_dbg("Failed to send request message."); - return -1; - } - - len = flow_read(fd, buf, ENROLL_BUF_LEN); - if (len < 0) { - log_dbg("No enrollment reply received."); - return -1; - } - - log_dbg("Received enrollment info (%zd bytes).", len); - - reply = enroll_msg__unpack(NULL, len, buf); - if (reply == NULL) { - log_dbg("No enrollment response."); - return -1; - } - - if (reply->code != ENROLL_CODE__ENROLL_BOOT) { - log_dbg("Failed to unpack enrollment response."); - enroll_msg__free_unpacked(reply, NULL); - return -1; - } - - if (!(reply->has_t_sec && reply->has_t_nsec)) { - log_dbg("No time in response message."); - enroll_msg__free_unpacked(reply, NULL); - return -1; - } - - clock_gettime(CLOCK_REALTIME, &rtt); - - delta_t = ts_diff_ms(&t0, &rtt); - - rtt.tv_sec = reply->t_sec; - rtt.tv_nsec = reply->t_nsec; - - if (labs(ts_diff_ms(&t0, &rtt)) - delta_t > ENROLL_WARN_TIME_OFFSET) - log_warn("Clock offset above threshold."); - - strcpy(enroll.conf.layer_info.layer_name, - reply->conf->layer_info->layer_name); - enroll.conf.type = reply->conf->ipcp_type; - enroll.conf.addr_size = reply->conf->addr_size; - enroll.conf.eid_size = reply->conf->eid_size; - enroll.conf.max_ttl = reply->conf->max_ttl; - enroll.conf.addr_auth_type = reply->conf->addr_auth_type; - enroll.conf.routing_type = reply->conf->routing_type; - enroll.conf.pff_type = reply->conf->pff_type; - enroll.conf.layer_info.dir_hash_algo - = reply->conf->layer_info->dir_hash_algo; - - enroll_msg__free_unpacked(reply, NULL); - - return 0; -} - -static ssize_t enroll_pack(uint8_t ** buf) -{ - enroll_msg_t msg = ENROLL_MSG__INIT; - ipcp_config_msg_t config = IPCP_CONFIG_MSG__INIT; - layer_info_msg_t layer_info = LAYER_INFO_MSG__INIT; - struct timespec now; - ssize_t len; - - clock_gettime(CLOCK_REALTIME, &now); - - msg.code = ENROLL_CODE__ENROLL_BOOT; - msg.has_t_sec = true; - msg.t_sec = now.tv_sec; - msg.has_t_nsec = true; - msg.t_nsec = now.tv_nsec; - msg.conf = &config; - - config.ipcp_type = enroll.conf.type; - config.has_addr_size = true; - config.addr_size = enroll.conf.addr_size; - config.has_eid_size = true; - config.eid_size = enroll.conf.eid_size; - config.has_max_ttl = true; - config.max_ttl = enroll.conf.max_ttl; - config.has_addr_auth_type = true; - config.addr_auth_type = enroll.conf.addr_auth_type; - config.has_routing_type = true; - config.routing_type = enroll.conf.routing_type; - config.has_pff_type = true; - config.pff_type = enroll.conf.pff_type; - config.layer_info = &layer_info; - - layer_info.layer_name = (char *) enroll.conf.layer_info.layer_name; - layer_info.dir_hash_algo = enroll.conf.layer_info.dir_hash_algo; - - len = enroll_msg__get_packed_size(&msg); - - *buf = malloc(len); - if (*buf == NULL) - return -1; - - enroll_msg__pack(&msg, *buf); - - return len; -} - -static void * enroll_handle(void * o) -{ - struct conn conn; - uint8_t buf[ENROLL_BUF_LEN]; - uint8_t * reply; - ssize_t len; - enroll_msg_t * msg; - - (void) o; - - while (true) { - if (connmgr_wait(COMPID_ENROLL, &conn)) { - log_err("Failed to get next connection."); - continue; - } - - len = flow_read(conn.flow_info.fd, buf, ENROLL_BUF_LEN); - if (len < 0) { - log_err("Failed to read from flow."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - msg = enroll_msg__unpack(NULL, len, buf); - if (msg == NULL) { - log_err("Failed to unpack message."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - if (msg->code != ENROLL_CODE__ENROLL_REQ) { - log_err("Wrong message type."); - connmgr_dealloc(COMPID_ENROLL, &conn); - enroll_msg__free_unpacked(msg, NULL); - continue; - } - - log_dbg("Enrolling a new neighbor."); - - enroll_msg__free_unpacked(msg, NULL); - - len = enroll_pack(&reply); - if (reply == NULL) { - log_err("Failed to pack enrollment message."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - log_dbg("Sending enrollment info (%zd bytes).", len); - - if (flow_write(conn.flow_info.fd, reply, len)) { - log_err("Failed respond to enrollment request."); - connmgr_dealloc(COMPID_ENROLL, &conn); - free(reply); - continue; - } - - free(reply); - - len = flow_read(conn.flow_info.fd, buf, ENROLL_BUF_LEN); - if (len < 0) { - log_err("Failed to read from flow."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - msg = enroll_msg__unpack(NULL, len, buf); - if (msg == NULL) { - log_err("Failed to unpack message."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - if (msg->code != ENROLL_CODE__ENROLL_DONE || !msg->has_result) { - log_err("Wrong message type."); - enroll_msg__free_unpacked(msg, NULL); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - if (msg->result == 0) - log_dbg("Neighbor enrollment successful."); - else - log_dbg("Neigbor reported failed enrollment."); - - enroll_msg__free_unpacked(msg, NULL); - - connmgr_dealloc(COMPID_ENROLL, &conn); - } - - return 0; -} - -int enroll_boot(struct conn * conn) -{ - log_dbg("Getting boot information."); - - if (send_rcv_enroll_msg(conn->flow_info.fd)) { - log_err("Failed to enroll."); - return -1; - } - - return 0; -} - -int enroll_done(struct conn * conn, - int result) -{ - enroll_msg_t msg = ENROLL_MSG__INIT; - uint8_t buf[ENROLL_BUF_LEN]; - ssize_t len; - - msg.code = ENROLL_CODE__ENROLL_DONE; - msg.has_result = true; - msg.result = result; - - len = enroll_msg__get_packed_size(&msg); - if (len < 0) { - log_dbg("Failed pack request message."); - return -1; - } - - enroll_msg__pack(&msg, buf); - - if (flow_write(conn->flow_info.fd, buf, len)) { - log_dbg("Failed to send acknowledgment."); - return -1; - } - - return 0; -} - -void enroll_bootstrap(const struct ipcp_config * conf) -{ - assert(conf); - - memcpy(&enroll.conf, conf, sizeof(enroll.conf)); -} - -struct ipcp_config * enroll_get_conf(void) -{ - return &enroll.conf; -} - -int enroll_init(void) -{ - struct conn_info info; - - memset(&info, 0, sizeof(info)); - - strcpy(info.comp_name, ENROLL_COMP); - strcpy(info.protocol, ENROLL_PROTO); - info.pref_version = 1; - info.pref_syntax = PROTO_GPB; - info.addr = 0; - - if (connmgr_comp_init(COMPID_ENROLL, &info)) { - log_err("Failed to register with connmgr."); - return -1; - } - - enroll.state = ENROLL_INIT; - - return 0; -} - -void enroll_fini(void) -{ - if (enroll.state == ENROLL_RUNNING) - pthread_join(enroll.listener, NULL); - - connmgr_comp_fini(COMPID_ENROLL); -} - -int enroll_start(void) -{ - if (pthread_create(&enroll.listener, NULL, enroll_handle, NULL)) - return -1; - - enroll.state = ENROLL_RUNNING; - - return 0; -} - -void enroll_stop(void) -{ - if (enroll.state == ENROLL_RUNNING) - pthread_cancel(enroll.listener); -} diff --git a/src/ipcpd/normal/enroll.h b/src/ipcpd/normal/enroll.h deleted file mode 100644 index fd662db1..00000000 --- a/src/ipcpd/normal/enroll.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Enrollment Task - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_ENROLL_H -#define OUROBOROS_IPCPD_NORMAL_ENROLL_H - -#include <ouroboros/ipcp.h> - -#include "comp.h" - -int enroll_init(void); - -void enroll_fini(void); - -int enroll_start(void); - -void enroll_stop(void); - -void enroll_bootstrap(const struct ipcp_config * conf); - -int enroll_boot(struct conn * conn); - -int enroll_done(struct conn * conn, - int result); - -struct ipcp_config * enroll_get_conf(void); - -#endif /* OUROBOROS_IPCPD_NORMAL_ENROLL_H */ diff --git a/src/ipcpd/normal/fa.c b/src/ipcpd/normal/fa.c deleted file mode 100644 index fbcbc6fa..00000000 --- a/src/ipcpd/normal/fa.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Flow allocator of the IPC Process - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#if defined(__linux__) || defined(__CYGWIN__) -#define _DEFAULT_SOURCE -#else -#define _POSIX_C_SOURCE 200112L -#endif - -#include "config.h" - -#define FA "flow-allocator" -#define OUROBOROS_PREFIX FA - -#include <ouroboros/logs.h> -#include <ouroboros/fqueue.h> -#include <ouroboros/errno.h> -#include <ouroboros/dev.h> -#include <ouroboros/ipcp-dev.h> - -#include "dir.h" -#include "fa.h" -#include "psched.h" -#include "ipcp.h" -#include "dt.h" - -#include <pthread.h> -#include <stdlib.h> -#include <string.h> - -#define TIMEOUT 10000 /* nanoseconds */ - -#define FLOW_REQ 0 -#define FLOW_REPLY 1 - -struct fa_msg { - uint64_t s_addr; - uint32_t r_eid; - uint32_t s_eid; - uint8_t code; - int8_t response; - /* QoS parameters from spec, aligned */ - uint8_t availability; - uint8_t in_order; - uint32_t delay; - uint64_t bandwidth; - uint32_t loss; - uint32_t ber; - uint32_t max_gap; -} __attribute__((packed)); - -struct cmd { - struct list_head next; - struct shm_du_buff * sdb; -}; - -struct { - pthread_rwlock_t flows_lock; - int r_eid[PROG_MAX_FLOWS]; - uint64_t r_addr[PROG_MAX_FLOWS]; - int fd; - - struct list_head cmds; - pthread_cond_t cond; - pthread_mutex_t mtx; - pthread_t worker; - - struct psched * psched; -} fa; - -static void packet_handler(int fd, - qoscube_t qc, - struct shm_du_buff * sdb) -{ - pthread_rwlock_rdlock(&fa.flows_lock); - - if (dt_write_packet(fa.r_addr[fd], qc, fa.r_eid[fd], sdb)) { - pthread_rwlock_unlock(&fa.flows_lock); - ipcp_sdb_release(sdb); - log_warn("Failed to forward packet."); - return; - } - - pthread_rwlock_unlock(&fa.flows_lock); -} - -static void destroy_conn(int fd) -{ - fa.r_eid[fd] = -1; - fa.r_addr[fd] = INVALID_ADDR; -} - -static void fa_post_packet(void * comp, - struct shm_du_buff * sdb) -{ - struct cmd * cmd; - - assert(comp == &fa); - - (void) comp; - - cmd = malloc(sizeof(*cmd)); - if (cmd == NULL) { - log_err("Command failed. Out of memory."); - ipcp_sdb_release(sdb); - return; - } - - cmd->sdb = sdb; - - pthread_mutex_lock(&fa.mtx); - - list_add(&cmd->next, &fa.cmds); - - pthread_cond_signal(&fa.cond); - - pthread_mutex_unlock(&fa.mtx); -} - -static void * fa_handle_packet(void * o) -{ - struct timespec ts = {0, TIMEOUT * 1000}; - - (void) o; - - while (true) { - struct timespec abstime; - int fd; - uint8_t * buf; - struct fa_msg * msg; - qosspec_t qs; - struct cmd * cmd; - - pthread_mutex_lock(&fa.mtx); - - pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, - &fa.mtx); - - while (list_is_empty(&fa.cmds)) - pthread_cond_wait(&fa.cond, &fa.mtx); - - cmd = list_last_entry(&fa.cmds, struct cmd, next); - list_del(&cmd->next); - - pthread_cleanup_pop(true); - - buf = malloc(sizeof(*msg) + ipcp_dir_hash_len()); - if (buf == NULL) { - log_err("Failed to allocate memory."); - ipcp_sdb_release(cmd->sdb); - free(cmd); - continue; - } - - msg = (struct fa_msg *) buf; - - /* Depending on the message call the function in ipcp-dev.h */ - - assert(sizeof(*msg) + ipcp_dir_hash_len() >= - (unsigned long int) (shm_du_buff_tail(cmd->sdb) - - shm_du_buff_head(cmd->sdb))); - - memcpy(msg, shm_du_buff_head(cmd->sdb), - shm_du_buff_tail(cmd->sdb) - shm_du_buff_head(cmd->sdb)); - - ipcp_sdb_release(cmd->sdb); - - free(cmd); - - switch (msg->code) { - case FLOW_REQ: - clock_gettime(PTHREAD_COND_CLOCK, &abstime); - - pthread_mutex_lock(&ipcpi.alloc_lock); - - while (ipcpi.alloc_id != -1 && - ipcp_get_state() == IPCP_OPERATIONAL) { - ts_add(&abstime, &ts, &abstime); - pthread_cond_timedwait(&ipcpi.alloc_cond, - &ipcpi.alloc_lock, - &abstime); - } - - if (ipcp_get_state() != IPCP_OPERATIONAL) { - pthread_mutex_unlock(&ipcpi.alloc_lock); - log_dbg("Won't allocate over non-operational" - "IPCP."); - free(msg); - continue; - } - - assert(ipcpi.alloc_id == -1); - - qs.delay = ntoh32(msg->delay); - qs.bandwidth = ntoh64(msg->bandwidth); - qs.availability = msg->availability; - qs.loss = ntoh32(msg->loss); - qs.ber = ntoh32(msg->ber); - qs.in_order = msg->in_order; - qs.max_gap = ntoh32(msg->max_gap); - - fd = ipcp_flow_req_arr((uint8_t *) (msg + 1), - ipcp_dir_hash_len(), - qs); - if (fd < 0) { - pthread_mutex_unlock(&ipcpi.alloc_lock); - log_err("Failed to get fd for flow."); - free(msg); - continue; - } - - pthread_rwlock_wrlock(&fa.flows_lock); - - fa.r_eid[fd] = ntoh32(msg->s_eid); - fa.r_addr[fd] = ntoh64(msg->s_addr); - - pthread_rwlock_unlock(&fa.flows_lock); - - ipcpi.alloc_id = fd; - pthread_cond_broadcast(&ipcpi.alloc_cond); - - pthread_mutex_unlock(&ipcpi.alloc_lock); - - break; - case FLOW_REPLY: - pthread_rwlock_wrlock(&fa.flows_lock); - - fa.r_eid[ntoh32(msg->r_eid)] = ntoh32(msg->s_eid); - - ipcp_flow_alloc_reply(ntoh32(msg->r_eid), - msg->response); - - if (msg->response < 0) - destroy_conn(ntoh32(msg->r_eid)); - else - psched_add(fa.psched, ntoh32(msg->r_eid)); - - pthread_rwlock_unlock(&fa.flows_lock); - - break; - default: - log_err("Got an unknown flow allocation message."); - break; - } - - free(msg); - } -} - -int fa_init(void) -{ - int i; - - for (i = 0; i < PROG_MAX_FLOWS; ++i) - destroy_conn(i); - - if (pthread_rwlock_init(&fa.flows_lock, NULL)) - goto fail_rwlock; - - if (pthread_mutex_init(&fa.mtx, NULL)) - goto fail_mtx; - - if (pthread_cond_init(&fa.cond, NULL)) - goto fail_cond; - - list_head_init(&fa.cmds); - - fa.fd = dt_reg_comp(&fa, &fa_post_packet, FA); - - return 0; - - fail_cond: - pthread_mutex_destroy(&fa.mtx); - fail_mtx: - pthread_rwlock_destroy(&fa.flows_lock); - fail_rwlock: - log_err("Failed to initialize flow allocator."); - return -1; -} - -void fa_fini(void) -{ - pthread_cond_destroy(&fa.cond);; - pthread_mutex_destroy(&fa.mtx); - pthread_rwlock_destroy(&fa.flows_lock); -} - -int fa_start(void) -{ - struct sched_param par; - int pol; - int max; - - fa.psched = psched_create(packet_handler); - if (fa.psched == NULL) { - log_err("Failed to start packet scheduler."); - goto fail_psched; - } - - if (pthread_create(&fa.worker, NULL, fa_handle_packet, NULL)) { - log_err("Failed to create worker thread."); - goto fail_thread; - } - - if (pthread_getschedparam(fa.worker, &pol, &par)) { - log_err("Failed to get worker thread scheduling parameters."); - goto fail_sched; - } - - max = sched_get_priority_max(pol); - if (max < 0) { - log_err("Failed to get max priority for scheduler."); - goto fail_sched; - } - - par.sched_priority = max; - - if (pthread_setschedparam(fa.worker, pol, &par)) { - log_err("Failed to set scheduler priority to maximum."); - goto fail_sched; - } - - return 0; - - fail_sched: - pthread_cancel(fa.worker); - pthread_join(fa.worker, NULL); - fail_thread: - psched_destroy(fa.psched); - fail_psched: - log_err("Failed to start flow allocator."); - return -1; -} - -void fa_stop(void) -{ - pthread_cancel(fa.worker); - pthread_join(fa.worker, NULL); - - psched_destroy(fa.psched); -} - -int fa_alloc(int fd, - const uint8_t * dst, - qosspec_t qs) -{ - struct fa_msg * msg; - uint64_t addr; - struct shm_du_buff * sdb; - qoscube_t qc; - - addr = dir_query(dst); - if (addr == 0) - return -1; - - if (ipcp_sdb_reserve(&sdb, sizeof(*msg) + ipcp_dir_hash_len())) - return -1; - - msg = (struct fa_msg *) shm_du_buff_head(sdb); - msg->code = FLOW_REQ; - msg->s_eid = hton32(fd); - msg->s_addr = hton64(ipcpi.dt_addr); - msg->delay = hton32(qs.delay); - msg->bandwidth = hton64(qs.bandwidth); - msg->availability = qs.availability; - msg->loss = hton32(qs.loss); - msg->ber = hton32(qs.ber); - msg->in_order = qs.in_order; - msg->max_gap = hton32(qs.max_gap); - - memcpy(msg + 1, dst, ipcp_dir_hash_len()); - - qc = qos_spec_to_cube(qs); - - if (dt_write_packet(addr, qc, fa.fd, sdb)) { - ipcp_sdb_release(sdb); - return -1; - } - - pthread_rwlock_wrlock(&fa.flows_lock); - - assert(fa.r_eid[fd] == -1); - fa.r_addr[fd] = addr; - - pthread_rwlock_unlock(&fa.flows_lock); - - return 0; -} - -int fa_alloc_resp(int fd, - int response) -{ - struct timespec ts = {0, TIMEOUT * 1000}; - struct timespec abstime; - struct fa_msg * msg; - struct shm_du_buff * sdb; - qoscube_t qc; - - clock_gettime(PTHREAD_COND_CLOCK, &abstime); - - pthread_mutex_lock(&ipcpi.alloc_lock); - - while (ipcpi.alloc_id != fd && ipcp_get_state() == IPCP_OPERATIONAL) { - ts_add(&abstime, &ts, &abstime); - pthread_cond_timedwait(&ipcpi.alloc_cond, - &ipcpi.alloc_lock, - &abstime); - } - - if (ipcp_get_state() != IPCP_OPERATIONAL) { - pthread_mutex_unlock(&ipcpi.alloc_lock); - return -1; - } - - ipcpi.alloc_id = -1; - pthread_cond_broadcast(&ipcpi.alloc_cond); - - pthread_mutex_unlock(&ipcpi.alloc_lock); - - if (ipcp_sdb_reserve(&sdb, sizeof(*msg) + ipcp_dir_hash_len())) { - destroy_conn(fd); - return -1; - } - - pthread_rwlock_wrlock(&fa.flows_lock); - - msg = (struct fa_msg *) shm_du_buff_head(sdb); - msg->code = FLOW_REPLY; - msg->r_eid = hton32(fa.r_eid[fd]); - msg->s_eid = hton32(fd); - msg->response = response; - - if (response < 0) { - destroy_conn(fd); - ipcp_sdb_release(sdb); - } else { - psched_add(fa.psched, fd); - } - - ipcp_flow_get_qoscube(fd, &qc); - - assert(qc >= 0 && qc < QOS_CUBE_MAX); - - if (dt_write_packet(fa.r_addr[fd], qc, fa.fd, sdb)) { - destroy_conn(fd); - pthread_rwlock_unlock(&fa.flows_lock); - ipcp_sdb_release(sdb); - return -1; - } - - pthread_rwlock_unlock(&fa.flows_lock); - - return 0; -} - -int fa_dealloc(int fd) -{ - if (ipcp_flow_fini(fd) < 0) - return 0; - - pthread_rwlock_wrlock(&fa.flows_lock); - - psched_del(fa.psched, fd); - - destroy_conn(fd); - - pthread_rwlock_unlock(&fa.flows_lock); - - flow_dealloc(fd); - - return 0; -} diff --git a/src/ipcpd/normal/fa.h b/src/ipcpd/normal/fa.h deleted file mode 100644 index d1ec72df..00000000 --- a/src/ipcpd/normal/fa.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Flow allocator of the IPC Process - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_FA_H -#define OUROBOROS_IPCPD_NORMAL_FA_H - -#include <ouroboros/qos.h> -#include <ouroboros/utils.h> - -int fa_init(void); - -void fa_fini(void); - -int fa_start(void); - -void fa_stop(void); - -int fa_alloc(int fd, - const uint8_t * dst, - qosspec_t qs); - -int fa_alloc_resp(int fd, - int response); - -int fa_dealloc(int fd); - -#endif /* OUROBOROS_IPCPD_NORMAL_FA_H */ diff --git a/src/ipcpd/normal/kademlia.proto b/src/ipcpd/normal/kademlia.proto deleted file mode 100644 index 6bd78b38..00000000 --- a/src/ipcpd/normal/kademlia.proto +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * KAD protocol - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * version 2.1 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -syntax = "proto2"; - -message kad_contact_msg { - required bytes id = 1; - required uint64 addr = 2; -}; - -message kad_msg { - required uint32 code = 1; - required uint32 cookie = 2; - required uint64 s_addr = 3; - optional bytes s_id = 4; - optional bytes key = 5; - repeated uint64 addrs = 6; - repeated kad_contact_msg contacts = 7; - // enrolment parameters - optional uint32 alpha = 8; - optional uint32 b = 9; - optional uint32 k = 10; - optional uint32 t_expire = 11; - optional uint32 t_refresh = 12; - optional uint32 t_replicate = 13; -};
\ No newline at end of file diff --git a/src/ipcpd/normal/main.c b/src/ipcpd/normal/main.c deleted file mode 100644 index 28fc8c5a..00000000 --- a/src/ipcpd/normal/main.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Normal IPC Process - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#if defined(__linux__) || defined(__CYGWIN__) -#define _DEFAULT_SOURCE -#else -#define _POSIX_C_SOURCE 200809L -#endif - -#include "config.h" - -#define OUROBOROS_PREFIX "normal-ipcp" - -#include <ouroboros/errno.h> -#include <ouroboros/hash.h> -#include <ouroboros/ipcp-dev.h> -#include <ouroboros/logs.h> -#include <ouroboros/notifier.h> -#include <ouroboros/rib.h> -#include <ouroboros/time_utils.h> - -#include "addr_auth.h" -#include "connmgr.h" -#include "dir.h" -#include "dt.h" -#include "enroll.h" -#include "fa.h" -#include "ipcp.h" - -#include <stdbool.h> -#include <signal.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <inttypes.h> - -#define THIS_TYPE IPCP_NORMAL - -static int initialize_components(const struct ipcp_config * conf) -{ - ipcpi.layer_name = strdup(conf->layer_info.layer_name); - if (ipcpi.layer_name == NULL) { - log_err("Failed to set layer name."); - goto fail_layer_name; - } - - ipcpi.dir_hash_algo = conf->layer_info.dir_hash_algo; - - assert(ipcp_dir_hash_len() != 0); - - if (addr_auth_init(conf->addr_auth_type, - &conf->addr_size)) { - log_err("Failed to init address authority."); - goto fail_addr_auth; - } - - ipcpi.dt_addr = addr_auth_address(); - if (ipcpi.dt_addr == 0) { - log_err("Failed to get a valid address."); - goto fail_addr_auth; - } - - log_dbg("IPCP got address %" PRIu64 ".", ipcpi.dt_addr); - - if (dt_init(conf->routing_type, - conf->pff_type, - conf->addr_size, - conf->eid_size, - conf->max_ttl)) { - log_err("Failed to initialize data transfer component."); - goto fail_dt; - } - - if (fa_init()) { - log_err("Failed to initialize flow allocator component."); - goto fail_fa; - } - - if (dir_init()) { - log_err("Failed to initialize directory."); - goto fail_dir; - } - - ipcp_set_state(IPCP_INIT); - - return 0; - - fail_dir: - fa_fini(); - fail_fa: - dt_fini(); - fail_dt: - addr_auth_fini(); - fail_addr_auth: - free(ipcpi.layer_name); - fail_layer_name: - return -1; -} - -static void finalize_components(void) -{ - dir_fini(); - - fa_fini(); - - dt_fini(); - - addr_auth_fini(); - - free(ipcpi.layer_name); -} - -static int start_components(void) -{ - assert(ipcp_get_state() == IPCP_INIT); - - ipcp_set_state(IPCP_OPERATIONAL); - - if (fa_start()) { - log_err("Failed to start flow allocator."); - goto fail_fa_start; - } - - if (enroll_start()) { - log_err("Failed to start enrollment."); - goto fail_enroll_start; - } - - if (connmgr_start()) { - log_err("Failed to start AP connection manager."); - goto fail_connmgr_start; - } - - return 0; - - fail_connmgr_start: - enroll_stop(); - fail_enroll_start: - fa_stop(); - fail_fa_start: - ipcp_set_state(IPCP_INIT); - return -1; -} - -static void stop_components(void) -{ - assert(ipcp_get_state() == IPCP_OPERATIONAL || - ipcp_get_state() == IPCP_SHUTDOWN); - - connmgr_stop(); - - enroll_stop(); - - fa_stop(); - - ipcp_set_state(IPCP_INIT); -} - -static int bootstrap_components(void) -{ - if (dir_bootstrap()) { - log_err("Failed to bootstrap directory."); - dt_stop(); - return -1; - } - - return 0; -} - -static int normal_ipcp_enroll(const char * dst, - struct layer_info * info) -{ - struct conn conn; - - if (connmgr_alloc(COMPID_ENROLL, dst, NULL, &conn)) { - log_err("Failed to get connection."); - goto fail_er_flow; - } - - /* Get boot state from peer. */ - if (enroll_boot(&conn)) { - log_err("Failed to get boot information."); - goto fail_enroll_boot; - } - - if (initialize_components(enroll_get_conf())) { - log_err("Failed to initialize IPCP components."); - goto fail_enroll_boot; - } - - if (dt_start()) { - log_err("Failed to initialize IPCP components."); - goto fail_dt_start; - } - - if (start_components()) { - log_err("Failed to start components."); - goto fail_start_comp; - } - - if (enroll_done(&conn, 0)) - log_warn("Failed to confirm enrollment with peer."); - - if (connmgr_dealloc(COMPID_ENROLL, &conn)) - log_warn("Failed to deallocate enrollment flow."); - - log_info("Enrolled with %s.", dst); - - info->dir_hash_algo = ipcpi.dir_hash_algo; - strcpy(info->layer_name, ipcpi.layer_name); - - return 0; - - fail_start_comp: - dt_stop(); - fail_dt_start: - finalize_components(); - fail_enroll_boot: - connmgr_dealloc(COMPID_ENROLL, &conn); - fail_er_flow: - return -1; -} - -static int normal_ipcp_bootstrap(const struct ipcp_config * conf) -{ - assert(conf); - assert(conf->type == THIS_TYPE); - - enroll_bootstrap(conf); - - if (initialize_components(conf)) { - log_err("Failed to init IPCP components."); - goto fail_init; - } - - if (dt_start()) { - log_err("Failed to initialize IPCP components."); - goto fail_dt_start; - }; - - if (start_components()) { - log_err("Failed to init IPCP components."); - goto fail_start; - } - - if (bootstrap_components()) { - log_err("Failed to bootstrap IPCP components."); - goto fail_bootstrap; - } - - log_dbg("Bootstrapped in layer %s.", conf->layer_info.layer_name); - - return 0; - - fail_bootstrap: - stop_components(); - fail_start: - dt_stop(); - fail_dt_start: - finalize_components(); - fail_init: - return -1; -} - -static int normal_ipcp_query(const uint8_t * dst) -{ - return dir_query(dst) ? 0 : -1; -} - -static struct ipcp_ops normal_ops = { - .ipcp_bootstrap = normal_ipcp_bootstrap, - .ipcp_enroll = normal_ipcp_enroll, - .ipcp_connect = connmgr_ipcp_connect, - .ipcp_disconnect = connmgr_ipcp_disconnect, - .ipcp_reg = dir_reg, - .ipcp_unreg = dir_unreg, - .ipcp_query = normal_ipcp_query, - .ipcp_flow_alloc = fa_alloc, - .ipcp_flow_join = NULL, - .ipcp_flow_alloc_resp = fa_alloc_resp, - .ipcp_flow_dealloc = fa_dealloc -}; - -int main(int argc, - char * argv[]) -{ - if (ipcp_init(argc, argv, &normal_ops) < 0) { - log_err("Failed to init IPCP."); - goto fail_init; - } - - /* These components must be init at creation. */ - if (rib_init(ipcpi.name)) { - log_err("Failed to initialize RIB."); - goto fail_rib_init; - } - - if (notifier_init()) { - log_err("Failed to initialize notifier component."); - goto fail_notifier_init; - } - - if (connmgr_init()) { - log_err("Failed to initialize connection manager."); - goto fail_connmgr_init; - } - - if (enroll_init()) { - log_err("Failed to initialize enrollment component."); - goto fail_enroll_init; - } - - if (ipcp_boot() < 0) { - log_err("Failed to boot IPCP."); - goto fail_boot; - } - - if (ipcp_create_r(0)) { - log_err("Failed to notify IRMd we are initialized."); - ipcp_set_state(IPCP_NULL); - goto fail_create_r; - } - - ipcp_shutdown(); - - if (ipcp_get_state() == IPCP_SHUTDOWN) { - dt_stop(); - stop_components(); - finalize_components(); - } - - enroll_fini(); - - connmgr_fini(); - - notifier_fini(); - - rib_fini(); - - ipcp_fini(); - - exit(EXIT_SUCCESS); - - fail_create_r: - ipcp_shutdown(); - fail_boot: - enroll_fini(); - fail_enroll_init: - connmgr_fini(); - fail_connmgr_init: - notifier_fini(); - fail_notifier_init: - rib_fini(); - fail_rib_init: - ipcp_fini(); - fail_init: - ipcp_create_r(-1); - exit(EXIT_FAILURE); -} diff --git a/src/ipcpd/normal/pff.c b/src/ipcpd/normal/pff.c deleted file mode 100644 index 5b1fa429..00000000 --- a/src/ipcpd/normal/pff.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * PDU Forwarding Function - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#define OUROBOROS_PREFIX "pff" - -#include <ouroboros/errno.h> -#include <ouroboros/logs.h> - -#include "pff.h" -#include "pol-pff-ops.h" -#include "pol/alternate_pff.h" -#include "pol/simple_pff.h" - -struct pff { - struct pol_pff_ops * ops; - struct pff_i * pff_i; -}; - -struct pff * pff_create(enum pol_pff pol) -{ - struct pff * pff; - - pff = malloc(sizeof(*pff)); - if (pff == NULL) - return NULL; - - switch (pol) { - case PFF_ALTERNATE: - log_dbg("Using alternate PFF policy."); - pff->ops = &alternate_pff_ops; - break; - case PFF_SIMPLE: - log_dbg("Using simple PFF policy."); - pff->ops = &simple_pff_ops; - break; - default: - goto err; - } - - pff->pff_i = pff->ops->create(); - if (pff->pff_i == NULL) - goto err; - - return pff; - err: - free(pff); - return NULL; -} - -void pff_destroy(struct pff * pff) -{ - pff->ops->destroy(pff->pff_i); - - free(pff); -} - -void pff_lock(struct pff * pff) -{ - return pff->ops->lock(pff->pff_i); -} - -void pff_unlock(struct pff * pff) -{ - return pff->ops->unlock(pff->pff_i); -} - -int pff_add(struct pff * pff, - uint64_t addr, - int * fd, - size_t len) -{ - return pff->ops->add(pff->pff_i, addr, fd, len); -} - -int pff_update(struct pff * pff, - uint64_t addr, - int * fd, - size_t len) -{ - return pff->ops->update(pff->pff_i, addr, fd, len); -} - -int pff_del(struct pff * pff, - uint64_t addr) -{ - return pff->ops->del(pff->pff_i, addr); -} - -void pff_flush(struct pff * pff) -{ - return pff->ops->flush(pff->pff_i); -} - -int pff_nhop(struct pff * pff, - uint64_t addr) -{ - return pff->ops->nhop(pff->pff_i, addr); -} - -int pff_flow_state_change(struct pff * pff, - int fd, - bool up) -{ - if (pff->ops->flow_state_change != NULL) - return pff->ops->flow_state_change(pff->pff_i, fd, up); - - return 0; -} diff --git a/src/ipcpd/normal/pff.h b/src/ipcpd/normal/pff.h deleted file mode 100644 index 721899b2..00000000 --- a/src/ipcpd/normal/pff.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * PDU Forwarding Function - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_PFF_H -#define OUROBOROS_IPCPD_NORMAL_PFF_H - -#include <ouroboros/ipcp.h> - -#include <stdint.h> -#include <stdlib.h> -#include <stdbool.h> - -struct pff * pff_create(enum pol_pff pol); - -void pff_destroy(struct pff * pff); - -void pff_lock(struct pff * pff); - -void pff_unlock(struct pff * pff); - -int pff_add(struct pff * pff, - uint64_t addr, - int * fd, - size_t len); - -int pff_update(struct pff * pff, - uint64_t addr, - int * fd, - size_t len); - -int pff_del(struct pff * pff, - uint64_t addr); - -void pff_flush(struct pff * pff); - -/* Returns fd towards next hop */ -int pff_nhop(struct pff * pff, - uint64_t addr); - -int pff_flow_state_change(struct pff * pff, - int fd, - bool up); - -#endif /* OUROBOROS_IPCPD_NORMAL_PFF_H */ diff --git a/src/ipcpd/normal/pol-addr-auth-ops.h b/src/ipcpd/normal/pol-addr-auth-ops.h deleted file mode 100644 index ed7ba450..00000000 --- a/src/ipcpd/normal/pol-addr-auth-ops.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Address authority policy ops - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_POL_ADDR_AUTH_OPS_H -#define OUROBOROS_IPCPD_NORMAL_POL_ADDR_AUTH_OPS_H - -struct pol_addr_auth_ops { - int (* init)(const void * info); - - int (* fini)(void); - - uint64_t (* address)(void); -}; - -#endif /* OUROBOROS_IPCPD_NORMAL_POL_ADDR_AUTH_OPS_H */ diff --git a/src/ipcpd/normal/pol-pff-ops.h b/src/ipcpd/normal/pol-pff-ops.h deleted file mode 100644 index 269000e8..00000000 --- a/src/ipcpd/normal/pol-pff-ops.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Pff policy ops - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_POL_PFF_OPS_H -#define OUROBOROS_IPCPD_NORMAL_POL_PFF_OPS_H - -#include <stdbool.h> - -struct pff_i; - -struct pol_pff_ops { - struct pff_i * (* create)(void); - - void (* destroy)(struct pff_i * pff_i); - - void (* lock)(struct pff_i * pff_i); - - void (* unlock)(struct pff_i * pff_i); - - int (* add)(struct pff_i * pff_i, - uint64_t addr, - int * fd, - size_t len); - - int (* update)(struct pff_i * pff_i, - uint64_t addr, - int * fd, - size_t len); - - int (* del)(struct pff_i * pff_i, - uint64_t addr); - - void (* flush)(struct pff_i * pff_i); - - int (* nhop)(struct pff_i * pff_i, - uint64_t addr); - - /* Optional operation. */ - int (* flow_state_change)(struct pff_i * pff_i, - int fd, - bool up); -}; - -#endif /* OUROBOROS_IPCPD_NORMAL_POL_PFF_OPS_H */ diff --git a/src/ipcpd/normal/pol-routing-ops.h b/src/ipcpd/normal/pol-routing-ops.h deleted file mode 100644 index 9ffb2d35..00000000 --- a/src/ipcpd/normal/pol-routing-ops.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Routing policy ops - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_POL_ROUTING_OPS_H -#define OUROBOROS_IPCPD_NORMAL_POL_ROUTING_OPS_H - -#include "pff.h" - -struct pol_routing_ops { - int (* init)(enum pol_routing pr); - - void (* fini)(void); - - struct routing_i * (* routing_i_create)(struct pff * pff); - - void (* routing_i_destroy)(struct routing_i * instance); -}; - -#endif /* OUROBOROS_IPCPD_NORMAL_POL_ROUTING_OPS_H */ diff --git a/src/ipcpd/normal/pol/alternate_pff.c b/src/ipcpd/normal/pol/alternate_pff.c deleted file mode 100644 index 38937297..00000000 --- a/src/ipcpd/normal/pol/alternate_pff.c +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Policy for PFF with alternate next hops - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#define _POSIX_C_SOURCE 200112L - -#include "config.h" - -#include <ouroboros/hashtable.h> -#include <ouroboros/errno.h> -#include <ouroboros/list.h> - -#include <string.h> -#include <assert.h> -#include <pthread.h> - -#include "alternate_pff.h" - -struct nhop { - struct list_head next; - int fd; -}; - -struct addr { - struct list_head next; - uint64_t addr; -}; - -struct pff_i { - struct htable * table; - - struct list_head addrs; - - struct list_head nhops_down; - - pthread_rwlock_t lock; -}; - -struct pol_pff_ops alternate_pff_ops = { - .create = alternate_pff_create, - .destroy = alternate_pff_destroy, - .lock = alternate_pff_lock, - .unlock = alternate_pff_unlock, - .add = alternate_pff_add, - .update = alternate_pff_update, - .del = alternate_pff_del, - .flush = alternate_pff_flush, - .nhop = alternate_pff_nhop, - .flow_state_change = alternate_flow_state_change -}; - -static int add_addr(struct pff_i * pff_i, - uint64_t addr) -{ - struct addr * a; - - a = malloc(sizeof(*a)); - if (a == NULL) - return -1; - - a->addr = addr; - - list_add(&a->next, &(pff_i->addrs)); - - return 0; -} - -static void del_addr(struct pff_i * pff_i, - uint64_t addr) -{ - struct list_head * pos = NULL; - struct list_head * n = NULL; - - list_for_each_safe(pos, n, &(pff_i->addrs)) { - struct addr * e = list_entry(pos, struct addr, next); - if (e->addr == addr) { - list_del(&e->next); - free(e); - return; - } - } -} - -static void del_addrs(struct pff_i * pff_i) -{ - struct list_head * pos = NULL; - struct list_head * n = NULL; - - list_for_each_safe(pos, n, &(pff_i->addrs)) { - struct addr * e = list_entry(pos, struct addr, next); - list_del(&e->next); - free(e); - } -} - -static void del_nhops_down(struct pff_i * pff_i) -{ - struct list_head * pos = NULL; - struct list_head * n = NULL; - - list_for_each_safe(pos, n, &(pff_i->nhops_down)) { - struct nhop * e = list_entry(pos, struct nhop, next); - list_del(&e->next); - free(e); - } -} - -static int del_nhop_down(struct pff_i * pff_i, - int fd) -{ - struct list_head * pos = NULL; - struct list_head * n = NULL; - - list_for_each_safe(pos, n, &(pff_i->nhops_down)) { - struct nhop * e = list_entry(pos, struct nhop, next); - if (e->fd == fd) { - list_del(&e->next); - free(e); - return 0; - } - } - - return -1; -} - -static int add_nhop_down(struct pff_i * pff_i, - int fd) -{ - struct nhop * nhop; - - nhop = malloc(sizeof(*nhop)); - if (nhop == NULL) - return -1; - - nhop->fd = fd; - - list_add(&nhop->next, &(pff_i->nhops_down)); - - return 0; -} - -static bool nhops_down_has(struct pff_i * pff_i, - int fd) -{ - struct list_head * pos = NULL; - - list_for_each(pos, &pff_i->nhops_down) { - struct nhop * e = list_entry(pos, struct nhop, next); - if (e->fd == fd) - return true; - } - - return false; -} - -static int add_to_htable(struct pff_i * pff_i, - uint64_t addr, - int * fd, - size_t len) -{ - int * val; - - assert(pff_i); - assert(len > 0); - - val = malloc(sizeof(*val) * (len + 1)); - if (val == NULL) - goto fail_malloc; - - memcpy(val, fd, len * sizeof(*val)); - /* Put primary hop again at the end */ - val[len] = val[0]; - - if (htable_insert(pff_i->table, addr, val, len)) - goto fail_insert; - - return 0; - - fail_insert: - free(val); - fail_malloc: - return -1; -} - -struct pff_i * alternate_pff_create(void) -{ - struct pff_i * tmp; - - tmp = malloc(sizeof(*tmp)); - if (tmp == NULL) - goto fail_malloc; - - if (pthread_rwlock_init(&tmp->lock, NULL)) - goto fail_lock; - - tmp->table = htable_create(PFT_SIZE, false); - if (tmp->table == NULL) - goto fail_table; - - list_head_init(&tmp->nhops_down); - list_head_init(&tmp->addrs); - - return tmp; - - fail_table: - pthread_rwlock_destroy(&tmp->lock); - fail_lock: - free(tmp); - fail_malloc: - return NULL; -} - -void alternate_pff_destroy(struct pff_i * pff_i) -{ - assert(pff_i); - - htable_destroy(pff_i->table); - del_nhops_down(pff_i); - del_addrs(pff_i); - pthread_rwlock_destroy(&pff_i->lock); - free(pff_i); -} - -void alternate_pff_lock(struct pff_i * pff_i) -{ - pthread_rwlock_wrlock(&pff_i->lock); -} - -void alternate_pff_unlock(struct pff_i * pff_i) -{ - pthread_rwlock_unlock(&pff_i->lock); -} - -int alternate_pff_add(struct pff_i * pff_i, - uint64_t addr, - int * fd, - size_t len) -{ - assert(pff_i); - assert(len > 0); - - if (add_to_htable(pff_i, addr, fd, len)) - return -1; - - if (add_addr(pff_i, addr)) { - htable_delete(pff_i->table, addr); - return -1; - } - - return 0; -} - -int alternate_pff_update(struct pff_i * pff_i, - uint64_t addr, - int * fd, - size_t len) -{ - assert(pff_i); - assert(len > 0); - - if (htable_delete(pff_i->table, addr)) - return -1; - - if (add_to_htable(pff_i, addr, fd, len)) - return -1; - - return 0; -} - -int alternate_pff_del(struct pff_i * pff_i, - uint64_t addr) -{ - assert(pff_i); - - del_addr(pff_i, addr); - - if (htable_delete(pff_i->table, addr)) - return -1; - - return 0; -} - -void alternate_pff_flush(struct pff_i * pff_i) -{ - assert(pff_i); - - htable_flush(pff_i->table); - - del_nhops_down(pff_i); - - del_addrs(pff_i); -} - -int alternate_pff_nhop(struct pff_i * pff_i, - uint64_t addr) -{ - int fd = -1; - size_t len; - void * el; - - assert(pff_i); - - pthread_rwlock_rdlock(&pff_i->lock); - - if (htable_lookup(pff_i->table, addr, &el, &len)) { - pthread_rwlock_unlock(&pff_i->lock); - return -1; - } - - fd = *((int *) el); - - pthread_rwlock_unlock(&pff_i->lock); - - return fd; -} - -int alternate_flow_state_change(struct pff_i * pff_i, - int fd, - bool up) -{ - struct list_head * pos = NULL; - size_t len; - void * el; - int * fds; - size_t i; - int tmp; - - assert(pff_i); - - pthread_rwlock_wrlock(&pff_i->lock); - - if (up) { - if (del_nhop_down(pff_i, fd)) { - pthread_rwlock_unlock(&pff_i->lock); - return -1; - } - } else { - if (add_nhop_down(pff_i, fd)) { - pthread_rwlock_unlock(&pff_i->lock); - return -1; - } - } - - list_for_each(pos, &pff_i->addrs) { - struct addr * e = list_entry(pos, struct addr, next); - if (htable_lookup(pff_i->table, e->addr, &el, &len)) { - pthread_rwlock_unlock(&pff_i->lock); - return -1; - } - - fds = (int *) el; - - if (up) { - /* It is using an alternate */ - if (fds[len] == fd && fds[0] != fd) { - for (i = 0 ; i < len; i++) { - /* Found the primary */ - if (fds[i] == fd) { - tmp = fds[0]; - fds[0] = fds[i]; - fds[i] = tmp; - break; - } - } - } - } else { - /* Need to switch to a (different) alternate */ - if (fds[0] == fd) { - for (i = 1; i < len; i++) { - /* Usable alternate */ - if (!nhops_down_has(pff_i, fds[i])) { - tmp = fds[0]; - fds[0] = fds[i]; - fds[i] = tmp; - break; - } - } - } - } - } - - pthread_rwlock_unlock(&pff_i->lock); - - return 0; -} diff --git a/src/ipcpd/normal/pol/alternate_pff.h b/src/ipcpd/normal/pol/alternate_pff.h deleted file mode 100644 index 3bfbb886..00000000 --- a/src/ipcpd/normal/pol/alternate_pff.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Policy for PFF with alternate next hops - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_ALTERNATE_PFF_H -#define OUROBOROS_IPCPD_NORMAL_ALTERNATE_PFF_H - -#include "pol-pff-ops.h" - -struct pff_i * alternate_pff_create(void); - -void alternate_pff_destroy(struct pff_i * pff_i); - -void alternate_pff_lock(struct pff_i * pff_i); - -void alternate_pff_unlock(struct pff_i * pff_i); - -int alternate_pff_add(struct pff_i * pff_i, - uint64_t addr, - int * fd, - size_t len); - -int alternate_pff_update(struct pff_i * pff_i, - uint64_t addr, - int * fd, - size_t len); - -int alternate_pff_del(struct pff_i * pff_i, - uint64_t addr); - -void alternate_pff_flush(struct pff_i * pff_i); - -/* Returns fd towards next hop */ -int alternate_pff_nhop(struct pff_i * pff_i, - uint64_t addr); - -int alternate_flow_state_change(struct pff_i * pff_i, - int fd, - bool up); - -struct pol_pff_ops alternate_pff_ops; - -#endif /* OUROBOROS_IPCPD_NORMAL_ALTERNATE_PFF_H */ diff --git a/src/ipcpd/normal/pol/flat.c b/src/ipcpd/normal/pol/flat.c deleted file mode 100644 index 157885f9..00000000 --- a/src/ipcpd/normal/pol/flat.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Policy for flat addresses in a distributed way - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#if defined(__linux__) || defined(__CYGWIN__) -#define _DEFAULT_SOURCE -#else -#define _POSIX_C_SOURCE 200112L -#endif - -#define OUROBOROS_PREFIX "flat-addr-auth" - -#include <ouroboros/logs.h> -#include <ouroboros/errno.h> -#include <ouroboros/time_utils.h> -#include <ouroboros/utils.h> - -#include "ipcp.h" -#include "flat.h" - -#include <time.h> -#include <stdlib.h> -#include <math.h> -#include <string.h> -#include <assert.h> - -#define NAME_LEN 8 - -struct { - uint8_t addr_size; -} flat; - -#define INVALID_ADDRESS 0 - -struct pol_addr_auth_ops flat_ops = { - .init = flat_init, - .fini = flat_fini, - .address = flat_address -}; - -int flat_init(const void * info) -{ - flat.addr_size = *((uint8_t *) info); - - if (flat.addr_size != 4) { - log_err("Flat address policy mandates 4 byte addresses."); - return -1; - } - - return 0; -} - -int flat_fini(void) -{ - return 0; -} - -uint64_t flat_address(void) -{ - struct timespec t; - uint32_t addr; - - clock_gettime(CLOCK_REALTIME, &t); - srand(t.tv_nsec); - - addr = (rand() % (RAND_MAX - 1) + 1) & 0xFFFFFFFF; - - return addr; -} diff --git a/src/ipcpd/normal/pol/flat.h b/src/ipcpd/normal/pol/flat.h deleted file mode 100644 index 9df3de51..00000000 --- a/src/ipcpd/normal/pol/flat.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Policy for flat addresses in a distributed way - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_FLAT_H -#define OUROBOROS_IPCPD_NORMAL_FLAT_H - -#include "pol-addr-auth-ops.h" - -int flat_init(const void * info); - -int flat_fini(void); - -uint64_t flat_address(void); - -struct pol_addr_auth_ops flat_ops; - -#endif /* OUROBOROS_IPCPD_NORMAL_FLAT_H */ diff --git a/src/ipcpd/normal/pol/graph.c b/src/ipcpd/normal/pol/graph.c deleted file mode 100644 index 6c93bb62..00000000 --- a/src/ipcpd/normal/pol/graph.c +++ /dev/null @@ -1,695 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Undirected graph structure - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#if defined(__linux__) || defined(__CYGWIN__) -#define _DEFAULT_SOURCE -#else -#define _POSIX_C_SOURCE 200112L -#endif - -#define OUROBOROS_PREFIX "graph" - -#include <ouroboros/logs.h> -#include <ouroboros/errno.h> -#include <ouroboros/list.h> - -#include "graph.h" -#include "ipcp.h" - -#include <assert.h> -#include <pthread.h> -#include <stdlib.h> -#include <limits.h> -#include <string.h> - -struct edge { - struct list_head next; - struct vertex * nb; - qosspec_t qs; - int announced; -}; - -struct vertex { - struct list_head next; - uint64_t addr; - struct list_head edges; - int index; -}; - -struct graph { - size_t nr_vertices; - struct list_head vertices; - pthread_mutex_t lock; -}; - -static struct edge * find_edge_by_addr(struct vertex * vertex, - uint64_t dst_addr) -{ - struct list_head * p = NULL; - - list_for_each(p, &vertex->edges) { - struct edge * e = list_entry(p, struct edge, next); - if (e->nb->addr == dst_addr) - return e; - } - - return NULL; -} - -static struct vertex * find_vertex_by_addr(struct graph * graph, - uint64_t addr) -{ - struct list_head * p = NULL; - - list_for_each(p, &graph->vertices) { - struct vertex * e = list_entry(p, struct vertex, next); - if (e->addr == addr) - return e; - } - - return NULL; -} - -static struct edge * add_edge(struct vertex * vertex, - struct vertex * nb) -{ - struct edge * edge; - - edge = malloc(sizeof(*edge)); - if (edge == NULL) - return NULL; - - list_head_init(&edge->next); - edge->nb = nb; - edge->announced = 0; - - list_add(&edge->next, &vertex->edges); - - return edge; -} - -static void del_edge(struct edge * edge) -{ - list_del(&edge->next); - free(edge); -} - -static struct vertex * add_vertex(struct graph * graph, - uint64_t addr) -{ - struct vertex * vertex; - struct list_head * p; - int i = 0; - - vertex = malloc(sizeof(*vertex)); - if (vertex == NULL) - return NULL; - - list_head_init(&vertex->next); - list_head_init(&vertex->edges); - vertex->addr = addr; - - /* Keep them ordered on address. */ - list_for_each(p, &graph->vertices) { - struct vertex * v = list_entry(p, struct vertex, next); - if (v->addr > addr) - break; - i++; - } - - vertex->index = i; - - list_add_tail(&vertex->next, p); - - /* Increase the index of the vertices to the right. */ - list_for_each(p, &graph->vertices) { - struct vertex * v = list_entry(p, struct vertex, next); - if (v->addr > addr) - v->index++; - } - - graph->nr_vertices++; - - return vertex; -} - -static void del_vertex(struct graph * graph, - struct vertex * vertex) -{ - struct list_head * p = NULL; - struct list_head * n = NULL; - - list_del(&vertex->next); - - /* Decrease the index of the vertices to the right. */ - list_for_each(p, &graph->vertices) { - struct vertex * v = list_entry(p, struct vertex, next); - if (v->addr > vertex->addr) - v->index--; - } - - list_for_each_safe(p, n, &vertex->edges) { - struct edge * e = list_entry(p, struct edge, next); - del_edge(e); - } - - free(vertex); - - graph->nr_vertices--; -} - -struct graph * graph_create(void) -{ - struct graph * graph; - - graph = malloc(sizeof(*graph)); - if (graph == NULL) - return NULL; - - if (pthread_mutex_init(&graph->lock, NULL)) { - free(graph); - return NULL; - } - - graph->nr_vertices = 0; - list_head_init(&graph->vertices); - - return graph; -} - -void graph_destroy(struct graph * graph) -{ - struct list_head * p = NULL; - struct list_head * n = NULL; - - assert(graph); - - pthread_mutex_lock(&graph->lock); - - list_for_each_safe(p, n, &graph->vertices) { - struct vertex * e = list_entry(p, struct vertex, next); - del_vertex(graph, e); - } - - pthread_mutex_unlock(&graph->lock); - - pthread_mutex_destroy(&graph->lock); - - free(graph); -} - -int graph_update_edge(struct graph * graph, - uint64_t s_addr, - uint64_t d_addr, - qosspec_t qs) -{ - struct vertex * v; - struct edge * e; - struct vertex * nb; - struct edge * nb_e; - - assert(graph); - - pthread_mutex_lock(&graph->lock); - - v = find_vertex_by_addr(graph, s_addr); - if (v == NULL) { - v = add_vertex(graph, s_addr); - if (v == NULL) { - pthread_mutex_unlock(&graph->lock); - log_err("Failed to add vertex."); - return -ENOMEM; - } - } - - nb = find_vertex_by_addr(graph, d_addr); - if (nb == NULL) { - nb = add_vertex(graph, d_addr); - if (nb == NULL) { - if (list_is_empty(&v->edges)) - del_vertex(graph, v); - pthread_mutex_unlock(&graph->lock); - log_err("Failed to add vertex."); - return -ENOMEM; - } - } - - e = find_edge_by_addr(v, d_addr); - if (e == NULL) { - e = add_edge(v, nb); - if (e == NULL) { - if (list_is_empty(&v->edges)) - del_vertex(graph, v); - if (list_is_empty(&nb->edges)) - del_vertex(graph, nb); - pthread_mutex_unlock(&graph->lock); - log_err("Failed to add edge."); - return -ENOMEM; - } - } - - e->announced++; - e->qs = qs; - - nb_e = find_edge_by_addr(nb, s_addr); - if (nb_e == NULL) { - nb_e = add_edge(nb, v); - if (nb_e == NULL) { - if (--e->announced == 0) - del_edge(e); - if (list_is_empty(&v->edges)) - del_vertex(graph, v); - if (list_is_empty(&nb->edges)) - del_vertex(graph, nb); - pthread_mutex_unlock(&graph->lock); - log_err("Failed to add edge."); - return -ENOMEM; - } - } - - nb_e->announced++; - nb_e->qs = qs; - - pthread_mutex_unlock(&graph->lock); - - return 0; -} - -int graph_del_edge(struct graph * graph, - uint64_t s_addr, - uint64_t d_addr) -{ - struct vertex * v; - struct edge * e; - struct vertex * nb; - struct edge * nb_e; - - assert(graph); - - pthread_mutex_lock(&graph->lock); - - v = find_vertex_by_addr(graph, s_addr); - if (v == NULL) { - pthread_mutex_unlock(&graph->lock); - log_err("No such source vertex."); - return -1; - } - - nb = find_vertex_by_addr(graph, d_addr); - if (nb == NULL) { - pthread_mutex_unlock(&graph->lock); - log_err("No such destination vertex."); - return -1; - } - - e = find_edge_by_addr(v, d_addr); - if (e == NULL) { - pthread_mutex_unlock(&graph->lock); - log_err("No such source edge."); - return -1; - } - - nb_e = find_edge_by_addr(nb, s_addr); - if (nb_e == NULL) { - pthread_mutex_unlock(&graph->lock); - log_err("No such destination edge."); - return -1; - } - - if (--e->announced == 0) - del_edge(e); - if (--nb_e->announced == 0) - del_edge(nb_e); - - /* Removing vertex if it was the last edge */ - if (list_is_empty(&v->edges)) - del_vertex(graph, v); - if (list_is_empty(&nb->edges)) - del_vertex(graph, nb); - - pthread_mutex_unlock(&graph->lock); - - return 0; -} - -static int get_min_vertex(struct graph * graph, - int * dist, - bool * used, - struct vertex ** v) -{ - int min = INT_MAX; - int index = -1; - int i = 0; - struct list_head * p = NULL; - - *v = NULL; - - list_for_each(p, &graph->vertices) { - if (!used[i] && dist[i] < min) { - min = dist[i]; - index = i; - *v = list_entry(p, struct vertex, next); - } - - i++; - } - - if (index != -1) - used[index] = true; - - return index; -} - -static int dijkstra(struct graph * graph, - uint64_t src, - struct vertex *** nhops, - int ** dist) -{ - bool * used; - struct list_head * p = NULL; - int i = 0; - struct vertex * v = NULL; - struct edge * e = NULL; - int alt; - - *nhops = malloc(sizeof(**nhops) * graph->nr_vertices); - if (*nhops == NULL) - goto fail_pnhops; - - *dist = malloc(sizeof(**dist) * graph->nr_vertices); - if (*dist == NULL) - goto fail_pdist; - - used = malloc(sizeof(*used) * graph->nr_vertices); - if (used == NULL) - goto fail_used; - - /* Init the data structures */ - memset(used, 0, sizeof(*used) * graph->nr_vertices); - memset(*nhops, 0, sizeof(**nhops) * graph->nr_vertices); - memset(*dist, 0, sizeof(**dist) * graph->nr_vertices); - - list_for_each(p, &graph->vertices) { - v = list_entry(p, struct vertex, next); - (*dist)[i++] = (v->addr == src) ? 0 : INT_MAX; - } - - /* Perform actual Dijkstra */ - i = get_min_vertex(graph, *dist, used, &v); - while (v != NULL) { - list_for_each(p, &v->edges) { - e = list_entry(p, struct edge, next); - - /* Only include it if both sides announced it. */ - if (e->announced != 2) - continue; - - /* - * NOTE: Current weight is just hop count. - * Method could be extended to use a different - * weight for a different QoS cube. - */ - alt = (*dist)[i] + 1; - if (alt < (*dist)[e->nb->index]) { - (*dist)[e->nb->index] = alt; - if (v->addr == src) - (*nhops)[e->nb->index] = e->nb; - else - (*nhops)[e->nb->index] = (*nhops)[i]; - } - } - i = get_min_vertex(graph, *dist, used, &v); - } - - free(used); - - return 0; - - fail_used: - free(*dist); - fail_pdist: - free(*nhops); - fail_pnhops: - return -1; - -} - -static void free_routing_table(struct list_head * table) -{ - struct list_head * h; - struct list_head * p; - struct list_head * q; - struct list_head * i; - - list_for_each_safe(p, h, table) { - struct routing_table * t = - list_entry(p, struct routing_table, next); - list_for_each_safe(q, i, &t->nhops) { - struct nhop * n = - list_entry(q, struct nhop, next); - list_del(&n->next); - free(n); - } - list_del(&t->next); - free(t); - } -} - -void graph_free_routing_table(struct graph * graph, - struct list_head * table) -{ - assert(table); - - pthread_mutex_lock(&graph->lock); - - free_routing_table(table); - - pthread_mutex_unlock(&graph->lock); -} - -static int graph_routing_table_simple(struct graph * graph, - uint64_t s_addr, - struct list_head * table, - int ** dist) -{ - struct vertex ** nhops; - struct list_head * p; - int i = 0; - struct vertex * v; - struct routing_table * t; - struct nhop * n; - - /* We need at least 2 vertices for a table */ - if (graph->nr_vertices < 2) - goto fail_vertices; - - if (dijkstra(graph, s_addr, &nhops, dist)) - goto fail_vertices; - - list_head_init(table); - - /* Now construct the routing table from the nhops. */ - list_for_each(p, &graph->vertices) { - v = list_entry(p, struct vertex, next); - - /* This is the src */ - if (nhops[i] == NULL) { - i++; - continue; - } - - t = malloc(sizeof(*t)); - if (t == NULL) - goto fail_t; - - list_head_init(&t->nhops); - - n = malloc(sizeof(*n)); - if (n == NULL) - goto fail_n; - - t->dst = v->addr; - n->nhop = nhops[i]->addr; - - list_add(&n->next, &t->nhops); - list_add(&t->next, table); - - i++; - } - - free(nhops); - - return 0; - - fail_n: - free(t); - fail_t: - free_routing_table(table); - free(nhops); - free(*dist); - fail_vertices: - *dist = NULL; - return -1; -} - -static int add_lfa_to_table(struct list_head * table, - uint64_t addr, - uint64_t lfa) -{ - struct list_head * p = NULL; - struct nhop * n; - - n = malloc(sizeof(*n)); - if (n == NULL) - return -1; - - n->nhop = lfa; - - list_for_each(p, table) { - struct routing_table * t = - list_entry(p, struct routing_table, next); - if (t->dst == addr) { - list_add_tail(&n->next, &t->nhops); - return 0; - } - } - - free(n); - - return -1; -} - -int graph_routing_table(struct graph * graph, - enum routing_algo algo, - uint64_t s_addr, - struct list_head * table) -{ - int * s_dist; - int * n_dist[PROG_MAX_FLOWS]; - uint64_t addrs[PROG_MAX_FLOWS]; - int n_index[PROG_MAX_FLOWS]; - struct list_head * p; - struct list_head * q; - struct vertex * v; - struct edge * e; - struct vertex ** nhops; - int i = 0; - int j = 0; - int k; - - assert(graph); - assert(table); - - pthread_mutex_lock(&graph->lock); - - /* Get the normal next hops routing table. */ - if (graph_routing_table_simple(graph, s_addr, table, &s_dist)) - goto fail_table_simple; - - /* Possibly augment the routing table. */ - switch (algo) { - case ROUTING_SIMPLE: - break; - case ROUTING_LFA: - for (j = 0; j < PROG_MAX_FLOWS; j++) { - n_dist[j] = NULL; - n_index[j] = -1; - addrs[j] = -1; - } - - list_for_each(p, &graph->vertices) { - v = list_entry(p, struct vertex, next); - - if (v->addr != s_addr) - continue; - - /* - * Get the distances for every neighbor - * of the source. - */ - list_for_each(q, &v->edges) { - e = list_entry(q, struct edge, next); - - addrs[i] = e->nb->addr; - n_index[i] = e->nb->index; - if (dijkstra(graph, e->nb->addr, - &nhops, &(n_dist[i++]))) - goto fail_dijkstra; - - free(nhops); - } - - break; - } - - /* Loop though all nodes to see if we have a LFA for them. */ - list_for_each(p, &graph->vertices) { - v = list_entry(p, struct vertex, next); - - if (v->addr == s_addr) - continue; - - /* - * Check for every neighbor if - * dist(neighbor, destination) < - * dist(neighbor, source) + dist(source, destination). - */ - for (j = 0; j < i; j++) { - /* Exclude ourselves. */ - if (addrs[j] == v->addr) - continue; - - if (n_dist[j][v->index] < - s_dist[n_index[j]] + s_dist[v->index]) - if (add_lfa_to_table(table, v->addr, - addrs[j])) - goto fail_add_lfa; - } - } - - for (j = 0; j < i; j++) - free(n_dist[j]); - - break; - default: - log_err("Unsupported algorithm."); - goto fail_algo; - } - - pthread_mutex_unlock(&graph->lock); - - free(s_dist); - - return 0; - - fail_add_lfa: - for (k = j; k < i; k++) - free(n_dist[k]); - fail_dijkstra: - free_routing_table(table); - fail_algo: - free(s_dist); - fail_table_simple: - pthread_mutex_unlock(&graph->lock); - - return -1; -} diff --git a/src/ipcpd/normal/pol/graph.h b/src/ipcpd/normal/pol/graph.h deleted file mode 100644 index 131e9eca..00000000 --- a/src/ipcpd/normal/pol/graph.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Undirected graph structure - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_GRAPH_H -#define OUROBOROS_IPCPD_NORMAL_GRAPH_H - -#include <ouroboros/list.h> -#include <ouroboros/qos.h> - -#include <inttypes.h> - -enum routing_algo { - ROUTING_SIMPLE = 0, - ROUTING_LFA -}; - -struct nhop { - struct list_head next; - uint64_t nhop; -}; - -struct routing_table { - struct list_head next; - uint64_t dst; - struct list_head nhops; -}; - -struct graph * graph_create(void); - -void graph_destroy(struct graph * graph); - -int graph_update_edge(struct graph * graph, - uint64_t s_addr, - uint64_t d_addr, - qosspec_t qs); - -int graph_del_edge(struct graph * graph, - uint64_t s_addr, - uint64_t d_addr); - -int graph_routing_table(struct graph * graph, - enum routing_algo algo, - uint64_t s_addr, - struct list_head * table); - -void graph_free_routing_table(struct graph * graph, - struct list_head * table); - -#endif /* OUROBOROS_IPCPD_NORMAL_GRAPH_H */ diff --git a/src/ipcpd/normal/pol/link_state.c b/src/ipcpd/normal/pol/link_state.c deleted file mode 100644 index d8f0e263..00000000 --- a/src/ipcpd/normal/pol/link_state.c +++ /dev/null @@ -1,1022 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Link state routing policy - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#if defined(__linux__) || defined(__CYGWIN__) -#define _DEFAULT_SOURCE -#else -#define _POSIX_C_SOURCE 200112L -#endif - -#include "config.h" - -#define OUROBOROS_PREFIX "link-state-routing" - -#include <ouroboros/endian.h> -#include <ouroboros/dev.h> -#include <ouroboros/errno.h> -#include <ouroboros/fccntl.h> -#include <ouroboros/fqueue.h> -#include <ouroboros/list.h> -#include <ouroboros/logs.h> -#include <ouroboros/notifier.h> -#include <ouroboros/rib.h> -#include <ouroboros/utils.h> - -#include "comp.h" -#include "connmgr.h" -#include "graph.h" -#include "ipcp.h" -#include "link_state.h" -#include "pff.h" - -#include <assert.h> -#include <stdlib.h> -#include <inttypes.h> -#include <string.h> -#include <pthread.h> - -#define RECALC_TIME 4 -#define LS_UPDATE_TIME 15 -#define LS_TIMEO 60 -#define LS_ENTRY_SIZE 104 -#define LSDB "lsdb" - -#ifndef CLOCK_REALTIME_COARSE -#define CLOCK_REALTIME_COARSE CLOCK_REALTIME -#endif - -struct lsa { - uint64_t d_addr; - uint64_t s_addr; - uint64_t seqno; -} __attribute__((packed)); - -struct routing_i { - struct list_head next; - - struct pff * pff; - pthread_t calculator; - - bool modified; - pthread_mutex_t lock; -}; - -/* TODO: link weight support. */ -struct adjacency { - struct list_head next; - - uint64_t dst; - uint64_t src; - - uint64_t seqno; - - time_t stamp; -}; - -enum nb_type { - NB_DT = 0, - NB_MGMT -}; - -struct nb { - struct list_head next; - - uint64_t addr; - int fd; - enum nb_type type; -}; - -struct { - struct list_head nbs; - size_t nbs_len; - fset_t * mgmt_set; - - struct list_head db; - size_t db_len; - - pthread_rwlock_t db_lock; - - struct graph * graph; - - pthread_t lsupdate; - pthread_t lsreader; - pthread_t listener; - - struct list_head routing_instances; - pthread_mutex_t routing_i_lock; - - enum routing_algo routing_algo; -} ls; - -struct pol_routing_ops link_state_ops = { - .init = link_state_init, - .fini = link_state_fini, - .routing_i_create = link_state_routing_i_create, - .routing_i_destroy = link_state_routing_i_destroy -}; - -static int str_adj(struct adjacency * adj, - char * buf, - size_t len) -{ - char tmbuf[64]; - char srcbuf[64]; - char dstbuf[64]; - char seqnobuf[64]; - struct tm * tm; - - if (len < LS_ENTRY_SIZE) - return -1; - - tm = localtime(&adj->stamp); - strftime(tmbuf, sizeof(tmbuf), "%F %T", tm); /* 19 chars */ - - sprintf(srcbuf, "%" PRIu64, adj->src); - sprintf(dstbuf, "%" PRIu64, adj->dst); - sprintf(seqnobuf, "%" PRIu64, adj->seqno); - - sprintf(buf, "src: %20s\ndst: %20s\nseqno: %18s\nupd: %20s\n", - srcbuf, dstbuf, seqnobuf, tmbuf); - - return LS_ENTRY_SIZE; -} - -static struct adjacency * get_adj(const char * path) -{ - struct list_head * p; - char entry[RIB_PATH_LEN + 1]; - - assert(path); - - list_for_each(p, &ls.db) { - struct adjacency * a = list_entry(p, struct adjacency, next); - sprintf(entry, "%" PRIu64 ".%" PRIu64, a->src, a->dst); - if (strcmp(entry, path) == 0) - return a; - } - - return NULL; -} - -static int lsdb_getattr(const char * path, - struct stat * st) -{ - struct adjacency * adj; - struct timespec now; - - clock_gettime(CLOCK_REALTIME_COARSE, &now); - - pthread_rwlock_rdlock(&ls.db_lock); - - adj = get_adj(path); - if (adj != NULL) { - st->st_mtime = adj->stamp; - st->st_size = LS_ENTRY_SIZE; - } else { - st->st_mtime = now.tv_sec; - st->st_size = 0; - } - - st->st_mode = S_IFREG | 0755; - st->st_nlink = 1; - st->st_uid = getuid(); - st->st_gid = getgid(); - - pthread_rwlock_unlock(&ls.db_lock); - - return 0; -} - -static int lsdb_read(const char * path, - char * buf, - size_t len) -{ - struct adjacency * a; - int size; - - pthread_rwlock_rdlock(&ls.db_lock); - - if (ls.db_len + ls.nbs_len == 0) - goto fail; - - a = get_adj(path); - if (a == NULL) - goto fail; - - size = str_adj(a, buf, len); - if (size < 0) - goto fail; - - pthread_rwlock_unlock(&ls.db_lock); - return size; - - fail: - pthread_rwlock_unlock(&ls.db_lock); - return -1; -} - -static int lsdb_readdir(char *** buf) -{ - struct list_head * p; - char entry[RIB_PATH_LEN + 1]; - ssize_t idx = 0; - - pthread_rwlock_rdlock(&ls.db_lock); - - if (ls.db_len + ls.nbs_len == 0) { - pthread_rwlock_unlock(&ls.db_lock); - return 0; - } - - *buf = malloc(sizeof(**buf) * (ls.db_len + ls.nbs_len)); - if (*buf == NULL) { - pthread_rwlock_unlock(&ls.db_lock); - return -ENOMEM; - } - - list_for_each(p, &ls.nbs) { - struct nb * nb = list_entry(p, struct nb, next); - char * str = (nb->type == NB_DT ? "dt." : "mgmt."); - sprintf(entry, "%s%" PRIu64, str, nb->addr); - (*buf)[idx] = malloc(strlen(entry) + 1); - if ((*buf)[idx] == NULL) { - while (idx-- > 0) - free((*buf)[idx]); - free(buf); - pthread_rwlock_unlock(&ls.db_lock); - return -ENOMEM; - } - - strcpy((*buf)[idx], entry); - - idx++; - } - - list_for_each(p, &ls.db) { - struct adjacency * a = list_entry(p, struct adjacency, next); - sprintf(entry, "%" PRIu64 ".%" PRIu64, a->src, a->dst); - (*buf)[idx] = malloc(strlen(entry) + 1); - if ((*buf)[idx] == NULL) { - ssize_t j; - for (j = 0; j < idx; ++j) - free(*buf[j]); - free(buf); - pthread_rwlock_unlock(&ls.db_lock); - return -ENOMEM; - } - - strcpy((*buf)[idx], entry); - - idx++; - } - - pthread_rwlock_unlock(&ls.db_lock); - - return idx; -} - -static struct rib_ops r_ops = { - .read = lsdb_read, - .readdir = lsdb_readdir, - .getattr = lsdb_getattr -}; - -static int lsdb_add_nb(uint64_t addr, - int fd, - enum nb_type type) -{ - struct list_head * p; - struct nb * nb; - - pthread_rwlock_wrlock(&ls.db_lock); - - list_for_each(p, &ls.nbs) { - struct nb * el = list_entry(p, struct nb, next); - if (el->addr == addr && el->type == type) { - log_dbg("Already know %s neighbor %" PRIu64 ".", - type == NB_DT ? "dt" : "mgmt", addr); - if (el->fd != fd) { - log_warn("Existing neighbor assigned new fd."); - el->fd = fd; - } - pthread_rwlock_unlock(&ls.db_lock); - return -EPERM; - } - - if (addr > el->addr) - break; - } - - nb = malloc(sizeof(*nb)); - if (nb == NULL) { - pthread_rwlock_unlock(&ls.db_lock); - return -ENOMEM; - } - - nb->addr = addr; - nb->fd = fd; - nb->type = type; - - list_add_tail(&nb->next, p); - - ++ls.nbs_len; - - log_dbg("Type %s neighbor %" PRIu64 " added.", - nb->type == NB_DT ? "dt" : "mgmt", addr); - - pthread_rwlock_unlock(&ls.db_lock); - - return 0; -} - -static int lsdb_del_nb(uint64_t addr, - int fd) -{ - struct list_head * p; - struct list_head * h; - - pthread_rwlock_wrlock(&ls.db_lock); - - list_for_each_safe(p, h, &ls.nbs) { - struct nb * nb = list_entry(p, struct nb, next); - if (nb->addr == addr && nb->fd == fd) { - list_del(&nb->next); - --ls.nbs_len; - pthread_rwlock_unlock(&ls.db_lock); - log_dbg("Type %s neighbor %" PRIu64 " deleted.", - nb->type == NB_DT ? "dt" : "mgmt", addr); - free(nb); - return 0; - } - } - - pthread_rwlock_unlock(&ls.db_lock); - - return -EPERM; -} - -static int nbr_to_fd(uint64_t addr) -{ - struct list_head * p; - - pthread_rwlock_rdlock(&ls.db_lock); - - list_for_each(p, &ls.nbs) { - struct nb * nb = list_entry(p, struct nb, next); - if (nb->addr == addr && nb->type == NB_DT) { - pthread_rwlock_unlock(&ls.db_lock); - return nb->fd; - } - } - - pthread_rwlock_unlock(&ls.db_lock); - - return -1; -} - -static void calculate_pff(struct routing_i * instance) -{ - int fd; - struct list_head table; - struct list_head * p; - struct list_head * q; - int fds[PROG_MAX_FLOWS]; - - if (graph_routing_table(ls.graph, ls.routing_algo, - ipcpi.dt_addr, &table)) - return; - - pff_lock(instance->pff); - - pff_flush(instance->pff); - - /* Calculate forwarding table from routing table. */ - list_for_each(p, &table) { - int i = 0; - struct routing_table * t = - list_entry(p, struct routing_table, next); - - list_for_each(q, &t->nhops) { - struct nhop * n = list_entry(q, struct nhop, next); - - fd = nbr_to_fd(n->nhop); - if (fd == -1) - continue; - - fds[i++] = fd; - } - if (i > 0) - pff_add(instance->pff, t->dst, fds, i); - } - - pff_unlock(instance->pff); - - graph_free_routing_table(ls.graph, &table); -} - -static void set_pff_modified(bool calc) -{ - struct list_head * p; - - pthread_mutex_lock(&ls.routing_i_lock); - list_for_each(p, &ls.routing_instances) { - struct routing_i * inst = - list_entry(p, struct routing_i, next); - pthread_mutex_lock(&inst->lock); - inst->modified = true; - pthread_mutex_unlock(&inst->lock); - if (calc) - calculate_pff(inst); - } - pthread_mutex_unlock(&ls.routing_i_lock); -} - -static int lsdb_add_link(uint64_t src, - uint64_t dst, - uint64_t seqno, - qosspec_t * qs) -{ - struct list_head * p; - struct adjacency * adj; - struct timespec now; - int ret = -1; - - clock_gettime(CLOCK_REALTIME_COARSE, &now); - - pthread_rwlock_wrlock(&ls.db_lock); - - list_for_each(p, &ls.db) { - struct adjacency * a = list_entry(p, struct adjacency, next); - if (a->dst == dst && a->src == src) { - if (a->seqno < seqno) { - a->stamp = now.tv_sec; - a->seqno = seqno; - ret = 0; - } - pthread_rwlock_unlock(&ls.db_lock); - return ret; - } - - if (a->dst > dst || (a->dst == dst && a->src > src)) - break; - } - - adj = malloc(sizeof(*adj)); - if (adj == NULL) { - pthread_rwlock_unlock(&ls.db_lock); - return -ENOMEM; - } - - adj->dst = dst; - adj->src = src; - adj->seqno = seqno; - adj->stamp = now.tv_sec; - - list_add_tail(&adj->next, p); - - ls.db_len++; - - if (graph_update_edge(ls.graph, src, dst, *qs)) - log_warn("Failed to add edge to graph."); - - pthread_rwlock_unlock(&ls.db_lock); - - set_pff_modified(true); - - return 0; -} - -static int lsdb_del_link(uint64_t src, - uint64_t dst) -{ - struct list_head * p; - struct list_head * h; - - pthread_rwlock_wrlock(&ls.db_lock); - - list_for_each_safe(p, h, &ls.db) { - struct adjacency * a = list_entry(p, struct adjacency, next); - if (a->dst == dst && a->src == src) { - list_del(&a->next); - if (graph_del_edge(ls.graph, src, dst)) - log_warn("Failed to delete edge from graph."); - - ls.db_len--; - - pthread_rwlock_unlock(&ls.db_lock); - set_pff_modified(false); - free(a); - return 0; - } - } - - pthread_rwlock_unlock(&ls.db_lock); - - return -EPERM; -} - -static void * periodic_recalc_pff(void * o) -{ - bool modified; - struct routing_i * inst = (struct routing_i *) o; - - while (true) { - pthread_mutex_lock(&inst->lock); - modified = inst->modified; - inst->modified = false; - pthread_mutex_unlock(&inst->lock); - - if (modified) - calculate_pff(inst); - sleep(RECALC_TIME); - } - - return (void *) 0; -} - -static void send_lsm(uint64_t src, - uint64_t dst, - uint64_t seqno) -{ - struct lsa lsm; - struct list_head * p; - - lsm.d_addr = hton64(dst); - lsm.s_addr = hton64(src); - lsm.seqno = hton64(seqno); - - list_for_each(p, &ls.nbs) { - struct nb * nb = list_entry(p, struct nb, next); - if (nb->type == NB_MGMT) - flow_write(nb->fd, &lsm, sizeof(lsm)); - } -} - -/* replicate the lsdb to a mgmt neighbor */ -static void lsdb_replicate(int fd) -{ - struct list_head * p; - struct list_head * h; - struct list_head copy; - - list_head_init(©); - - /* Lock the lsdb, copy the lsms and send outside of lock. */ - pthread_rwlock_rdlock(&ls.db_lock); - - list_for_each(p, &ls.db) { - struct adjacency * adj; - struct adjacency * cpy; - adj = list_entry(p, struct adjacency, next); - cpy = malloc(sizeof(*cpy)); - if (cpy == NULL) { - log_warn("Failed to replicate full lsdb."); - break; - } - - cpy->dst = adj->dst; - cpy->src = adj->src; - cpy->seqno = adj->seqno; - - list_add_tail(&cpy->next, ©); - } - - pthread_rwlock_unlock(&ls.db_lock); - - list_for_each_safe(p, h, ©) { - struct lsa lsm; - struct adjacency * adj; - adj = list_entry(p, struct adjacency, next); - lsm.d_addr = hton64(adj->dst); - lsm.s_addr = hton64(adj->src); - lsm.seqno = hton64(adj->seqno); - list_del(&adj->next); - free(adj); - flow_write(fd, &lsm, sizeof(lsm)); - } -} - -static void * lsupdate(void * o) -{ - struct list_head * p; - struct list_head * h; - struct timespec now; - - (void) o; - - while (true) { - clock_gettime(CLOCK_REALTIME_COARSE, &now); - - pthread_rwlock_rdlock(&ls.db_lock); - - pthread_cleanup_push((void (*) (void *)) pthread_rwlock_unlock, - (void *) &ls.db_lock); - - list_for_each_safe(p, h, &ls.db) { - struct adjacency * adj; - adj = list_entry(p, struct adjacency, next); - if (now.tv_sec - adj->stamp > LS_TIMEO) { - list_del(&adj->next); - log_dbg("%" PRIu64 " - %" PRIu64" timed out.", - adj->src, adj->dst); - if (graph_del_edge(ls.graph, adj->src, - adj->dst)) - log_err("Failed to del edge."); - free(adj); - continue; - } - - if (adj->src == ipcpi.dt_addr) { - adj->seqno++; - send_lsm(adj->src, adj->dst, adj->seqno); - adj->stamp = now.tv_sec; - } - } - - pthread_cleanup_pop(true); - - sleep(LS_UPDATE_TIME); - } - - return (void *) 0; -} - -static void * ls_conn_handle(void * o) -{ - struct conn conn; - - (void) o; - - while (true) { - if (connmgr_wait(COMPID_MGMT, &conn)) { - log_err("Failed to get next MGMT connection."); - continue; - } - - /* NOTE: connection acceptance policy could be here. */ - - notifier_event(NOTIFY_MGMT_CONN_ADD, &conn); - } - - return 0; -} - - -static void forward_lsm(uint8_t * buf, - size_t len, - int in_fd) -{ - struct list_head * p; - - pthread_rwlock_rdlock(&ls.db_lock); - - pthread_cleanup_push((void (*))(void *) pthread_rwlock_unlock, - &ls.db_lock); - - list_for_each(p, &ls.nbs) { - struct nb * nb = list_entry(p, struct nb, next); - if (nb->type == NB_MGMT && nb->fd != in_fd) - flow_write(nb->fd, buf, len); - } - - pthread_cleanup_pop(true); -} - -static void * lsreader(void * o) -{ - fqueue_t * fq; - int ret; - uint8_t buf[sizeof(struct lsa)]; - int fd; - qosspec_t qs; - struct lsa * msg; - size_t len; - - (void) o; - - memset(&qs, 0, sizeof(qs)); - - fq = fqueue_create(); - if (fq == NULL) - return (void *) -1; - - pthread_cleanup_push((void (*) (void *)) fqueue_destroy, - (void *) fq); - - while (true) { - ret = fevent(ls.mgmt_set, fq, NULL); - if (ret < 0) { - log_warn("Event error: %d.", ret); - continue; - } - - while ((fd = fqueue_next(fq)) >= 0) { - if (fqueue_type(fq) != FLOW_PKT) - continue; - - len = flow_read(fd, buf, sizeof(*msg)); - if (len <= 0 || len != sizeof(*msg)) - continue; - - msg = (struct lsa *) buf; - - if (lsdb_add_link(ntoh64(msg->s_addr), - ntoh64(msg->d_addr), - ntoh64(msg->seqno), - &qs)) - continue; - - forward_lsm(buf, len, fd); - } - } - - pthread_cleanup_pop(true); - - return (void *) 0; -} - -static void flow_event(int fd, - bool up) -{ - - struct list_head * p; - - log_dbg("Notifying routing instances of flow event."); - - pthread_mutex_lock(&ls.routing_i_lock); - - list_for_each(p, &ls.routing_instances) { - struct routing_i * ri = list_entry(p, struct routing_i, next); - pff_flow_state_change(ri->pff, fd, up); - } - - pthread_mutex_unlock(&ls.routing_i_lock); -} - -static void handle_event(void * self, - int event, - const void * o) -{ - /* FIXME: Apply correct QoS on graph */ - struct conn * c; - qosspec_t qs; - int flags; - - (void) self; - - c = (struct conn *) o; - - memset(&qs, 0, sizeof(qs)); - - switch (event) { - case NOTIFY_DT_CONN_ADD: - pthread_rwlock_rdlock(&ls.db_lock); - send_lsm(ipcpi.dt_addr, c->conn_info.addr, 0); - pthread_rwlock_unlock(&ls.db_lock); - - if (lsdb_add_nb(c->conn_info.addr, c->flow_info.fd, NB_DT)) - log_dbg("Failed to add neighbor to LSDB."); - - if (lsdb_add_link(ipcpi.dt_addr, c->conn_info.addr, 0, &qs)) - log_dbg("Failed to add new adjacency to LSDB."); - break; - case NOTIFY_DT_CONN_DEL: - flow_event(c->flow_info.fd, false); - - if (lsdb_del_nb(c->conn_info.addr, c->flow_info.fd)) - log_dbg("Failed to delete neighbor from LSDB."); - - if (lsdb_del_link(ipcpi.dt_addr, c->conn_info.addr)) - log_dbg("Local link was not in LSDB."); - break; - case NOTIFY_DT_CONN_QOS: - log_dbg("QoS changes currently unsupported."); - break; - case NOTIFY_DT_CONN_UP: - flow_event(c->flow_info.fd, true); - break; - case NOTIFY_DT_CONN_DOWN: - flow_event(c->flow_info.fd, false); - break; - case NOTIFY_MGMT_CONN_ADD: - fccntl(c->flow_info.fd, FLOWGFLAGS, &flags); - fccntl(c->flow_info.fd, FLOWSFLAGS, flags | FLOWFRNOPART); - fset_add(ls.mgmt_set, c->flow_info.fd); - if (lsdb_add_nb(c->conn_info.addr, c->flow_info.fd, NB_MGMT)) - log_warn("Failed to add mgmt neighbor to LSDB."); - /* replicate the entire lsdb */ - lsdb_replicate(c->flow_info.fd); - break; - case NOTIFY_MGMT_CONN_DEL: - fset_del(ls.mgmt_set, c->flow_info.fd); - if (lsdb_del_nb(c->conn_info.addr, c->flow_info.fd)) - log_warn("Failed to delete mgmt neighbor from LSDB."); - break; - default: - break; - } -} - -struct routing_i * link_state_routing_i_create(struct pff * pff) -{ - struct routing_i * tmp; - - assert(pff); - - tmp = malloc(sizeof(*tmp)); - if (tmp == NULL) - goto fail_tmp; - - tmp->pff = pff; - tmp->modified = false; - - if (pthread_mutex_init(&tmp->lock, NULL)) - goto fail_instance_lock_init; - - if (pthread_create(&tmp->calculator, NULL, - periodic_recalc_pff, tmp)) - goto fail_pthread_create_lsupdate; - - pthread_mutex_lock(&ls.routing_i_lock); - - list_add(&tmp->next, &ls.routing_instances); - - pthread_mutex_unlock(&ls.routing_i_lock); - - return tmp; - - fail_pthread_create_lsupdate: - pthread_mutex_destroy(&tmp->lock); - fail_instance_lock_init: - free(tmp); - fail_tmp: - return NULL; -} - -void link_state_routing_i_destroy(struct routing_i * instance) -{ - assert(instance); - - pthread_mutex_lock(&ls.routing_i_lock); - - list_del(&instance->next); - - pthread_mutex_unlock(&ls.routing_i_lock); - - pthread_cancel(instance->calculator); - - pthread_join(instance->calculator, NULL); - - pthread_mutex_destroy(&instance->lock); - - free(instance); -} - -int link_state_init(enum pol_routing pr) -{ - struct conn_info info; - - memset(&info, 0, sizeof(info)); - - strcpy(info.comp_name, LS_COMP); - strcpy(info.protocol, LS_PROTO); - info.pref_version = 1; - info.pref_syntax = PROTO_GPB; - info.addr = ipcpi.dt_addr; - - switch (pr) { - case ROUTING_LINK_STATE: - log_dbg("Using link state routing policy."); - ls.routing_algo = ROUTING_SIMPLE; - break; - case ROUTING_LINK_STATE_LFA: - log_dbg("Using Loop-Free Alternates policy."); - ls.routing_algo = ROUTING_LFA; - break; - default: - goto fail_graph; - } - - ls.graph = graph_create(); - if (ls.graph == NULL) - goto fail_graph; - - if (notifier_reg(handle_event, NULL)) - goto fail_notifier_reg; - - if (pthread_rwlock_init(&ls.db_lock, NULL)) - goto fail_db_lock_init; - - if (pthread_mutex_init(&ls.routing_i_lock, NULL)) - goto fail_routing_i_lock_init; - - if (connmgr_comp_init(COMPID_MGMT, &info)) - goto fail_connmgr_comp_init; - - ls.mgmt_set = fset_create(); - if (ls.mgmt_set == NULL) - goto fail_fset_create; - - list_head_init(&ls.db); - list_head_init(&ls.nbs); - list_head_init(&ls.routing_instances); - - if (pthread_create(&ls.lsupdate, NULL, lsupdate, NULL)) - goto fail_pthread_create_lsupdate; - - if (pthread_create(&ls.lsreader, NULL, lsreader, NULL)) - goto fail_pthread_create_lsreader; - - if (pthread_create(&ls.listener, NULL, ls_conn_handle, NULL)) - goto fail_pthread_create_listener; - - if (rib_reg(LSDB, &r_ops)) - goto fail_rib_reg; - - ls.db_len = 0; - ls.nbs_len = 0; - - return 0; - - fail_rib_reg: - pthread_cancel(ls.listener); - pthread_join(ls.listener, NULL); - fail_pthread_create_listener: - pthread_cancel(ls.lsreader); - pthread_join(ls.lsreader, NULL); - fail_pthread_create_lsreader: - pthread_cancel(ls.lsupdate); - pthread_join(ls.lsupdate, NULL); - fail_pthread_create_lsupdate: - fset_destroy(ls.mgmt_set); - fail_fset_create: - connmgr_comp_fini(COMPID_MGMT); - fail_connmgr_comp_init: - pthread_mutex_destroy(&ls.routing_i_lock); - fail_routing_i_lock_init: - pthread_rwlock_destroy(&ls.db_lock); - fail_db_lock_init: - notifier_unreg(handle_event); - fail_notifier_reg: - graph_destroy(ls.graph); - fail_graph: - return -1; -} - -void link_state_fini(void) -{ - struct list_head * p; - struct list_head * h; - - rib_unreg(LSDB); - - pthread_cancel(ls.listener); - pthread_join(ls.listener, NULL); - - pthread_cancel(ls.lsreader); - pthread_join(ls.lsreader, NULL); - - pthread_cancel(ls.lsupdate); - pthread_join(ls.lsupdate, NULL); - - fset_destroy(ls.mgmt_set); - - connmgr_comp_fini(COMPID_MGMT); - - graph_destroy(ls.graph); - - pthread_rwlock_wrlock(&ls.db_lock); - - list_for_each_safe(p, h, &ls.db) { - struct adjacency * a = list_entry(p, struct adjacency, next); - list_del(&a->next); - free(a); - } - - pthread_rwlock_unlock(&ls.db_lock); - - pthread_rwlock_destroy(&ls.db_lock); - - pthread_mutex_destroy(&ls.routing_i_lock); - - notifier_unreg(handle_event); -} diff --git a/src/ipcpd/normal/pol/link_state.h b/src/ipcpd/normal/pol/link_state.h deleted file mode 100644 index 3fcb03ff..00000000 --- a/src/ipcpd/normal/pol/link_state.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Link state routing policy - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_POL_LINK_STATE_H -#define OUROBOROS_IPCPD_NORMAL_POL_LINK_STATE_H - -#define LS_COMP "Management" -#define LS_PROTO "LSP" - -#include "pol-routing-ops.h" - -int link_state_init(enum pol_routing pr); - -void link_state_fini(void); - -struct routing_i * link_state_routing_i_create(struct pff * pff); - -void link_state_routing_i_destroy(struct routing_i * instance); - -struct pol_routing_ops link_state_ops; - -#endif /* OUROBOROS_IPCPD_NORMAL_POL_LINK_STATE_H */ diff --git a/src/ipcpd/normal/pol/simple_pff.c b/src/ipcpd/normal/pol/simple_pff.c deleted file mode 100644 index 4338c53c..00000000 --- a/src/ipcpd/normal/pol/simple_pff.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Simple PDU Forwarding Function - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#define _POSIX_C_SOURCE 200112L - -#include "config.h" - -#include <ouroboros/hashtable.h> -#include <ouroboros/errno.h> - -#include <assert.h> -#include <pthread.h> - -#include "simple_pff.h" - -struct pff_i { - struct htable * table; - pthread_rwlock_t lock; -}; - -struct pol_pff_ops simple_pff_ops = { - .create = simple_pff_create, - .destroy = simple_pff_destroy, - .lock = simple_pff_lock, - .unlock = simple_pff_unlock, - .add = simple_pff_add, - .update = simple_pff_update, - .del = simple_pff_del, - .flush = simple_pff_flush, - .nhop = simple_pff_nhop, - .flow_state_change = NULL -}; - -struct pff_i * simple_pff_create(void) -{ - struct pff_i * tmp; - - tmp = malloc(sizeof(*tmp)); - if (tmp == NULL) - return NULL; - - if (pthread_rwlock_init(&tmp->lock, NULL)) { - free(tmp); - return NULL; - } - - tmp->table = htable_create(PFT_SIZE, false); - if (tmp->table == NULL) { - pthread_rwlock_destroy(&tmp->lock); - free(tmp); - return NULL; - } - - return tmp; -} - -void simple_pff_destroy(struct pff_i * pff_i) -{ - assert(pff_i); - - htable_destroy(pff_i->table); - - pthread_rwlock_destroy(&pff_i->lock); - free(pff_i); -} - -void simple_pff_lock(struct pff_i * pff_i) -{ - pthread_rwlock_wrlock(&pff_i->lock); -} - -void simple_pff_unlock(struct pff_i * pff_i) -{ - pthread_rwlock_unlock(&pff_i->lock); -} - -int simple_pff_add(struct pff_i * pff_i, - uint64_t addr, - int * fd, - size_t len) -{ - int * val; - - assert(pff_i); - assert(len > 0); - - (void) len; - - val = malloc(sizeof(*val)); - if (val == NULL) - return -ENOMEM; - - *val = fd[0]; - - if (htable_insert(pff_i->table, addr, val, 1)) { - free(val); - return -1; - } - - return 0; -} - -int simple_pff_update(struct pff_i * pff_i, - uint64_t addr, - int * fd, - size_t len) -{ - int * val; - - assert(pff_i); - assert(len > 0); - - (void) len; - - val = malloc(sizeof(*val)); - if (val == NULL) - return -ENOMEM; - *val = fd[0]; - - if (htable_delete(pff_i->table, addr)) { - free(val); - return -1; - } - - if (htable_insert(pff_i->table, addr, val, 1)) { - free(val); - return -1; - } - - return 0; -} - -int simple_pff_del(struct pff_i * pff_i, - uint64_t addr) -{ - assert(pff_i); - - if (htable_delete(pff_i->table, addr)) - return -1; - - return 0; -} - -void simple_pff_flush(struct pff_i * pff_i) -{ - assert(pff_i); - - htable_flush(pff_i->table); -} - -int simple_pff_nhop(struct pff_i * pff_i, - uint64_t addr) -{ - void * j; - size_t len; - int fd = -1; - - assert(pff_i); - - pthread_rwlock_rdlock(&pff_i->lock); - - if (!htable_lookup(pff_i->table, addr, &j, &len)) - fd = *((int *) j); - - pthread_rwlock_unlock(&pff_i->lock); - - return fd; -} diff --git a/src/ipcpd/normal/pol/simple_pff.h b/src/ipcpd/normal/pol/simple_pff.h deleted file mode 100644 index 08504e4e..00000000 --- a/src/ipcpd/normal/pol/simple_pff.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Simple policy for PFF - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_SIMPLE_PFF_H -#define OUROBOROS_IPCPD_NORMAL_SIMPLE_PFF_H - -#include "pol-pff-ops.h" - -struct pff_i * simple_pff_create(void); - -void simple_pff_destroy(struct pff_i * pff_i); - -void simple_pff_lock(struct pff_i * pff_i); - -void simple_pff_unlock(struct pff_i * pff_i); - -int simple_pff_add(struct pff_i * pff_i, - uint64_t addr, - int * fd, - size_t len); - -int simple_pff_update(struct pff_i * pff_i, - uint64_t addr, - int * fd, - size_t len); - -int simple_pff_del(struct pff_i * pff_i, - uint64_t addr); - -void simple_pff_flush(struct pff_i * pff_i); - -/* Returns fd towards next hop */ -int simple_pff_nhop(struct pff_i * pff_i, - uint64_t addr); - -struct pol_pff_ops simple_pff_ops; - -#endif /* OUROBOROS_IPCPD_NORMAL_SIMPLE_PFF_H */ diff --git a/src/ipcpd/normal/pol/tests/CMakeLists.txt b/src/ipcpd/normal/pol/tests/CMakeLists.txt deleted file mode 100644 index d0652533..00000000 --- a/src/ipcpd/normal/pol/tests/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -get_filename_component(CURRENT_SOURCE_PARENT_DIR - ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY) -get_filename_component(CURRENT_BINARY_PARENT_DIR - ${CMAKE_CURRENT_BINARY_DIR} DIRECTORY) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) - -include_directories(${CURRENT_SOURCE_PARENT_DIR}) -include_directories(${CURRENT_BINARY_PARENT_DIR}) - -include_directories(${CMAKE_SOURCE_DIR}/include) -include_directories(${CMAKE_BINARY_DIR}/include) - -get_filename_component(PARENT_PATH ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY) -get_filename_component(PARENT_DIR ${PARENT_PATH} NAME) - -create_test_sourcelist(${PARENT_DIR}_tests test_suite.c - # Add new tests here - graph_test.c - ) - -add_executable(${PARENT_DIR}_test EXCLUDE_FROM_ALL ${${PARENT_DIR}_tests}) -target_link_libraries(${PARENT_DIR}_test ouroboros-common) - -add_dependencies(check ${PARENT_DIR}_test) - -set(tests_to_run ${${PARENT_DIR}_tests}) -remove(tests_to_run test_suite.c) - -foreach (test ${tests_to_run}) - get_filename_component(test_name ${test} NAME_WE) - add_test(${test_name} ${C_TEST_PATH}/${PARENT_DIR}_test ${test_name}) -endforeach (test) diff --git a/src/ipcpd/normal/pol/tests/graph_test.c b/src/ipcpd/normal/pol/tests/graph_test.c deleted file mode 100644 index a312c1a8..00000000 --- a/src/ipcpd/normal/pol/tests/graph_test.c +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Test of the graph structure - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#define _POSIX_C_SOURCE 200112L - -#include <ouroboros/utils.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "graph.c" - -struct graph * graph; -struct list_head table; -qosspec_t qs; - -int graph_test_entries(int entries) -{ - struct list_head * p; - int i = 0; - - if (graph_routing_table(graph, ROUTING_SIMPLE, 1, &table)) { - printf("Failed to get routing table.\n"); - return -1; - } - - list_for_each(p, &table) - i++; - - if (i != entries) { - printf("Wrong number of entries.\n"); - graph_free_routing_table(graph, &table); - return -1; - } - - graph_free_routing_table(graph, &table); - - return 0; -} - -int graph_test_double_link(void) -{ - struct list_head * p; - int i = 0; - - if (graph_routing_table(graph, ROUTING_SIMPLE, 1, &table)) { - printf("Failed to get routing table.\n"); - return -1; - } - - list_for_each(p, &table) - i++; - - if (i != 2) { - printf("Wrong number of entries.\n"); - graph_free_routing_table(graph, &table); - return -1; - } - - list_for_each(p, &table) { - struct routing_table * t = - list_entry(p, struct routing_table, next); - struct nhop * n = - list_first_entry(&t->nhops, struct nhop, next); - - if ((t->dst != 2 && n->nhop != 2) || - (t->dst != 3 && n->nhop != 2)) { - printf("Wrong routing entry.\n"); - graph_free_routing_table(graph, &table); - return -1; - } - } - - graph_free_routing_table(graph, &table); - - return 0; -} - -int graph_test_single_link(void) -{ - struct list_head * p; - int i = 0; - - if (graph_routing_table(graph, ROUTING_SIMPLE, 1, &table)) { - printf("Failed to get routing table.\n"); - return -1; - } - - list_for_each(p, &table) - i++; - - if (i != 1) { - printf("Wrong number of entries.\n"); - graph_free_routing_table(graph, &table); - return -1; - } - - list_for_each(p, &table) { - struct routing_table * t = - list_entry(p, struct routing_table, next); - struct nhop * n = - list_first_entry(&t->nhops, struct nhop, next); - - if (t->dst != 2 && n->nhop != 2) { - printf("Wrong routing entry.\n"); - graph_free_routing_table(graph, &table); - return -1; - } - } - - graph_free_routing_table(graph, &table); - - return 0; -} - -int graph_test(int argc, - char ** argv) -{ - int nhop; - int dst; - struct list_head * p; - - (void) argc; - (void) argv; - - memset(&qs, 0, sizeof(qs)); - - graph = graph_create(); - if (graph == NULL) { - printf("Failed to create graph.\n"); - return -1; - } - - graph_destroy(graph); - - graph = graph_create(); - if (graph == NULL) { - printf("Failed to create graph.\n"); - return -1; - } - - if (graph_update_edge(graph, 1, 2, qs)) { - printf("Failed to add edge.\n"); - graph_destroy(graph); - return -1; - } - - if (graph_update_edge(graph, 2, 1, qs)) { - printf("Failed to add edge.\n"); - graph_destroy(graph); - return -1; - } - - if (graph_test_single_link()) { - graph_destroy(graph); - return -1; - } - - if (graph_update_edge(graph, 2, 3, qs)) { - printf("Failed to add edge.\n"); - graph_destroy(graph); - return -1; - } - - if (graph_update_edge(graph, 3, 2, qs)) { - printf("Failed to add edge.\n"); - graph_destroy(graph); - return -1; - } - - - if (graph_test_double_link()) { - graph_destroy(graph); - return -1; - } - - if (graph_del_edge(graph, 2, 3)) { - printf("Failed to delete edge.\n"); - graph_destroy(graph); - return -1; - } - - if (graph_del_edge(graph, 3, 2)) { - printf("Failed to delete edge.\n"); - graph_destroy(graph); - return -1; - } - - if (graph_test_single_link()) { - graph_destroy(graph); - return -1; - } - - graph_update_edge(graph, 2, 3, qs); - graph_update_edge(graph, 3, 2, qs); - graph_update_edge(graph, 1, 3, qs); - graph_update_edge(graph, 3, 1, qs); - - if (graph_test_entries(2)) { - graph_destroy(graph); - return -1; - } - - graph_update_edge(graph, 3, 4, qs); - graph_update_edge(graph, 4, 3, qs); - graph_update_edge(graph, 4, 5, qs); - graph_update_edge(graph, 5, 4, qs); - - if (graph_test_entries(4)) { - graph_destroy(graph); - return -1; - } - - graph_update_edge(graph, 2, 6, qs); - graph_update_edge(graph, 6, 2, qs); - graph_update_edge(graph, 6, 7, qs); - graph_update_edge(graph, 7, 6, qs); - graph_update_edge(graph, 3, 7, qs); - graph_update_edge(graph, 7, 3, qs); - - if (graph_test_entries(6)) { - graph_destroy(graph); - return -1; - } - - if (graph_routing_table(graph, ROUTING_SIMPLE, 1, &table)) { - printf("Failed to get routing table.\n"); - return -1; - } - - list_for_each(p, &table) { - struct routing_table * t = - list_entry(p, struct routing_table, next); - struct nhop * n = - list_first_entry(&t->nhops, struct nhop, next); - - dst = t->dst; - nhop = n->nhop; - - if (dst == 3 && nhop != 3) { - printf("Wrong entry."); - graph_free_routing_table(graph, &table); - return -1; - } - - if (dst == 2 && nhop != 2) { - printf("Wrong entry."); - graph_free_routing_table(graph, &table); - return -1; - } - - if (dst == 6 && nhop != 2) { - printf("Wrong entry."); - graph_free_routing_table(graph, &table); - return -1; - } - - if (dst == 4 && nhop != 3) { - printf("Wrong entry."); - graph_free_routing_table(graph, &table); - return -1; - } - - if (dst == 5 && nhop != 3) { - printf("Wrong entry."); - graph_free_routing_table(graph, &table); - return -1; - } - - if (dst == 7 && nhop != 3) { - printf("Wrong entry."); - graph_free_routing_table(graph, &table); - return -1; - } - } - - graph_free_routing_table(graph, &table); - - return 0; -} diff --git a/src/ipcpd/normal/psched.c b/src/ipcpd/normal/psched.c deleted file mode 100644 index 6e8c4e0e..00000000 --- a/src/ipcpd/normal/psched.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Packet scheduler component - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#if defined(__linux__) || defined(__CYGWIN__) -#define _DEFAULT_SOURCE -#else -#define _POSIX_C_SOURCE 200112L -#endif - -#include "config.h" - -#include <ouroboros/errno.h> -#include <ouroboros/notifier.h> - -#include "ipcp.h" -#include "psched.h" -#include "connmgr.h" - -#include <assert.h> -#include <sched.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> - -static int qos_prio [] = { - QOS_PRIO_BE, - QOS_PRIO_VIDEO, - QOS_PRIO_VOICE, -}; - -struct psched { - fset_t * set[QOS_CUBE_MAX]; - next_packet_fn_t callback; - pthread_t readers[QOS_CUBE_MAX * IPCP_SCHED_THR_MUL]; -}; - -struct sched_info { - struct psched * sch; - qoscube_t qc; -}; - -static void cleanup_reader(void * o) -{ - fqueue_destroy((fqueue_t *) o); -} - -static void * packet_reader(void * o) -{ - struct psched * sched; - struct shm_du_buff * sdb; - int fd; - fqueue_t * fq; - qoscube_t qc; - - sched = ((struct sched_info *) o)->sch; - qc = ((struct sched_info *) o)->qc; - - ipcp_lock_to_core(); - - free(o); - - fq = fqueue_create(); - if (fq == NULL) - return (void *) -1; - - pthread_cleanup_push(cleanup_reader, fq); - - while (true) { - int ret = fevent(sched->set[qc], fq, NULL); - if (ret < 0) - continue; - - while ((fd = fqueue_next(fq)) >= 0) { - switch (fqueue_type(fq)) { - case FLOW_DEALLOC: - notifier_event(NOTIFY_DT_FLOW_DEALLOC, &fd); - break; - case FLOW_DOWN: - notifier_event(NOTIFY_DT_FLOW_DOWN, &fd); - break; - case FLOW_UP: - notifier_event(NOTIFY_DT_FLOW_UP, &fd); - break; - case FLOW_PKT: - if (ipcp_flow_read(fd, &sdb)) - continue; - - sched->callback(fd, qc, sdb); - break; - default: - break; - } - } - } - - pthread_cleanup_pop(true); - - return (void *) 0; -} - -struct psched * psched_create(next_packet_fn_t callback) -{ - struct psched * psched; - struct sched_info * infos[QOS_CUBE_MAX * IPCP_SCHED_THR_MUL]; - int i; - int j; - - assert(callback); - - psched = malloc(sizeof(*psched)); - if (psched == NULL) - goto fail_malloc; - - psched->callback = callback; - - for (i = 0; i < QOS_CUBE_MAX; ++i) { - psched->set[i] = fset_create(); - if (psched->set[i] == NULL) { - for (j = 0; j < i; ++j) - fset_destroy(psched->set[j]); - goto fail_flow_set; - } - } - - for (i = 0; i < QOS_CUBE_MAX * IPCP_SCHED_THR_MUL; ++i) { - infos[i] = malloc(sizeof(*infos[i])); - if (infos[i] == NULL) { - for (j = 0; j < i; ++j) - free(infos[j]); - goto fail_infos; - } - infos[i]->sch = psched; - infos[i]->qc = i % QOS_CUBE_MAX; - } - - for (i = 0; i < QOS_CUBE_MAX * IPCP_SCHED_THR_MUL; ++i) { - if (pthread_create(&psched->readers[i], NULL, - packet_reader, infos[i])) { - for (j = 0; j < i; ++j) - pthread_cancel(psched->readers[j]); - for (j = 0; j < i; ++j) - pthread_join(psched->readers[j], NULL); - for (j = i; j < QOS_CUBE_MAX * IPCP_SCHED_THR_MUL; ++j) - free(infos[i]); - goto fail_infos; - } - } - - for (i = 0; i < QOS_CUBE_MAX * IPCP_SCHED_THR_MUL; ++i) { - struct sched_param par; - int pol = SCHED_RR; - int min; - int max; - - min = sched_get_priority_min(pol); - max = sched_get_priority_max(pol); - - min = (max - min) / 2; - - par.sched_priority = min + - (qos_prio[i % QOS_CUBE_MAX] * (max - min) / 99); - - if (pthread_setschedparam(psched->readers[i], pol, &par)) - goto fail_sched; - } - - return psched; - - fail_sched: - for (j = 0; j < QOS_CUBE_MAX * IPCP_SCHED_THR_MUL; ++j) - pthread_cancel(psched->readers[j]); - for (j = 0; j < QOS_CUBE_MAX * IPCP_SCHED_THR_MUL; ++j) - pthread_join(psched->readers[j], NULL); - fail_infos: - for (j = 0; j < QOS_CUBE_MAX; ++j) - fset_destroy(psched->set[j]); - fail_flow_set: - free(psched); - fail_malloc: - return NULL; -} - -void psched_destroy(struct psched * psched) -{ - int i; - - assert(psched); - - for (i = 0; i < QOS_CUBE_MAX * IPCP_SCHED_THR_MUL; ++i) { - pthread_cancel(psched->readers[i]); - pthread_join(psched->readers[i], NULL); - } - - for (i = 0; i < QOS_CUBE_MAX; ++i) - fset_destroy(psched->set[i]); - - free(psched); -} - -void psched_add(struct psched * psched, - int fd) -{ - qoscube_t qc; - - assert(psched); - - ipcp_flow_get_qoscube(fd, &qc); - fset_add(psched->set[qc], fd); -} - -void psched_del(struct psched * psched, - int fd) -{ - qoscube_t qc; - - assert(psched); - - ipcp_flow_get_qoscube(fd, &qc); - fset_del(psched->set[qc], fd); -} diff --git a/src/ipcpd/normal/psched.h b/src/ipcpd/normal/psched.h deleted file mode 100644 index 3d7896cc..00000000 --- a/src/ipcpd/normal/psched.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Packet scheduler component - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_PSCHED_H -#define OUROBOROS_IPCPD_NORMAL_PSCHED_H - -#include <ouroboros/ipcp-dev.h> -#include <ouroboros/fqueue.h> - -typedef void (* next_packet_fn_t)(int fd, - qoscube_t qc, - struct shm_du_buff * sdb); - -struct psched * psched_create(next_packet_fn_t callback); - -void psched_destroy(struct psched * psched); - -void psched_add(struct psched * psched, - int fd); - -void psched_del(struct psched * psched, - int fd); - -#endif /* OUROBOROS_IPCPD_NORMAL_PSCHED_H */ diff --git a/src/ipcpd/normal/routing.c b/src/ipcpd/normal/routing.c deleted file mode 100644 index 2cd24707..00000000 --- a/src/ipcpd/normal/routing.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Routing component of the IPCP - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#define _POSIX_C_SOURCE 200112L - -#include <ouroboros/errno.h> - -#include "routing.h" -#include "pol/link_state.h" - -struct pol_routing_ops * r_ops; - -int routing_init(enum pol_routing pr) -{ - switch (pr) { - case ROUTING_LINK_STATE: - case ROUTING_LINK_STATE_LFA: - r_ops = &link_state_ops; - break; - default: - return -ENOTSUP; - } - - return r_ops->init(pr); -} - -struct routing_i * routing_i_create(struct pff * pff) -{ - return r_ops->routing_i_create(pff); -} - -void routing_i_destroy(struct routing_i * instance) -{ - return r_ops->routing_i_destroy(instance); -} - -void routing_fini(void) -{ - r_ops->fini(); -} diff --git a/src/ipcpd/normal/routing.h b/src/ipcpd/normal/routing.h deleted file mode 100644 index 9bbcd08b..00000000 --- a/src/ipcpd/normal/routing.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Routing component of the IPCP - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#ifndef OUROBOROS_IPCPD_NORMAL_ROUTING_H -#define OUROBOROS_IPCPD_NORMAL_ROUTING_H - -#include <ouroboros/ipcp.h> -#include <ouroboros/qos.h> - -#include "pff.h" - -#include <stdint.h> - -int routing_init(enum pol_routing pr); - -void routing_fini(void); - -struct routing_i * routing_i_create(struct pff * pff); - -void routing_i_destroy(struct routing_i * instance); - -#endif /* OUROBOROS_IPCPD_NORMAL_ROUTING_H */ diff --git a/src/ipcpd/normal/tests/CMakeLists.txt b/src/ipcpd/normal/tests/CMakeLists.txt deleted file mode 100644 index 482711d5..00000000 --- a/src/ipcpd/normal/tests/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -get_filename_component(CURRENT_SOURCE_PARENT_DIR - ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY) -get_filename_component(CURRENT_BINARY_PARENT_DIR - ${CMAKE_CURRENT_BINARY_DIR} DIRECTORY) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) - -include_directories(${CURRENT_SOURCE_PARENT_DIR}) -include_directories(${CURRENT_BINARY_PARENT_DIR}) - -include_directories(${CMAKE_SOURCE_DIR}/include) -include_directories(${CMAKE_BINARY_DIR}/include) - -get_filename_component(PARENT_PATH ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY) -get_filename_component(PARENT_DIR ${PARENT_PATH} NAME) - -create_test_sourcelist(${PARENT_DIR}_tests test_suite.c - # Add new tests here - dht_test.c - ) - -protobuf_generate_c(KAD_PROTO_SRCS KAD_PROTO_HDRS ../kademlia.proto) - -add_executable(${PARENT_DIR}_test EXCLUDE_FROM_ALL ${${PARENT_DIR}_tests} - ${KAD_PROTO_SRCS}) -target_link_libraries(${PARENT_DIR}_test ouroboros-common) - -add_dependencies(check ${PARENT_DIR}_test) - -set(tests_to_run ${${PARENT_DIR}_tests}) -remove(tests_to_run test_suite.c) - -foreach (test ${tests_to_run}) - get_filename_component(test_name ${test} NAME_WE) - add_test(${test_name} ${C_TEST_PATH}/${PARENT_DIR}_test ${test_name}) -endforeach (test) diff --git a/src/ipcpd/normal/tests/dht_test.c b/src/ipcpd/normal/tests/dht_test.c deleted file mode 100644 index 26e9102e..00000000 --- a/src/ipcpd/normal/tests/dht_test.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2019 - * - * Unit tests of the DHT - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#define __DHT_TEST__ - -#include "dht.c" - -#include <pthread.h> -#include <time.h> -#include <stdlib.h> -#include <stdio.h> - -#define KEY_LEN 32 - -#define EXP 86400 -#define CONTACTS 1000 - -int dht_test(int argc, - char ** argv) -{ - struct dht * dht; - uint64_t addr = 0x0D1F; - uint8_t key[KEY_LEN]; - size_t i; - - (void) argc; - (void) argv; - - dht = dht_create(addr); - if (dht == NULL) { - printf("Failed to create dht.\n"); - return -1; - } - - dht_destroy(dht); - - dht = dht_create(addr); - if (dht == NULL) { - printf("Failed to re-create dht.\n"); - return -1; - } - - if (dht_bootstrap(dht, KEY_LEN, EXP)) { - printf("Failed to bootstrap dht.\n"); - dht_destroy(dht); - return -1; - } - - dht_destroy(dht); - - dht = dht_create(addr); - if (dht == NULL) { - printf("Failed to re-create dht.\n"); - return -1; - } - - if (dht_bootstrap(dht, KEY_LEN, EXP)) { - printf("Failed to bootstrap dht.\n"); - dht_destroy(dht); - return -1; - } - - for (i = 0; i < CONTACTS; ++i) { - uint64_t addr; - random_buffer(&addr, sizeof(addr)); - random_buffer(key, KEY_LEN); - pthread_rwlock_wrlock(&dht->lock); - if (dht_update_bucket(dht, key, addr)) { - pthread_rwlock_unlock(&dht->lock); - printf("Failed to update bucket.\n"); - dht_destroy(dht); - return -1; - } - pthread_rwlock_unlock(&dht->lock); - } - - dht_destroy(dht); - - return 0; -} |