diff options
Diffstat (limited to 'src/ipcpd')
-rw-r--r-- | src/ipcpd/CMakeLists.txt | 15 | ||||
-rw-r--r-- | src/ipcpd/broadcast/CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/ipcpd/broadcast/comp.h | 45 | ||||
-rw-r--r-- | src/ipcpd/broadcast/connmgr.c | 496 | ||||
-rw-r--r-- | src/ipcpd/broadcast/connmgr.h | 71 | ||||
-rw-r--r-- | src/ipcpd/broadcast/dt.c | 46 | ||||
-rw-r--r-- | src/ipcpd/broadcast/dt.h | 6 | ||||
-rw-r--r-- | src/ipcpd/broadcast/enroll.c | 363 | ||||
-rw-r--r-- | src/ipcpd/broadcast/enroll.h | 47 | ||||
-rw-r--r-- | src/ipcpd/broadcast/main.c | 142 | ||||
-rw-r--r-- | src/ipcpd/common/comp.h (renamed from src/ipcpd/unicast/comp.h) | 18 | ||||
-rw-r--r-- | src/ipcpd/common/connmgr.c | 564 | ||||
-rw-r--r-- | src/ipcpd/common/connmgr.h (renamed from src/ipcpd/unicast/connmgr.h) | 14 | ||||
-rw-r--r-- | src/ipcpd/common/enroll.c | 337 | ||||
-rw-r--r-- | src/ipcpd/common/enroll.h (renamed from src/ipcpd/unicast/enroll.h) | 20 | ||||
-rw-r--r-- | src/ipcpd/config.h.in | 23 | ||||
-rw-r--r-- | src/ipcpd/eth/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/ipcpd/eth/dix.c | 6 | ||||
-rw-r--r-- | src/ipcpd/eth/eth.c | 441 | ||||
-rw-r--r-- | src/ipcpd/eth/llc.c | 6 | ||||
-rw-r--r-- | src/ipcpd/ipcp.c | 1009 | ||||
-rw-r--r-- | src/ipcpd/ipcp.h | 58 | ||||
-rw-r--r-- | src/ipcpd/local/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/ipcpd/local/main.c | 219 | ||||
-rw-r--r-- | src/ipcpd/raptor/CMakeLists.txt | 50 | ||||
-rw-r--r-- | src/ipcpd/raptor/main.c | 1114 | ||||
-rw-r--r-- | src/ipcpd/shim-data.c | 51 | ||||
-rw-r--r-- | src/ipcpd/shim-data.h | 6 | ||||
-rw-r--r-- | src/ipcpd/udp/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/ipcpd/udp/main.c | 611 | ||||
-rw-r--r-- | src/ipcpd/unicast/CMakeLists.txt | 36 | ||||
-rw-r--r-- | src/ipcpd/unicast/addr-auth.c (renamed from src/ipcpd/unicast/addr_auth.c) | 13 | ||||
-rw-r--r-- | src/ipcpd/unicast/addr-auth.h (renamed from src/ipcpd/unicast/addr_auth.h) | 6 | ||||
-rw-r--r-- | src/ipcpd/unicast/addr-auth/flat.c (renamed from src/ipcpd/unicast/pol/flat.c) | 32 | ||||
-rw-r--r-- | src/ipcpd/unicast/addr-auth/flat.h (renamed from src/ipcpd/unicast/pol/flat.h) | 10 | ||||
-rw-r--r-- | src/ipcpd/unicast/addr-auth/ops.h (renamed from src/ipcpd/unicast/pol-addr-auth-ops.h) | 14 | ||||
-rw-r--r-- | src/ipcpd/unicast/addr-auth/pol.h | 23 | ||||
-rw-r--r-- | src/ipcpd/unicast/ca.c | 109 | ||||
-rw-r--r-- | src/ipcpd/unicast/ca.h | 68 | ||||
-rw-r--r-- | src/ipcpd/unicast/ca/mb-ecn.c | 296 | ||||
-rw-r--r-- | src/ipcpd/unicast/ca/mb-ecn.h | 56 | ||||
-rw-r--r-- | src/ipcpd/unicast/ca/nop.c | 98 | ||||
-rw-r--r-- | src/ipcpd/unicast/ca/nop.h | 52 | ||||
-rw-r--r-- | src/ipcpd/unicast/ca/ops.h | 58 | ||||
-rw-r--r-- | src/ipcpd/unicast/ca/pol.h | 24 | ||||
-rw-r--r-- | src/ipcpd/unicast/connmgr.c | 504 | ||||
-rw-r--r-- | src/ipcpd/unicast/dht.h | 52 | ||||
-rw-r--r-- | src/ipcpd/unicast/dir.c | 58 | ||||
-rw-r--r-- | src/ipcpd/unicast/dir.h | 8 | ||||
-rw-r--r-- | src/ipcpd/unicast/dir/dht.c (renamed from src/ipcpd/unicast/dht.c) | 247 | ||||
-rw-r--r-- | src/ipcpd/unicast/dir/dht.h | 52 | ||||
-rw-r--r-- | src/ipcpd/unicast/dir/dht.proto (renamed from src/ipcpd/unicast/kademlia.proto) | 18 | ||||
-rw-r--r-- | src/ipcpd/unicast/dir/ops.h | 46 | ||||
-rw-r--r-- | src/ipcpd/unicast/dir/pol.h | 23 | ||||
-rw-r--r-- | src/ipcpd/unicast/dir/tests/CMakeLists.txt | 40 | ||||
-rw-r--r-- | src/ipcpd/unicast/dir/tests/dht_test.c (renamed from src/ipcpd/unicast/tests/dht_test.c) | 27 | ||||
-rw-r--r-- | src/ipcpd/unicast/dt.c | 363 | ||||
-rw-r--r-- | src/ipcpd/unicast/dt.h | 14 | ||||
-rw-r--r-- | src/ipcpd/unicast/enroll.c | 379 | ||||
-rw-r--r-- | src/ipcpd/unicast/fa.c | 853 | ||||
-rw-r--r-- | src/ipcpd/unicast/fa.h | 26 | ||||
-rw-r--r-- | src/ipcpd/unicast/main.c | 180 | ||||
-rw-r--r-- | src/ipcpd/unicast/pff.c | 19 | ||||
-rw-r--r-- | src/ipcpd/unicast/pff.h | 6 | ||||
-rw-r--r-- | src/ipcpd/unicast/pff/alternate.c (renamed from src/ipcpd/unicast/pol/alternate_pff.c) | 10 | ||||
-rw-r--r-- | src/ipcpd/unicast/pff/alternate.h (renamed from src/ipcpd/unicast/pol/alternate_pff.h) | 10 | ||||
-rw-r--r-- | src/ipcpd/unicast/pff/multipath.c (renamed from src/ipcpd/unicast/pol/multipath_pff.c) | 38 | ||||
-rw-r--r-- | src/ipcpd/unicast/pff/multipath.h (renamed from src/ipcpd/unicast/pol/multipath_pff.h) | 10 | ||||
-rw-r--r-- | src/ipcpd/unicast/pff/ops.h (renamed from src/ipcpd/unicast/pol-pff-ops.h) | 14 | ||||
-rw-r--r-- | src/ipcpd/unicast/pff/pft.c (renamed from src/ipcpd/unicast/pol/pft.c) | 20 | ||||
-rw-r--r-- | src/ipcpd/unicast/pff/pft.h (renamed from src/ipcpd/unicast/pol/pft.h) | 6 | ||||
-rw-r--r-- | src/ipcpd/unicast/pff/pol.h | 25 | ||||
-rw-r--r-- | src/ipcpd/unicast/pff/simple.c (renamed from src/ipcpd/unicast/pol/simple_pff.c) | 10 | ||||
-rw-r--r-- | src/ipcpd/unicast/pff/simple.h (renamed from src/ipcpd/unicast/pol/simple_pff.h) | 10 | ||||
-rw-r--r-- | src/ipcpd/unicast/pff/tests/CMakeLists.txt (renamed from src/ipcpd/unicast/tests/CMakeLists.txt) | 13 | ||||
-rw-r--r-- | src/ipcpd/unicast/pff/tests/pft_test.c (renamed from src/ipcpd/unicast/pol/tests/pft_test.c) | 6 | ||||
-rw-r--r-- | src/ipcpd/unicast/psched.c | 17 | ||||
-rw-r--r-- | src/ipcpd/unicast/psched.h | 12 | ||||
-rw-r--r-- | src/ipcpd/unicast/routing.c | 10 | ||||
-rw-r--r-- | src/ipcpd/unicast/routing.h | 6 | ||||
-rw-r--r-- | src/ipcpd/unicast/routing/graph.c (renamed from src/ipcpd/unicast/pol/graph.c) | 10 | ||||
-rw-r--r-- | src/ipcpd/unicast/routing/graph.h (renamed from src/ipcpd/unicast/pol/graph.h) | 6 | ||||
-rw-r--r-- | src/ipcpd/unicast/routing/link-state.c (renamed from src/ipcpd/unicast/pol/link_state.c) | 82 | ||||
-rw-r--r-- | src/ipcpd/unicast/routing/link-state.h (renamed from src/ipcpd/unicast/pol/link_state.h) | 10 | ||||
-rw-r--r-- | src/ipcpd/unicast/routing/ops.h (renamed from src/ipcpd/unicast/pol-routing-ops.h) | 14 | ||||
-rw-r--r-- | src/ipcpd/unicast/routing/pol.h | 23 | ||||
-rw-r--r-- | src/ipcpd/unicast/routing/tests/CMakeLists.txt (renamed from src/ipcpd/unicast/pol/tests/CMakeLists.txt) | 7 | ||||
-rw-r--r-- | src/ipcpd/unicast/routing/tests/graph_test.c (renamed from src/ipcpd/unicast/pol/tests/graph_test.c) | 6 |
88 files changed, 4647 insertions, 5327 deletions
diff --git a/src/ipcpd/CMakeLists.txt b/src/ipcpd/CMakeLists.txt index d0b368a3..54294f11 100644 --- a/src/ipcpd/CMakeLists.txt +++ b/src/ipcpd/CMakeLists.txt @@ -1,3 +1,7 @@ +set(CONNMGR_RCV_TIMEOUT 1000 CACHE STRING + "Timeout for the connection manager to wait for OCEP info (ms).") +set(IPCP_DEBUG_LOCAL FALSE CACHE BOOL + "Use PID as address for local debugging") set(IPCP_QOS_CUBE_BE_PRIO 50 CACHE STRING "Priority for best effort QoS cube (0-99)") set(IPCP_QOS_CUBE_VIDEO_PRIO 90 CACHE STRING @@ -10,12 +14,16 @@ set(IPCP_ADD_THREADS 4 CACHE STRING "Number of extra threads to start when an IPCP faces thread starvation") set(IPCP_SCHED_THR_MUL 2 CACHE STRING "Number of scheduler threads per QoS cube") -set(DISABLE_CORE_LOCK FALSE CACHE BOOL +set(DISABLE_CORE_LOCK TRUE CACHE BOOL "Disable locking performance threads to a core") set(IPCP_CONN_WAIT_DIR TRUE CACHE BOOL "Check the running state of the directory when adding a dt connection") set(DHT_ENROLL_SLACK 50 CACHE STRING "DHT enrollment waiting time (0-999, ms)") +if (CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(IPCP_LINUX_TIMERSLACK_NS 1000 CACHE STRING + "Slack value for high resolution timers on Linux systems.") +endif () if ((IPCP_QOS_CUBE_BE_PRIO LESS 0) OR (IPCP_QOS_CUBE_BE_PRIO GREATER 99)) message(FATAL_ERROR "Invalid priority for best effort QoS cube") @@ -40,10 +48,13 @@ set(IPCP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/shim-data.c ) +set (COMMON_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/common/enroll.c + ) + add_subdirectory(local) add_subdirectory(eth) add_subdirectory(udp) -add_subdirectory(raptor) add_subdirectory(unicast) add_subdirectory(broadcast) diff --git a/src/ipcpd/broadcast/CMakeLists.txt b/src/ipcpd/broadcast/CMakeLists.txt index afcc8696..d85f335e 100644 --- a/src/ipcpd/broadcast/CMakeLists.txt +++ b/src/ipcpd/broadcast/CMakeLists.txt @@ -13,16 +13,17 @@ include_directories(${CMAKE_SOURCE_DIR}/include) include_directories(${CMAKE_BINARY_DIR}/include) set(IPCP_BROADCAST_TARGET ipcpd-broadcast CACHE INTERNAL "") +set(IPCP_BROADCAST_MPL 60 CACHE STRING + "Default maximum packet lifetime for the broadcast IPCP, in seconds") set(SOURCE_FILES # Add source files here connmgr.c dt.c - enroll.c main.c ) -add_executable(ipcpd-broadcast ${SOURCE_FILES} ${IPCP_SOURCES} +add_executable(ipcpd-broadcast ${SOURCE_FILES} ${IPCP_SOURCES} ${COMMON_SOURCES} ${LAYER_CONFIG_PROTO_SRCS}) target_link_libraries(ipcpd-broadcast LINK_PUBLIC ouroboros-dev) diff --git a/src/ipcpd/broadcast/comp.h b/src/ipcpd/broadcast/comp.h deleted file mode 100644 index 07983978..00000000 --- a/src/ipcpd/broadcast/comp.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2020 - * - * Components for the broadcast IPC process - * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> - * - * 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_BROADCAST_COMP_H -#define OUROBOROS_IPCPD_BROADCAST_COMP_H - -#include <ouroboros/cacep.h> - -#define DST_MAX_STRLEN 64 - -enum comp_id { - COMPID_DT = 0, - COMPID_ENROLL, - 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_BROADCAST_COMP_H */ diff --git a/src/ipcpd/broadcast/connmgr.c b/src/ipcpd/broadcast/connmgr.c index b023584a..f297175d 100644 --- a/src/ipcpd/broadcast/connmgr.c +++ b/src/ipcpd/broadcast/connmgr.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Handles connections between components * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -20,496 +20,16 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ +#include "config.h" + #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 "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); - 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; - 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); +#include <ouroboros/ipcp.h> - pthread_mutex_unlock(&comp->lock); +#define BUILD_IPCP_BROADCAST - return 0; -} +#include "common/connmgr.c" diff --git a/src/ipcpd/broadcast/connmgr.h b/src/ipcpd/broadcast/connmgr.h deleted file mode 100644 index 019056f2..00000000 --- a/src/ipcpd/broadcast/connmgr.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2020 - * - * Handles the different AP connections - * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> - * - * 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_BROADCAST_CONNMGR_H -#define OUROBOROS_IPCPD_BROADCAST_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 - -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_BROADCAST_CONNMGR_H */ diff --git a/src/ipcpd/broadcast/dt.c b/src/ipcpd/broadcast/dt.c index 6e8bacf1..938c9085 100644 --- a/src/ipcpd/broadcast/dt.c +++ b/src/ipcpd/broadcast/dt.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Forward loop for broadcast * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -33,7 +33,6 @@ #define DT "dt" #define OUROBOROS_PREFIX DT -#include <ouroboros/endian.h> #include <ouroboros/dev.h> #include <ouroboros/errno.h> #include <ouroboros/fqueue.h> @@ -41,17 +40,16 @@ #include <ouroboros/logs.h> #include <ouroboros/notifier.h> #include <ouroboros/utils.h> +#include <ouroboros/pthread.h> -#include "comp.h" -#include "connmgr.h" +#include "common/comp.h" +#include "common/connmgr.h" #include "dt.h" -#include "ipcp.h" #include <assert.h> #include <stdlib.h> #include <inttypes.h> #include <string.h> -#include <pthread.h> struct nb { struct list_head next; @@ -80,15 +78,16 @@ static int dt_add_nb(int fd) list_for_each(p, &fwd.nbs) { struct nb * el = list_entry(p, struct nb, next); if (el->fd == fd) { - log_dbg("Already know neighbor."); pthread_rwlock_unlock(&fwd.nbs_lock); - return -EPERM; + log_warn("Already know neighbor on fd %d.", fd); + return 0; } } nb = malloc(sizeof(*nb)); if (nb == NULL) { pthread_rwlock_unlock(&fwd.nbs_lock); + log_err("Failed to malloc neighbor struct."); return -ENOMEM; } @@ -98,10 +97,10 @@ static int dt_add_nb(int fd) ++fwd.nbs_len; - log_dbg("Neighbor %d added.", fd); - pthread_rwlock_unlock(&fwd.nbs_lock); + log_dbg("Neighbor %d added.", fd); + return 0; } @@ -126,6 +125,8 @@ static int dt_del_nb(int fd) pthread_rwlock_unlock(&fwd.nbs_lock); + log_err("Neighbor not found on fd %d.", fd); + return -EPERM; } @@ -158,8 +159,7 @@ static void dt_packet(uint8_t * buf, pthread_rwlock_rdlock(&fwd.nbs_lock); - pthread_cleanup_push((void (*))(void *) pthread_rwlock_unlock, - &fwd.nbs_lock); + pthread_cleanup_push(__cleanup_rwlock_unlock, &fwd.nbs_lock); list_for_each(p, &fwd.nbs) { struct nb * nb = list_entry(p, struct nb, next); @@ -170,6 +170,11 @@ static void dt_packet(uint8_t * buf, pthread_cleanup_pop(true); } +static void __cleanup_fqueue_destroy(void * fq) +{ + fqueue_destroy((fqueue_t *) fq); +} + static void * dt_reader(void * o) { fqueue_t * fq; @@ -184,13 +189,12 @@ static void * dt_reader(void * o) if (fq == NULL) return (void *) -1; - pthread_cleanup_push((void (*) (void *)) fqueue_destroy, - (void *) fq); + pthread_cleanup_push(__cleanup_fqueue_destroy, (void *) fq); while (true) { ret = fevent(fwd.set, fq, NULL); if (ret < 0) { - log_warn("Event error: %d.", ret); + log_warn("Event warning: %d.", ret); continue; } @@ -225,13 +229,13 @@ static void handle_event(void * self, switch (event) { case NOTIFY_DT_CONN_ADD: - if (dt_add_nb(c->flow_info.fd)) - log_dbg("Failed to add neighbor."); + if (dt_add_nb(c->flow_info.fd) < 0) + log_err("Failed to add neighbor."); fset_add(fwd.set, c->flow_info.fd); break; case NOTIFY_DT_CONN_DEL: - if (dt_del_nb(c->flow_info.fd)) - log_dbg("Failed to delete neighbor."); + if (dt_del_nb(c->flow_info.fd) < 0) + log_err("Failed to delete neighbor."); fset_del(fwd.set, c->flow_info.fd); break; default: diff --git a/src/ipcpd/broadcast/dt.h b/src/ipcpd/broadcast/dt.h index e573511c..8d3b83f8 100644 --- a/src/ipcpd/broadcast/dt.h +++ b/src/ipcpd/broadcast/dt.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Forward loop for broadcast * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 diff --git a/src/ipcpd/broadcast/enroll.c b/src/ipcpd/broadcast/enroll.c deleted file mode 100644 index 511892b7..00000000 --- a/src/ipcpd/broadcast/enroll.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2020 - * - * Enrollment Task - * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> - * - * 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) < 0) { - 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.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.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) < 0) { - 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) < 0) { - 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/broadcast/enroll.h b/src/ipcpd/broadcast/enroll.h deleted file mode 100644 index 837e0a28..00000000 --- a/src/ipcpd/broadcast/enroll.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2020 - * - * Enrollment Task - * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> - * - * 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_BROADCAST_ENROLL_H -#define OUROBOROS_IPCPD_BROADCAST_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_BROADCAST_ENROLL_H */ diff --git a/src/ipcpd/broadcast/main.c b/src/ipcpd/broadcast/main.c index 120b2bf1..f51fc629 100644 --- a/src/ipcpd/broadcast/main.c +++ b/src/ipcpd/broadcast/main.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Broadcast IPC Process * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -29,19 +29,20 @@ #include "config.h" #define OUROBOROS_PREFIX "broadcast-ipcp" +#define THIS_TYPE IPCP_BROADCAST -#include <ouroboros/errno.h> -#include <ouroboros/hash.h> #include <ouroboros/dev.h> +#include <ouroboros/errno.h> #include <ouroboros/ipcp-dev.h> #include <ouroboros/logs.h> #include <ouroboros/notifier.h> +#include <ouroboros/random.h> #include <ouroboros/rib.h> -#include <ouroboros/time_utils.h> +#include <ouroboros/time.h> -#include "connmgr.h" +#include "common/connmgr.h" +#include "common/enroll.h" #include "dt.h" -#include "enroll.h" #include "ipcp.h" #include <stdbool.h> @@ -51,54 +52,38 @@ #include <assert.h> #include <inttypes.h> -#define THIS_TYPE IPCP_BROADCAST +struct ipcp ipcpi; 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; + strcpy(ipcpi.layer_name, conf->layer_info.name); + ipcpi.dir_hash_algo = (enum hash_algo) conf->layer_info.dir_hash_algo; assert(ipcp_dir_hash_len() != 0); - if (dt_init()) { + if (dt_init() < 0) { log_err("Failed to initialize forwarding component."); - goto fail_dt; + return -1; } ipcp_set_state(IPCP_INIT); return 0; - - fail_dt: - free(ipcpi.layer_name); - fail_layer_name: - return -1; } static void finalize_components(void) { dt_fini(); - - free(ipcpi.layer_name); } static int start_components(void) { - assert(ipcp_get_state() == IPCP_INIT); - - ipcp_set_state(IPCP_OPERATIONAL); - - if (enroll_start()) { + if (enroll_start() < 0) { log_err("Failed to start enrollment."); goto fail_enroll_start; } - if (connmgr_start()) { + if (connmgr_start() < 0) { log_err("Failed to start AP connection manager."); goto fail_connmgr_start; } @@ -114,52 +99,55 @@ static int start_components(void) static void stop_components(void) { - assert(ipcp_get_state() == IPCP_OPERATIONAL || - ipcp_get_state() == IPCP_SHUTDOWN); - connmgr_stop(); enroll_stop(); - - ipcp_set_state(IPCP_INIT); } static int broadcast_ipcp_enroll(const char * dst, struct layer_info * info) { struct conn conn; + uint8_t id[ENROLL_ID_LEN]; - if (connmgr_alloc(COMPID_ENROLL, dst, NULL, &conn)) { - log_err("Failed to get connection."); - goto fail_er_flow; + if (random_buffer(id, ENROLL_ID_LEN) < 0) { + log_err("Failed to generate enrollment ID."); + goto fail_id; + } + + log_info_id(id, "Requesting enrollment."); + + if (connmgr_alloc(COMPID_ENROLL, dst, NULL, &conn) < 0) { + log_err_id(id, "Failed to get connection."); + goto fail_id; } /* Get boot state from peer. */ - if (enroll_boot(&conn)) { - log_err("Failed to get boot information."); + if (enroll_boot(&conn, id) < 0) { + log_err_id(id, "Failed to get boot information."); goto fail_enroll_boot; } - if (initialize_components(enroll_get_conf())) { - log_err("Failed to initialize IPCP components."); + if (initialize_components(enroll_get_conf()) < 0) { + log_err_id(id, "Failed to initialize components."); goto fail_enroll_boot; } - if (start_components()) { - log_err("Failed to start components."); + if (start_components() < 0) { + log_err_id(id, "Failed to start components."); goto fail_start_comp; } - if (enroll_done(&conn, 0)) - log_warn("Failed to confirm enrollment with peer."); + if (enroll_ack(&conn, id, 0) < 0) + log_err_id(id, "Failed to confirm enrollment."); - if (connmgr_dealloc(COMPID_ENROLL, &conn)) - log_warn("Failed to deallocate enrollment flow."); + if (connmgr_dealloc(COMPID_ENROLL, &conn) < 0) + log_warn_id(id, "Failed to dealloc enrollment flow."); - log_info("Enrolled with %s.", dst); + log_info_id(id, "Enrolled with %s.", dst); - info->dir_hash_algo = ipcpi.dir_hash_algo; - strcpy(info->layer_name, ipcpi.layer_name); + info->dir_hash_algo = (enum pol_dir_hash) ipcpi.dir_hash_algo; + strcpy(info->name, ipcpi.layer_name); return 0; @@ -167,7 +155,7 @@ static int broadcast_ipcp_enroll(const char * dst, finalize_components(); fail_enroll_boot: connmgr_dealloc(COMPID_ENROLL, &conn); - fail_er_flow: + fail_id: return -1; } @@ -175,6 +163,8 @@ static int broadcast_ipcp_bootstrap(const struct ipcp_config * conf) { assert(conf); assert(conf->type == THIS_TYPE); + ((struct ipcp_config *) conf)->layer_info.dir_hash_algo = + DIR_HASH_SHA3_256; enroll_bootstrap(conf); @@ -188,8 +178,6 @@ static int broadcast_ipcp_bootstrap(const struct ipcp_config * conf) goto fail_start; } - log_dbg("Bootstrapped in layer %s.", conf->layer_info.layer_name); - return 0; fail_start: @@ -223,6 +211,8 @@ static int broadcast_ipcp_join(int fd, qosspec_t qs) { struct conn conn; + time_t mpl = IPCP_BROADCAST_MPL; + buffer_t data = {NULL, 0}; (void) qs; @@ -230,12 +220,14 @@ static int broadcast_ipcp_join(int fd, conn.flow_info.fd = fd; - if (name_check(dst) != 0) + if (name_check(dst) != 0) { + log_err("Failed to check name."); return -1; + } notifier_event(NOTIFY_DT_CONN_ADD, &conn); - ipcp_flow_alloc_reply(fd, 0, NULL, 0); + ipcp_flow_alloc_reply(fd, 0, mpl, &data); return 0; } @@ -250,12 +242,11 @@ int broadcast_ipcp_dealloc(int fd) notifier_event(NOTIFY_DT_CONN_DEL, &conn); - flow_dealloc(fd); + ipcp_flow_dealloc(fd); return 0; } - static struct ipcp_ops broadcast_ops = { .ipcp_bootstrap = broadcast_ipcp_bootstrap, .ipcp_enroll = broadcast_ipcp_enroll, @@ -273,17 +264,11 @@ static struct ipcp_ops broadcast_ops = { int main(int argc, char * argv[]) { - if (ipcp_init(argc, argv, &broadcast_ops) < 0) { - log_err("Failed to init IPCP."); + if (ipcp_init(argc, argv, &broadcast_ops, THIS_TYPE) < 0) { + log_err("Failed to initialize 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; @@ -299,49 +284,38 @@ int main(int argc, goto fail_enroll_init; } - if (ipcp_boot() < 0) { + if (ipcp_start() < 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; + goto fail_start; } - ipcp_shutdown(); + ipcp_sigwait(); if (ipcp_get_state() == IPCP_SHUTDOWN) { stop_components(); finalize_components(); } + ipcp_stop(); + enroll_fini(); connmgr_fini(); notifier_fini(); - rib_fini(); - ipcp_fini(); exit(EXIT_SUCCESS); - fail_create_r: - ipcp_shutdown(); - fail_boot: + fail_start: 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/unicast/comp.h b/src/ipcpd/common/comp.h index 42367833..f3790d9c 100644 --- a/src/ipcpd/unicast/comp.h +++ b/src/ipcpd/common/comp.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * - * Components for the unicast IPC process + * Components for the unicast/broadcast IPC process * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -20,12 +20,10 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#ifndef OUROBOROS_IPCPD_UNICAST_COMP_H -#define OUROBOROS_IPCPD_UNICAST_COMP_H +#ifndef OUROBOROS_IPCPD_COMMON_COMP_H +#define OUROBOROS_IPCPD_COMMON_COMP_H -#include <ouroboros/cacep.h> - -#include "dt.h" +#include <ouroboros/cep.h> #define DST_MAX_STRLEN 64 @@ -45,4 +43,4 @@ struct conn { } flow_info; }; -#endif /* OUROBOROS_IPCPD_UNICAST_COMP_H */ +#endif /* OUROBOROS_IPCPD_COMMON_COMP_H */ diff --git a/src/ipcpd/common/connmgr.c b/src/ipcpd/common/connmgr.c new file mode 100644 index 00000000..4b5fd420 --- /dev/null +++ b/src/ipcpd/common/connmgr.c @@ -0,0 +1,564 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Handles connections between components + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * 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 "connection-manager" + +#include <ouroboros/cep.h> +#include <ouroboros/dev.h> +#include <ouroboros/errno.h> +#include <ouroboros/fccntl.h> +#include <ouroboros/list.h> +#include <ouroboros/logs.h> +#include <ouroboros/notifier.h> +#include <ouroboros/pthread.h> + +#include "connmgr.h" +#include "ipcp.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.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; + struct timespec timeo = TIMESPEC_INIT_MS(CONNMGR_RCV_TIMEOUT); + int err; + + (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_err("Flow accept failed: %d", fd); + continue; + } + + log_info("Handling incoming flow %d.",fd); + + fccntl(fd, FLOWSRCVTIMEO, &timeo); + + err = cep_rcv(fd, &rcv_info); + if (err < 0) { + log_err("Error receiving OCEP info: %d.", err); + flow_dealloc(fd); + continue; + } + + log_info("Request to connect to %s.", rcv_info.comp_name); + + id = get_id_by_name(rcv_info.comp_name); + if (id < 0) { + log_err("Connection request for unknown component %s.", + rcv_info.comp_name); + cep_snd(fd, &fail_info); + flow_dealloc(fd); + continue; + } + + err = cep_snd(fd, &connmgr.comps[id].info); + if (err < 0) { + log_err("Failed responding to OCEP request: %d.", err); + flow_dealloc(fd); + continue; + } + + err = add_comp_conn(id, fd, qs, &rcv_info); + if (err < 0) { + log_err("Failed to add new connection: %d.", err); + flow_dealloc(fd); + continue; + } + + log_info("Finished handling incoming flow %d for %s.", + fd, rcv_info.comp_name); + } + + 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)) { + log_err("Failed to register notifier."); + 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)) { + log_err("Failed to create pthread: %s.", strerror(errno)); + 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)) { + log_err("Failed to initialize mutex: %s.", strerror(errno)); + goto fail_mutex; + } + + if (pthread_cond_init(&comp->cond, NULL)) { + log_err("Failed to initialize condvar: %s.", strerror(errno)); + goto fail_cond; + } + + list_head_init(&comp->conns); + list_head_init(&comp->pending); + + memcpy(&connmgr.comps[id].info, info, sizeof(connmgr.comps[id].info)); + + return 0; + + fail_cond: + pthread_mutex_destroy(&comp->lock); + fail_mutex: + return -1; +} + +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; + int ret; + + assert(dst); + assert(component); + + ce = malloc(sizeof(*ce)); + if (ce == NULL) { + log_err("Out of memory."); + goto fail_malloc; + } + + id = get_id_by_name(component); + if (id < 0) { + log_err("No such component: %s", component); + goto fail_id; + } + + pthread_cleanup_push(free, ce); + + ret = connmgr_alloc(id, dst, &qs, &ce->conn); + + pthread_cleanup_pop(false); + + if (ret < 0) { + log_err("Failed to allocate flow."); + goto fail_id; + } + + 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; + + fail_id: + free(ce); + fail_malloc: + return -1; +} + +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) { + log_err("No such component: %s.", component); + 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) +{ + struct comp * comp; + int fd; + struct timespec timeo = TIMESPEC_INIT_MS(CONNMGR_RCV_TIMEOUT); + + assert(id >= 0 && id < COMPID_MAX); + assert(dst); + + comp = connmgr.comps + id; + + fd = flow_alloc(dst, qs, NULL); + if (fd < 0) { + log_err("Failed to allocate flow to %s.", dst); + goto fail_alloc; + } + + conn->flow_info.fd = fd; + + if (qs != NULL) + conn->flow_info.qs = *qs; + else + memset(&conn->flow_info.qs, 0, sizeof(conn->flow_info.qs)); + + log_dbg("Sending OCEP info for protocol %s to fd %d.", + comp->info.protocol, conn->flow_info.fd); + + fccntl(fd, FLOWSRCVTIMEO, &timeo); + + if (cep_snd(fd, &comp->info)) { + log_err("Failed to send OCEP info."); + goto fail_cep; + } + + if (cep_rcv(fd, &conn->conn_info)) { + log_err("Failed to receive OCEP info."); + goto fail_cep; + } + + if (strcmp(comp->info.protocol, conn->conn_info.protocol)) { + log_err("Unknown protocol (requested %s, got %s).", + comp->info.protocol, conn->conn_info.protocol); + goto fail_cep; + } + + if (comp->info.pref_version != conn->conn_info.pref_version) { + log_err("Unknown protocol version %d.", + conn->conn_info.pref_version); + goto fail_cep; + } + + if (comp->info.pref_syntax != conn->conn_info.pref_syntax) { + log_err("Unknown protocol syntax."); + goto fail_cep; + } + + switch (id) { + case COMPID_DT: + notifier_event(NOTIFY_DT_CONN_ADD, conn); +#if defined(BUILD_IPCP_UNICAST) && defined(IPCP_CONN_WAIT_DIR) + dir_wait_running(); +#endif + break; + case COMPID_MGMT: + notifier_event(NOTIFY_MGMT_CONN_ADD, conn); + break; + default: + break; + } + + return 0; + + fail_cep: + flow_dealloc(conn->flow_info.fd); + fail_alloc: + return -1; +} + +int connmgr_dealloc(enum comp_id id, + struct conn * conn) +{ + switch (id) { + case COMPID_DT: + notifier_event(NOTIFY_DT_CONN_DEL, conn); + break; +#if defined(BUILD_IPCP_UNICAST) && defined(IPCP_CONN_WAIT_DIR) + case COMPID_MGMT: + notifier_event(NOTIFY_MGMT_CONN_DEL, conn); + break; +#endif + 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(__cleanup_mutex_unlock, &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); + log_err("Failed to get connection element."); + 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/unicast/connmgr.h b/src/ipcpd/common/connmgr.h index 17f78245..0710dbbf 100644 --- a/src/ipcpd/unicast/connmgr.h +++ b/src/ipcpd/common/connmgr.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Handles the different AP connections * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -20,10 +20,10 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#ifndef OUROBOROS_IPCPD_UNICAST_CONNMGR_H -#define OUROBOROS_IPCPD_UNICAST_CONNMGR_H +#ifndef OUROBOROS_IPCPD_COMMON_CONNMGR_H +#define OUROBOROS_IPCPD_COMMON_CONNMGR_H -#include <ouroboros/cacep.h> +#include <ouroboros/cep.h> #include <ouroboros/qos.h> #include "comp.h" @@ -71,4 +71,4 @@ int connmgr_dealloc(enum comp_id id, int connmgr_wait(enum comp_id id, struct conn * conn); -#endif /* OUROBOROS_IPCPD_UNICAST_CONNMGR_H */ +#endif /* OUROBOROS_IPCPD_COMMON_CONNMGR_H */ diff --git a/src/ipcpd/common/enroll.c b/src/ipcpd/common/enroll.c new file mode 100644 index 00000000..5e35ce37 --- /dev/null +++ b/src/ipcpd/common/enroll.c @@ -0,0 +1,337 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Enrollment Task + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * 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/dev.h> +#include <ouroboros/errno.h> +#include <ouroboros/logs.h> +#include <ouroboros/serdes-oep.h> +#include <ouroboros/time.h> + +#include "common/connmgr.h" +#include "common/enroll.h" +#include "ipcp.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> + +#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 void * enroll_handle(void * o) +{ + struct enroll_req req; + struct enroll_resp resp; + struct enroll_ack ack; + struct conn conn; + uint8_t __buf[ENROLL_BUF_LEN]; + buffer_t buf; + ssize_t len; + + (void) o; + + buf.data = __buf; + buf.len = sizeof(__buf); + + resp.response = 0; + resp.conf = enroll.conf; + + while (true) { + buffer_t msg; + int fd; + + if (connmgr_wait(COMPID_ENROLL, &conn)) { + log_err("Failed to get next connection."); + continue; + } + + fd = conn.flow_info.fd; + + log_info("Incoming enrollment connection on flow %d.", fd); + + len = flow_read(fd, buf.data, buf.len); + if (len < 0) { + log_err("Failed to read from flow %d.", fd); + goto finish_flow; + } + + msg.data = buf.data; + msg.len = (size_t) len; + + if (enroll_req_des(&req, msg) < 0) { + log_err("Failed to unpack request message."); + goto finish_flow; + } + + log_info_id(req.id, "Handling incoming enrollment."); + + /* TODO: authentication, timezone handling (UTC). */ + + ack.result = -100; + + clock_gettime(CLOCK_REALTIME, &resp.t); + + memcpy(resp.id, req.id, ENROLL_ID_LEN); + + len = enroll_resp_ser(&resp, buf); + if (len < 0) { + log_err_id(req.id, "Failed to pack reply."); + goto finish_enroll; + } + + log_dbg_id(req.id, "Sending enrollment info (%zd bytes).", len); + + if (flow_write(conn.flow_info.fd, buf.data, len) < 0) { + log_err_id(req.id, "Failed te send response."); + goto finish_enroll; + } + + len = flow_read(conn.flow_info.fd, buf.data, buf.len); + if (len < 0) { + log_err_id(req.id, "Failed to read from flow."); + goto finish_enroll; + } + + msg.data = buf.data; + msg.len = (size_t) len; + + if (enroll_ack_des(&ack, msg) < 0) { + log_err_id(req.id, "Failed to unpack ack."); + goto finish_enroll; + } + + if (memcmp(req.id, ack.id, ENROLL_ID_LEN) != 0) + log_warn_id(req.id, "Enrollment ID mismatch."); + + finish_enroll: + switch(ack.result) { + case 0: + log_info_id(req.id, "Enrollment completed."); + break; + case -100: + log_warn_id(req.id, "Enrollment failed."); + break; + default: + log_warn_id(req.id, "Enrollment failed at remote."); + } + finish_flow: + connmgr_dealloc(COMPID_ENROLL, &conn); + + log_info("Enrollment flow %d closed.", fd); + } + + return 0; +} + +int enroll_boot(struct conn * conn, + const uint8_t * id) +{ + uint8_t __buf[ENROLL_BUF_LEN]; + buffer_t buf; + buffer_t msg; + ssize_t len; + ssize_t delta_t; + struct timespec t0; + struct timespec rtt; + int fd; + int ret; + struct enroll_req req; + struct enroll_resp resp; + + fd = conn->flow_info.fd; + + buf.data = __buf; + buf.len = sizeof(__buf); + + memcpy(req.id, id, ENROLL_ID_LEN); + + len = enroll_req_ser(&req, buf); + if (len < 0) { + log_err_id(id, "Failed to pack request message."); + return -1; + } + + clock_gettime(CLOCK_REALTIME, &t0); + + if (flow_write(fd, buf.data, len) < 0) { + log_err_id(id, "Failed to send request message."); + return -1; + } + + len = flow_read(fd, buf.data, buf.len); + if (len < 0) { + log_err_id(id, "No reply received."); + return -1; + } + + log_dbg_id(id, "Received configuration info (%zd bytes).", len); + + msg.data = buf.data; + msg.len = len; + + ret = enroll_resp_des(&resp, msg); + if (ret < 0) { + log_err_id(id, "Failed to unpack response message."); + return -1; + } + + if (memcmp(resp.id, id, ENROLL_ID_LEN) != 0) { + log_err_id(id, "Enrollment ID mismatch."); + return -1; + } + + if (resp.response < 0) { + log_warn_id(id, "Remote denied request: %d.", resp.response); + return -1; + } + + if (resp.conf.type != ipcpi.type) { + log_err_id(id, "Wrong type in enrollment response %d (%d).", + resp.conf.type, ipcpi.type); + return -1; + } + + clock_gettime(CLOCK_REALTIME, &rtt); + + delta_t = ts_diff_ms(&t0, &rtt); + + rtt.tv_sec = resp.t.tv_sec; + rtt.tv_nsec = resp.t.tv_nsec; + + if (labs(ts_diff_ms(&t0, &rtt)) - delta_t > ENROLL_WARN_TIME_OFFSET) + log_warn_id(id, "Clock offset above threshold."); + + enroll.conf = resp.conf; + + return 0; +} + +int enroll_ack(struct conn * conn, + const uint8_t * id, + const int result) +{ + struct enroll_ack ack; + uint8_t __buf[ENROLL_BUF_LEN]; + buffer_t buf; + ssize_t len; + + buf.data = __buf; + buf.len = sizeof(__buf); + + ack.result = result; + + memcpy(ack.id, id, ENROLL_ID_LEN); + + len = enroll_ack_ser(&ack, buf); + if (len < 0) { + log_err_id(id, "Failed to pack acknowledgement."); + return -1; + } + + if (flow_write(conn->flow_info.fd, buf.data, len) < 0) { + log_err_id(id, "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/unicast/enroll.h b/src/ipcpd/common/enroll.h index 804f5d5b..f26c31a3 100644 --- a/src/ipcpd/unicast/enroll.h +++ b/src/ipcpd/common/enroll.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Enrollment Task * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -20,8 +20,8 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#ifndef OUROBOROS_IPCPD_UNICAST_ENROLL_H -#define OUROBOROS_IPCPD_UNICAST_ENROLL_H +#ifndef OUROBOROS_IPCPD_COMMON_ENROLL_H +#define OUROBOROS_IPCPD_COMMON_ENROLL_H #include <ouroboros/ipcp.h> @@ -37,11 +37,13 @@ void enroll_stop(void); void enroll_bootstrap(const struct ipcp_config * conf); -int enroll_boot(struct conn * conn); +int enroll_boot(struct conn * conn, + const uint8_t * id); -int enroll_done(struct conn * conn, - int result); +int enroll_ack(struct conn * conn, + const uint8_t * id, + const int result); struct ipcp_config * enroll_get_conf(void); -#endif /* OUROBOROS_IPCPD_UNICAST_ENROLL_H */ +#endif /* OUROBOROS_IPCPD_COMMON_ENROLL_H */ diff --git a/src/ipcpd/config.h.in b/src/ipcpd/config.h.in index 3f69d327..fe4f5fd2 100644 --- a/src/ipcpd/config.h.in +++ b/src/ipcpd/config.h.in @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * IPC process configuration * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -39,6 +39,10 @@ #define IPCP_ADD_THREADS @IPCP_ADD_THREADS@ #cmakedefine HAVE_LIBGCRYPT +#define IPCP_LINUX_SLACK_NS @IPCP_LINUX_TIMERSLACK_NS@ + +#cmakedefine IPCP_DEBUG_LOCAL + /* unicast IPCP */ #define QOS_PRIO_BE @IPCP_QOS_CUBE_BE_PRIO@ #define QOS_PRIO_VIDEO @IPCP_QOS_CUBE_VIDEO_PRIO@ @@ -46,6 +50,8 @@ #define IPCP_SCHED_THR_MUL @IPCP_SCHED_THR_MUL@ #define PFT_SIZE @PFT_SIZE@ #define DHT_ENROLL_SLACK @DHT_ENROLL_SLACK@ +#define IPCP_UNICAST_MPL @IPCP_UNICAST_MPL@ +#define CONNMGR_RCV_TIMEOUT @CONNMGR_RCV_TIMEOUT@ #cmakedefine IPCP_CONN_WAIT_DIR #cmakedefine DISABLE_CORE_LOCK @@ -57,8 +63,9 @@ #define NSLOOKUP_EXEC "@NSLOOKUP_EXECUTABLE@" #define IPCP_UDP_RD_THR @IPCP_UDP_RD_THR@ #define IPCP_UDP_WR_THR @IPCP_UDP_WR_THR@ +#define IPCP_UDP_MPL @IPCP_UDP_MPL@ -/* eth-llc */ +/* eth */ #cmakedefine HAVE_NETMAP #cmakedefine HAVE_BPF #cmakedefine HAVE_RAW_SOCKETS @@ -66,3 +73,11 @@ #define IPCP_ETH_RD_THR @IPCP_ETH_RD_THR@ #define IPCP_ETH_WR_THR @IPCP_ETH_WR_THR@ #define IPCP_ETH_LO_MTU @IPCP_ETH_LO_MTU@ +#define IPCP_ETH_MPL @IPCP_ETH_MPL@ + +/* local */ +#define IPCP_LOCAL_MPL @IPCP_LOCAL_MPL@ + +/* broadcast */ +/* local */ +#define IPCP_BROADCAST_MPL @IPCP_BROADCAST_MPL@ diff --git a/src/ipcpd/eth/CMakeLists.txt b/src/ipcpd/eth/CMakeLists.txt index d7105b4f..d57e1848 100644 --- a/src/ipcpd/eth/CMakeLists.txt +++ b/src/ipcpd/eth/CMakeLists.txt @@ -85,6 +85,8 @@ if (HAVE_ETH) "Bypass the Qdisc in the kernel when using raw sockets") set(IPCP_ETH_LO_MTU 1500 CACHE STRING "Restrict Ethernet MTU over loopback interfaces") + set(IPCP_ETH_MPL 5 CACHE STRING + "Default maximum packet lifetime for the Ethernet IPCPs, in seconds") set(ETH_LLC_SOURCES # Add source files here diff --git a/src/ipcpd/eth/dix.c b/src/ipcpd/eth/dix.c index dd007709..37b9896d 100644 --- a/src/ipcpd/eth/dix.c +++ b/src/ipcpd/eth/dix.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * IPC processes over Ethernet - DIX * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 diff --git a/src/ipcpd/eth/eth.c b/src/ipcpd/eth/eth.c index 6b17912b..ea6e0f1c 100644 --- a/src/ipcpd/eth/eth.c +++ b/src/ipcpd/eth/eth.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * IPC processes over Ethernet * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -37,6 +37,7 @@ #include "config.h" +#include <ouroboros/endian.h> #include <ouroboros/hash.h> #include <ouroboros/errno.h> #include <ouroboros/list.h> @@ -46,15 +47,15 @@ #include <ouroboros/ipcp-dev.h> #include <ouroboros/fqueue.h> #include <ouroboros/logs.h> -#include <ouroboros/time_utils.h> +#include <ouroboros/time.h> #include <ouroboros/fccntl.h> +#include <ouroboros/pthread.h> #include "ipcp.h" #include "shim-data.h" #include <signal.h> #include <stdlib.h> -#include <pthread.h> #include <fcntl.h> #include <unistd.h> #include <string.h> @@ -135,7 +136,6 @@ #define ETH_FRAME_SIZE (ETH_HEADER_SIZE + ETH_MTU_MAX) #endif -#define ALLOC_TIMEO 10 /* ms */ #define NAME_QUERY_TIMEO 2000 /* ms */ #define MGMT_TIMEO 100 /* ms */ #define MGMT_FRAME_SIZE 2048 @@ -145,6 +145,8 @@ #define NAME_QUERY_REQ 2 #define NAME_QUERY_REPLY 3 +struct ipcp ipcpi; + struct mgmt_msg { #if defined(BUILD_ETH_DIX) uint16_t seid; @@ -162,6 +164,7 @@ struct mgmt_msg { uint32_t ber; uint32_t max_gap; uint32_t delay; + uint32_t timeout; uint16_t cypher_s; uint8_t in_order; #if defined (BUILD_ETH_DIX) @@ -452,16 +455,15 @@ static int eth_ipcp_send_frame(const uint8_t * dst_addr, return 0; } -static int eth_ipcp_alloc(const uint8_t * dst_addr, +static int eth_ipcp_alloc(const uint8_t * dst_addr, #if defined(BUILD_ETH_DIX) - uint16_t eid, + uint16_t eid, #elif defined(BUILD_ETH_LLC) - uint8_t ssap, + uint8_t ssap, #endif - const uint8_t * hash, - qosspec_t qs, - const void * data, - size_t dlen) + const uint8_t * hash, + qosspec_t qs, + const buffer_t * data) { uint8_t * buf; struct mgmt_msg * msg; @@ -470,7 +472,7 @@ static int eth_ipcp_alloc(const uint8_t * dst_addr, len = sizeof(*msg) + ipcp_dir_hash_len(); - buf = malloc(len + ETH_HEADER_TOT_SIZE + dlen); + buf = malloc(len + ETH_HEADER_TOT_SIZE + data->len); if (buf == NULL) return -1; @@ -490,9 +492,11 @@ static int eth_ipcp_alloc(const uint8_t * dst_addr, msg->in_order = qs.in_order; msg->max_gap = hton32(qs.max_gap); msg->cypher_s = hton16(qs.cypher_s); + msg->timeout = hton32(qs.timeout); memcpy(msg + 1, hash, ipcp_dir_hash_len()); - memcpy(buf + len + ETH_HEADER_TOT_SIZE, data, dlen); + if (data->len > 0) + memcpy(buf + len + ETH_HEADER_TOT_SIZE, data->data, data->len); ret = eth_ipcp_send_frame(dst_addr, #if defined(BUILD_ETH_DIX) @@ -501,28 +505,27 @@ static int eth_ipcp_alloc(const uint8_t * dst_addr, reverse_bits(MGMT_SAP), reverse_bits(MGMT_SAP), #endif - buf, len + dlen); + buf, len + data->len); free(buf); return ret; } -static int eth_ipcp_alloc_resp(uint8_t * dst_addr, +static int eth_ipcp_alloc_resp(uint8_t * dst_addr, #if defined(BUILD_ETH_DIX) - uint16_t seid, - uint16_t deid, + uint16_t seid, + uint16_t deid, #elif defined(BUILD_ETH_LLC) - uint8_t ssap, - uint8_t dsap, + uint8_t ssap, + uint8_t dsap, #endif - int response, - const void * data, - size_t len) + int response, + const buffer_t * data) { struct mgmt_msg * msg; uint8_t * buf; - buf = malloc(sizeof(*msg) + ETH_HEADER_TOT_SIZE + len); + buf = malloc(sizeof(*msg) + ETH_HEADER_TOT_SIZE + data->len); if (buf == NULL) return -1; @@ -538,7 +541,8 @@ static int eth_ipcp_alloc_resp(uint8_t * dst_addr, #endif msg->response = response; - memcpy(msg + 1, data, len); + if (data->len > 0) + memcpy(msg + 1, data->data, data->len); if (eth_ipcp_send_frame(dst_addr, #if defined(BUILD_ETH_DIX) @@ -547,7 +551,7 @@ static int eth_ipcp_alloc_resp(uint8_t * dst_addr, reverse_bits(MGMT_SAP), reverse_bits(MGMT_SAP), #endif - buf, sizeof(*msg) + len)) { + buf, sizeof(*msg) + data->len)) { free(buf); return -1; } @@ -557,42 +561,20 @@ static int eth_ipcp_alloc_resp(uint8_t * dst_addr, return 0; } -static int eth_ipcp_req(uint8_t * r_addr, +static int eth_ipcp_req(uint8_t * r_addr, #if defined(BUILD_ETH_DIX) - uint16_t r_eid, + uint16_t r_eid, #elif defined(BUILD_ETH_LLC) - uint8_t r_sap, + uint8_t r_sap, #endif - const uint8_t * dst, - qosspec_t qs, - const void * data, - size_t len) + const uint8_t * dst, + qosspec_t qs, + const buffer_t * data) { - struct timespec ts = {0, ALLOC_TIMEO * MILLION}; - struct timespec abstime; - int fd; - - clock_gettime(PTHREAD_COND_CLOCK, &abstime); + int fd; - 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) { - log_dbg("Won't allocate over non-operational IPCP."); - pthread_mutex_unlock(&ipcpi.alloc_lock); - return -1; - } - - /* reply to IRM, called under lock to prevent race */ - fd = ipcp_flow_req_arr(dst, ipcp_dir_hash_len(), qs, data, len); + fd = ipcp_wait_flow_req_arr(dst, qs, IPCP_ETH_MPL, data); if (fd < 0) { - pthread_mutex_unlock(&ipcpi.alloc_lock); log_err("Could not get new flow from IRMd."); return -1; } @@ -607,11 +589,6 @@ static int eth_ipcp_req(uint8_t * r_addr, pthread_rwlock_unlock(ð_data.flows_lock); - ipcpi.alloc_id = fd; - pthread_cond_broadcast(&ipcpi.alloc_cond); - - pthread_mutex_unlock(&ipcpi.alloc_lock); - #if defined(BUILD_ETH_DIX) log_dbg("New flow request, fd %d, remote endpoint %d.", fd, r_eid); #elif defined(BUILD_ETH_LLC) @@ -620,20 +597,20 @@ static int eth_ipcp_req(uint8_t * r_addr, return 0; } -static int eth_ipcp_alloc_reply(uint8_t * r_addr, +static int eth_ipcp_alloc_reply(uint8_t * r_addr, #if defined(BUILD_ETH_DIX) - uint16_t seid, - uint16_t deid, + uint16_t seid, + uint16_t deid, #elif defined(BUILD_ETH_LLC) - uint8_t ssap, - int dsap, + uint8_t ssap, + int dsap, #endif - int response, - const void * data, - size_t len) + int response, + const buffer_t * data) { - int ret = 0; - int fd = -1; + int ret = 0; + int fd = -1; + time_t mpl = IPCP_ETH_MPL; pthread_rwlock_wrlock(ð_data.flows_lock); @@ -668,11 +645,12 @@ static int eth_ipcp_alloc_reply(uint8_t * r_addr, #elif defined(BUILD_ETH_LLC) log_dbg("Flow reply, fd %d, SSAP %d, DSAP %d.", fd, ssap, dsap); #endif - if ((ret = ipcp_flow_alloc_reply(fd, response, data, len)) < 0) + if ((ret = ipcp_flow_alloc_reply(fd, response, mpl, data)) < 0) { + log_err("Failed to reply to flow allocation."); return -1; + } return ret; - } static int eth_ipcp_name_query_req(const uint8_t * hash, @@ -734,6 +712,7 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf, struct mgmt_msg * msg; size_t msg_len; qosspec_t qs; + buffer_t data; msg = (struct mgmt_msg *) buf; @@ -751,6 +730,10 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf, qs.in_order = msg->in_order; qs.max_gap = ntoh32(msg->max_gap); qs.cypher_s = ntoh16(msg->cypher_s); + qs.timeout = ntoh32(msg->timeout); + + data.data = (uint8_t *) buf + msg_len; + data.len = len - msg_len; if (shim_data_reg_has(eth_data.shim_data, buf + sizeof(*msg))) { @@ -762,13 +745,15 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf, #endif buf + sizeof(*msg), qs, - buf + msg_len, - len - msg_len); + &data); } break; case FLOW_REPLY: assert(len >= sizeof(*msg)); + data.data = (uint8_t *) buf + sizeof(*msg); + data.len = len - sizeof(*msg); + eth_ipcp_alloc_reply(r_addr, #if defined(BUILD_ETH_DIX) ntohs(msg->seid), @@ -778,8 +763,7 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf, msg->dsap, #endif msg->response, - buf + sizeof(*msg), - len - sizeof(*msg)); + &data); break; case NAME_QUERY_REQ: eth_ipcp_name_query_req(buf + sizeof(*msg), r_addr); @@ -797,19 +781,15 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf, static void * eth_ipcp_mgmt_handler(void * o) { - int ret; - struct timespec timeout = {(MGMT_TIMEO / 1000), - (MGMT_TIMEO % 1000) * MILLION}; - struct timespec abstime; - struct mgmt_frame * frame; - (void) o; - pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, - (void *) ð_data.mgmt_lock); + pthread_cleanup_push(__cleanup_mutex_unlock, ð_data.mgmt_lock); while (true) { - ret = 0; + int ret = 0; + struct timespec timeout = TIMESPEC_INIT_MS(MGMT_TIMEO); + struct timespec abstime; + struct mgmt_frame * frame = NULL; clock_gettime(PTHREAD_COND_CLOCK, &abstime); ts_add(&abstime, &timeout, &abstime); @@ -821,23 +801,19 @@ static void * eth_ipcp_mgmt_handler(void * o) ret = -pthread_cond_timedwait(ð_data.mgmt_cond, ð_data.mgmt_lock, &abstime); + if (ret != -ETIMEDOUT) + frame = list_first_entry((ð_data.mgmt_frames), + struct mgmt_frame, next); + if (frame != NULL) + list_del(&frame->next); - if (ret == -ETIMEDOUT) { - pthread_mutex_unlock(ð_data.mgmt_lock); - continue; - } + pthread_mutex_unlock(ð_data.mgmt_lock); - frame = list_first_entry((ð_data.mgmt_frames), - struct mgmt_frame, next); - if (frame == NULL) { - pthread_mutex_unlock(ð_data.mgmt_lock); + if (frame == NULL) continue; - } - - list_del(&frame->next); - pthread_mutex_unlock(ð_data.mgmt_lock); eth_ipcp_mgmt_frame(frame->buf, frame->len, frame->r_addr); + free(frame); } @@ -883,7 +859,7 @@ static void * eth_ipcp_packet_reader(void * o) buf = nm_nextpkt(eth_data.nmd, &hdr); if (buf == NULL) { - log_err("Bad read from netmap device."); + log_dbg("Bad read from netmap device."); continue; } #else @@ -914,6 +890,7 @@ static void * eth_ipcp_packet_reader(void * o) ETH_MTU + ETH_HEADER_TOT_SIZE, 0); #endif if (frame_len <= 0) { + log_dbg("Failed to receive frame."); ipcp_sdb_release(sdb); continue; } @@ -940,22 +917,14 @@ static void * eth_ipcp_packet_reader(void * o) #endif length = ntohs(e_frame->length); #if defined(BUILD_ETH_DIX) - if (e_frame->ethertype != eth_data.ethertype) { -#ifndef HAVE_NETMAP - ipcp_sdb_release(sdb); -#endif - continue; - } + if (e_frame->ethertype != eth_data.ethertype) + goto fail_frame; deid = ntohs(e_frame->eid); if (deid == MGMT_EID) { #elif defined (BUILD_ETH_LLC) - if (length > 0x05FF) {/* DIX */ -#ifndef HAVE_NETMAP - ipcp_sdb_release(sdb); -#endif - continue; - } + if (length > 0x05FF) /* DIX */ + goto fail_frame; length -= LLC_HEADER_SIZE; @@ -964,12 +933,12 @@ static void * eth_ipcp_packet_reader(void * o) if (ssap == MGMT_SAP && dsap == MGMT_SAP) { #endif + ipcp_sdb_release(sdb); /* No need for the N+1 buffer. */ + frame = malloc(sizeof(*frame)); if (frame == NULL) { -#ifndef HAVE_NETMAP - ipcp_sdb_release(sdb); -#endif - continue; + log_err("Failed to allocate frame."); + goto fail_frame; } memcpy(frame->buf, &e_frame->payload, length); @@ -980,10 +949,6 @@ static void * eth_ipcp_packet_reader(void * o) list_add(&frame->next, ð_data.mgmt_frames); pthread_cond_signal(ð_data.mgmt_cond); pthread_mutex_unlock(ð_data.mgmt_lock); - -#ifndef HAVE_NETMAP - ipcp_sdb_release(sdb); -#endif } else { pthread_rwlock_rdlock(ð_data.flows_lock); @@ -994,10 +959,7 @@ static void * eth_ipcp_packet_reader(void * o) #endif if (fd < 0) { pthread_rwlock_unlock(ð_data.flows_lock); -#ifndef HAVE_NETMAP - ipcp_sdb_release(sdb); -#endif - continue; + goto fail_frame; } #ifdef BUILD_ETH_LLC @@ -1005,10 +967,7 @@ static void * eth_ipcp_packet_reader(void * o) || memcmp(eth_data.fd_to_ef[fd].r_addr, e_frame->src_hwaddr, MAC_SIZE)) { pthread_rwlock_unlock(ð_data.flows_lock); -#ifndef HAVE_NETMAP - ipcp_sdb_release(sdb); -#endif - continue; + goto fail_frame; } #endif pthread_rwlock_unlock(ð_data.flows_lock); @@ -1016,9 +975,20 @@ static void * eth_ipcp_packet_reader(void * o) #ifndef HAVE_NETMAP shm_du_buff_head_release(sdb, ETH_HEADER_TOT_SIZE); shm_du_buff_truncate(sdb, length); - ipcp_flow_write(fd, sdb); #else - flow_write(fd, &e_frame->payload, length); + if (ipcp_sdb_reserve(&sdb, length)) + continue; + + buf = shm_du_buff_head(sdb); + memcpy(buf, &e_frame->payload, length); +#endif + if (np1_flow_write(fd, sdb) < 0) + ipcp_sdb_release(sdb); + + continue; + fail_frame: +#ifndef HAVE_NETMAP + ipcp_sdb_release(sdb); #endif } } @@ -1052,27 +1022,28 @@ static void * eth_ipcp_packet_writer(void * o) (void) o; - pthread_cleanup_push(cleanup_writer, fq); - ipcp_lock_to_core(); + pthread_cleanup_push(cleanup_writer, fq); + while (true) { fevent(eth_data.np1_flows, fq, NULL); while ((fd = fqueue_next(fq)) >= 0) { if (fqueue_type(fq) != FLOW_PKT) continue; - if (ipcp_flow_read(fd, &sdb)) { + if (np1_flow_read(fd, &sdb)) { log_dbg("Bad read from fd %d.", fd); continue; } - len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb); + len = shm_du_buff_len(sdb); if (shm_du_buff_head_alloc(sdb, ETH_HEADER_TOT_SIZE) == NULL) { log_dbg("Failed to allocate header."); ipcp_sdb_release(sdb); + continue; } pthread_rwlock_rdlock(ð_data.flows_lock); @@ -1088,14 +1059,15 @@ static void * eth_ipcp_packet_writer(void * o) pthread_rwlock_unlock(ð_data.flows_lock); - eth_ipcp_send_frame(r_addr, + if (eth_ipcp_send_frame(r_addr, #if defined(BUILD_ETH_DIX) deid, #elif defined(BUILD_ETH_LLC) dsap, ssap, #endif shm_du_buff_head(sdb), - len); + len)) + log_dbg("Failed to send frame."); ipcp_sdb_release(sdb); } } @@ -1160,12 +1132,6 @@ static void change_flows_state(bool up) pthread_rwlock_unlock(ð_data.flows_lock); } -static void close_ptr(void * o) -{ - close(*((int *) o)); -} - - static void * eth_ipcp_if_monitor(void * o) { int fd; @@ -1186,7 +1152,7 @@ static void * eth_ipcp_if_monitor(void * o) return (void *) -1; } - pthread_cleanup_push(close_ptr, &fd); + pthread_cleanup_push(__cleanup_close_ptr, &fd); while (true) { status = recvmsg(fd, &msg, 0); @@ -1281,25 +1247,23 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) assert(conf); assert(conf->type == THIS_TYPE); - if (conf->dev == NULL) { - log_err("Device name is NULL."); - return -1; - } + ipcpi.dir_hash_algo = (enum hash_algo) conf->layer_info.dir_hash_algo; + strcpy(ipcpi.layer_name, conf->layer_info.name); - if (strlen(conf->dev) >= IFNAMSIZ) { - log_err("Invalid device name: %s.", conf->dev); + if (strlen(conf->eth.dev) >= IFNAMSIZ) { + log_err("Invalid device name: %s.", conf->eth.dev); return -1; } memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, conf->dev); + strcpy(ifr.ifr_name, conf->eth.dev); #ifdef BUILD_ETH_DIX - if (conf->ethertype < 0x0600 || conf->ethertype == 0xFFFF) { - log_err("Invalid Ethertype."); + if (conf->eth.ethertype < 0x0600 || conf->eth.ethertype == 0xFFFF) { + log_err("Invalid Ethertype: %d.", conf->eth.ethertype); return -1; } - eth_data.ethertype = htons(conf->ethertype); + eth_data.ethertype = htons(conf->eth.ethertype); #endif #if defined(__FreeBSD__) || defined(__APPLE__) @@ -1309,9 +1273,9 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) } for (ifa = ifaddr, idx = 0; ifa != NULL; ifa = ifa->ifa_next, ++idx) { - if (strcmp(ifa->ifa_name, conf->dev)) + if (strcmp(ifa->ifa_name, conf->eth.dev)) continue; - log_dbg("Interface %s found.", conf->dev); + log_dbg("Interface %s found.", conf->eth.dev); #if defined(HAVE_NETMAP) || defined(HAVE_BPF) memcpy(eth_data.hw_addr, @@ -1346,7 +1310,8 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) log_dbg("Device MTU is %d.", ifr.ifr_mtu); eth_data.mtu = MIN((int) ETH_MTU_MAX, ifr.ifr_mtu); - if (memcmp(conf->dev, "lo", 2) == 0 && eth_data.mtu > IPCP_ETH_LO_MTU) { + if (memcmp(conf->eth.dev, "lo", 2) == 0 && + eth_data.mtu > IPCP_ETH_LO_MTU) { log_dbg("Using loopback interface. MTU restricted to %d.", IPCP_ETH_LO_MTU); eth_data.mtu = IPCP_ETH_LO_MTU; @@ -1370,7 +1335,7 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) close(skfd); - idx = if_nametoindex(conf->dev); + idx = if_nametoindex(conf->eth.dev); if (idx == 0) { log_err("Failed to retrieve interface index."); return -1; @@ -1380,7 +1345,7 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) #if defined(HAVE_NETMAP) strcpy(ifn, "netmap:"); - strcat(ifn, conf->dev); + strcat(ifn, conf->eth.dev); eth_data.nmd = nm_open(ifn, NULL, 0, NULL); if (eth_data.nmd == NULL) { @@ -1450,7 +1415,7 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) if (eth_data.s_fd < 0) { log_err("Failed to create socket."); - return -1; + goto fail_socket; } flags = fcntl(eth_data.s_fd, F_GETFL, 0); @@ -1472,60 +1437,52 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) #endif if (bind(eth_data.s_fd, (struct sockaddr *) ð_data.device, - sizeof(eth_data.device))) { + sizeof(eth_data.device)) < 0) { log_err("Failed to bind socket to interface."); goto fail_device; } - #endif /* HAVE_NETMAP */ - ipcp_set_state(IPCP_OPERATIONAL); - #if defined(__linux__) - if (pthread_create(ð_data.if_monitor, - NULL, - eth_ipcp_if_monitor, - NULL)) { - ipcp_set_state(IPCP_INIT); + if (pthread_create(ð_data.if_monitor, NULL, + eth_ipcp_if_monitor, NULL)) { + log_err("Failed to create monitor thread: %s.", + strerror(errno)); goto fail_device; } #endif - if (pthread_create(ð_data.mgmt_handler, - NULL, - eth_ipcp_mgmt_handler, - NULL)) { - ipcp_set_state(IPCP_INIT); + if (pthread_create(ð_data.mgmt_handler, NULL, + eth_ipcp_mgmt_handler, NULL)) { + log_err("Failed to create mgmt handler thread: %s.", + strerror(errno)); goto fail_mgmt_handler; } for (idx = 0; idx < IPCP_ETH_RD_THR; ++idx) { - if (pthread_create(ð_data.packet_reader[idx], - NULL, - eth_ipcp_packet_reader, - NULL)) { - ipcp_set_state(IPCP_INIT); + if (pthread_create(ð_data.packet_reader[idx], NULL, + eth_ipcp_packet_reader, NULL)) { + log_err("Failed to create packet reader thread: %s", + strerror(errno)); goto fail_packet_reader; } } for (idx = 0; idx < IPCP_ETH_WR_THR; ++idx) { - if (pthread_create(ð_data.packet_writer[idx], - NULL, - eth_ipcp_packet_writer, - NULL)) { - ipcp_set_state(IPCP_INIT); + if (pthread_create(ð_data.packet_writer[idx], NULL, + eth_ipcp_packet_writer, NULL)) { + log_err("Failed to create packet writer thread: %s", + strerror(errno)); goto fail_packet_writer; } } #if defined(BUILD_ETH_DIX) log_dbg("Bootstrapped IPCP over DIX Ethernet with pid %d " - "and Ethertype 0x%X.", getpid(), conf->ethertype); + "and Ethertype 0x%X.", getpid(), conf->eth.ethertype); #elif defined(BUILD_ETH_LLC) log_dbg("Bootstrapped IPCP over Ethernet with LLC with pid %d.", getpid()); #endif - return 0; fail_packet_writer: @@ -1556,19 +1513,18 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) #elif defined(HAVE_RAW_SOCKETS) close(eth_data.s_fd); #endif + fail_socket: return -1; } static int eth_ipcp_reg(const uint8_t * hash) { if (shim_data_reg_add_entry(eth_data.shim_data, hash)) { - log_err("Failed to add " HASH_FMT " to local registry.", - HASH_VAL(hash)); + log_err("Failed to add " HASH_FMT32 " to local registry.", + HASH_VAL32(hash)); return -1; } - log_dbg("Registered " HASH_FMT ".", HASH_VAL(hash)); - return 0; } @@ -1582,8 +1538,7 @@ static int eth_ipcp_unreg(const uint8_t * hash) static int eth_ipcp_query(const uint8_t * hash) { uint8_t r_addr[MAC_SIZE]; - struct timespec timeout = {(NAME_QUERY_TIMEO / 1000), - (NAME_QUERY_TIMEO % 1000) * MILLION}; + struct timespec timeout = TIMESPEC_INIT_MS(NAME_QUERY_TIMEO); struct dir_query * query; int ret; uint8_t * buf; @@ -1635,11 +1590,10 @@ static int eth_ipcp_query(const uint8_t * hash) return ret; } -static int eth_ipcp_flow_alloc(int fd, - const uint8_t * hash, - qosspec_t qs, - const void * data, - size_t len) +static int eth_ipcp_flow_alloc(int fd, + const uint8_t * hash, + qosspec_t qs, + const buffer_t * data) { #ifdef BUILD_ETH_LLC uint8_t ssap = 0; @@ -1647,12 +1601,11 @@ static int eth_ipcp_flow_alloc(int fd, uint8_t r_addr[MAC_SIZE]; uint64_t addr = 0; - log_dbg("Allocating flow to " HASH_FMT ".", HASH_VAL(hash)); - assert(hash); if (!shim_data_dir_has(eth_data.shim_data, hash)) { - log_err("Destination unreachable."); + log_err("Destination "HASH_FMT32 "unreachable.", + HASH_VAL32(hash)); return -1; } addr = shim_data_dir_get_addr(eth_data.shim_data, hash); @@ -1662,6 +1615,7 @@ static int eth_ipcp_flow_alloc(int fd, ssap = bmp_allocate(eth_data.saps); if (!bmp_is_id_valid(eth_data.saps, ssap)) { pthread_rwlock_unlock(ð_data.flows_lock); + log_err("Failed to allocate SSAP."); return -1; } @@ -1680,34 +1634,29 @@ static int eth_ipcp_flow_alloc(int fd, #endif hash, qs, - data, - len) < 0) { + data) < 0) { #ifdef BUILD_ETH_LLC pthread_rwlock_wrlock(ð_data.flows_lock); bmp_release(eth_data.saps, eth_data.fd_to_ef[fd].sap); eth_data.fd_to_ef[fd].sap = -1; eth_data.ef_to_fd[ssap] = -1; pthread_rwlock_unlock(ð_data.flows_lock); + log_err("Failed to allocate with peer."); #endif return -1; } fset_add(eth_data.np1_flows, fd); -#if defined(BUILD_ETH_DIX) - log_dbg("Pending flow with fd %d.", fd); -#elif defined(BUILD_ETH_LLC) - log_dbg("Pending flow with fd %d on SAP %d.", fd, ssap); +#if defined(BUILD_ETH_LLC) + log_dbg("Assigned SAP %d for fd %d.", ssap, fd); #endif return 0; } -static int eth_ipcp_flow_alloc_resp(int fd, - int response, - const void * data, - size_t len) +static int eth_ipcp_flow_alloc_resp(int fd, + int response, + const buffer_t * data) { - struct timespec ts = {0, ALLOC_TIMEO * MILLION}; - struct timespec abstime; #if defined(BUILD_ETH_DIX) uint16_t r_eid; #elif defined(BUILD_ETH_LLC) @@ -1716,27 +1665,11 @@ static int eth_ipcp_flow_alloc_resp(int fd, #endif uint8_t r_addr[MAC_SIZE]; - 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); + if (ipcp_wait_flow_resp(fd) < 0) { + log_err("Failed to wait for flow response."); return -1; } - ipcpi.alloc_id = -1; - pthread_cond_broadcast(&ipcpi.alloc_cond); - - pthread_mutex_unlock(&ipcpi.alloc_lock); - pthread_rwlock_wrlock(ð_data.flows_lock); #if defined(BUILD_ETH_DIX) r_eid = eth_data.fd_to_ef[fd].r_eid; @@ -1744,6 +1677,7 @@ static int eth_ipcp_flow_alloc_resp(int fd, ssap = bmp_allocate(eth_data.saps); if (!bmp_is_id_valid(eth_data.saps, ssap)) { pthread_rwlock_unlock(ð_data.flows_lock); + log_err("Failed to allocate SSAP."); return -1; } @@ -1762,21 +1696,19 @@ static int eth_ipcp_flow_alloc_resp(int fd, ssap, r_sap, #endif response, - data, - len) < 0) { + data) < 0) { #ifdef BUILD_ETH_LLC pthread_rwlock_wrlock(ð_data.flows_lock); bmp_release(eth_data.saps, eth_data.fd_to_ef[fd].sap); pthread_rwlock_unlock(ð_data.flows_lock); #endif + log_err("Failed to respond to peer."); return -1; } fset_add(eth_data.np1_flows, fd); -#if defined(BUILD_ETH_DIX) - log_dbg("Accepted flow, fd %d.", fd); -#elif defined(BUILD_ETH_LLC) - log_dbg("Accepted flow, fd %d, SAP %d.", fd, (uint8_t)ssap); +#if defined(BUILD_ETH_LLC) + log_dbg("Assigned SAP %d for fd %d.", ssap, fd); #endif return 0; } @@ -1788,10 +1720,10 @@ static int eth_ipcp_flow_dealloc(int fd) #endif ipcp_flow_fini(fd); - pthread_rwlock_wrlock(ð_data.flows_lock); - fset_del(eth_data.np1_flows, fd); + pthread_rwlock_wrlock(ð_data.flows_lock); + #if defined(BUILD_ETH_DIX) eth_data.fd_to_ef[fd].r_eid = -1; #elif defined BUILD_ETH_LLC @@ -1805,9 +1737,7 @@ static int eth_ipcp_flow_dealloc(int fd) pthread_rwlock_unlock(ð_data.flows_lock); - flow_dealloc(fd); - - log_dbg("Flow with fd %d deallocated.", fd); + ipcp_flow_dealloc(fd); return 0; } @@ -1831,9 +1761,6 @@ int main(int argc, { int i; - if (ipcp_init(argc, argv, ð_ops) < 0) - goto fail_init; - if (eth_data_init() < 0) { #if defined(BUILD_ETH_DIX) log_err("Failed to init eth-llc data."); @@ -1843,18 +1770,17 @@ int main(int argc, goto fail_data_init; } - if (ipcp_boot() < 0) { - log_err("Failed to boot IPCP."); - goto fail_boot; + if (ipcp_init(argc, argv, ð_ops, THIS_TYPE) < 0) { + log_err("Failed to initialize IPCP."); + goto fail_init; } - if (ipcp_create_r(0)) { - log_err("Failed to notify IRMd we are initialized."); - ipcp_set_state(IPCP_NULL); - goto fail_create_r; + if (ipcp_start() < 0) { + log_err("Failed to start IPCP."); + goto fail_start; } - ipcp_shutdown(); + ipcp_sigwait(); if (ipcp_get_state() == IPCP_SHUTDOWN) { for (i = 0; i < IPCP_ETH_WR_THR; ++i) @@ -1877,19 +1803,18 @@ int main(int argc, #endif } - eth_data_fini(); + ipcp_stop(); ipcp_fini(); + eth_data_fini(); + exit(EXIT_SUCCESS); - fail_create_r: - ipcp_shutdown(); - fail_boot: - eth_data_fini(); - fail_data_init: + fail_start: ipcp_fini(); fail_init: - ipcp_create_r(-1); + eth_data_fini(); + fail_data_init: exit(EXIT_FAILURE); } diff --git a/src/ipcpd/eth/llc.c b/src/ipcpd/eth/llc.c index 60abfdbb..c900dcab 100644 --- a/src/ipcpd/eth/llc.c +++ b/src/ipcpd/eth/llc.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * IPC processes over Ethernet - LLC * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 diff --git a/src/ipcpd/ipcp.c b/src/ipcpd/ipcp.c index 95d2f783..966c4920 100644 --- a/src/ipcpd/ipcp.c +++ b/src/ipcpd/ipcp.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * IPC process main loop * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -24,7 +24,6 @@ #define _DEFAULT_SOURCE #else #define _POSIX_C_SOURCE 200112L -#define __XSI_VISIBLE 500 #endif #if defined(__linux__) && !defined(DISABLE_CORE_LOCK) @@ -32,26 +31,25 @@ #define NPROC (sysconf(_SC_NPROCESSORS_ONLN)) #endif -#if defined(__linux__) || defined(__CYGWIN__) -#define _DEFAULT_SOURCE -#else -#define _POSIX_C_SOURCE 200112L -#define __XSI_VISIBLE 500 -#endif - #include "config.h" -#define OUROBOROS_PREFIX "ipcpd/ipcp" +#define OUROBOROS_PREFIX "ipcpd/ipcp" +#define IPCP_INFO "info" +#define ALLOC_TIMEOUT 50 /* ms */ +#include <ouroboros/bitmap.h> +#include <ouroboros/dev.h> +#include <ouroboros/errno.h> #include <ouroboros/hash.h> +#include <ouroboros/ipcp-dev.h> #include <ouroboros/logs.h> -#include <ouroboros/time_utils.h> -#include <ouroboros/utils.h> -#include <ouroboros/sockets.h> -#include <ouroboros/errno.h> -#include <ouroboros/dev.h> -#include <ouroboros/bitmap.h> #include <ouroboros/np1_flow.h> +#include <ouroboros/protobuf.h> +#include <ouroboros/pthread.h> +#include <ouroboros/rib.h> +#include <ouroboros/sockets.h> +#include <ouroboros/time.h> +#include <ouroboros/utils.h> #include "ipcp.h" @@ -59,9 +57,19 @@ #include <string.h> #include <sys/socket.h> #include <stdlib.h> -#if defined(__linux__) && !defined(DISABLE_CORE_LOCK) +#if defined(__linux__) +#include <sys/prctl.h> +#ifndef DISABLE_CORE_LOCK #include <unistd.h> #endif +#endif + +char * info[LAYER_NAME_SIZE + 1] = { + "_state", + "_type", + "_layer", + NULL +}; struct cmd { struct list_head next; @@ -97,16 +105,115 @@ void ipcp_hash_str(char * buf, buf[2 * i] = '\0'; } -static void close_ptr(void * o) +static int ipcp_rib_read(const char * path, + char * buf, + size_t len) { - close(*((int *) o)); + char * entry; + + if (len < LAYER_NAME_SIZE + 2) /* trailing \n */ + return 0; + + entry = strstr(path, RIB_SEPARATOR) + 1; + assert(entry); + + if (strcmp(entry, info[0]) == 0) { /* _state */ + enum ipcp_state state = ipcp_get_state(); + if (state == IPCP_NULL) + strcpy(buf, "null\n"); + else if (state == IPCP_INIT) + strcpy(buf, "init\n"); + else if (state == IPCP_OPERATIONAL) + strcpy(buf, "operational\n"); + else if (state == IPCP_SHUTDOWN) + strcpy(buf, "shutdown\n"); + else + strcpy(buf, "bug\n"); + } + + if (strcmp(entry, info[1]) == 0) { /* _type */ + if (ipcpi.type == IPCP_LOCAL) + strcpy(buf, "local\n"); + else if (ipcpi.type == IPCP_UNICAST) + strcpy(buf, "unicast\n"); + else if (ipcpi.type == IPCP_BROADCAST) + strcpy(buf, "broadcast\n"); + else if (ipcpi.type == IPCP_ETH_LLC) + strcpy(buf, "eth-llc\n"); + else if (ipcpi.type == IPCP_ETH_DIX) + strcpy(buf, "eth-dix\n"); + else if (ipcpi.type == IPCP_UDP) + strcpy(buf, "udp\n"); + else + strcpy(buf, "bug\n"); + } + + if (strcmp(entry, info[2]) == 0) { /* _layer */ + memset(buf, 0, LAYER_NAME_SIZE + 1); + if (ipcp_get_state() < IPCP_OPERATIONAL) + strcpy(buf, "(null)"); + else + strcpy(buf, ipcpi.layer_name); + + buf[strlen(buf)] = '\n'; + } + + return strlen(buf); +} + +static int ipcp_rib_readdir(char *** buf) +{ + int i = 0; + + while (info[i] != NULL) + i++; + + *buf = malloc(sizeof(**buf) * i); + if (*buf == NULL) + goto fail; + + i = 0; + + while (info[i] != NULL) { + (*buf)[i] = strdup(info[i]); + if ((*buf)[i] == NULL) + goto fail_dup; + i++; + } + + return i; + fail_dup: + while (i > 0) + free((*buf)[--i]); + fail: + free(*buf); + + return -1; } +static int ipcp_rib_getattr(const char * path, + struct rib_attr * attr) +{ + char buf[LAYER_NAME_SIZE + 2]; + struct timespec now; + + clock_gettime(CLOCK_REALTIME_COARSE, &now); + + attr->size = ipcp_rib_read(path, buf, LAYER_NAME_SIZE + 2); + attr->mtime = now.tv_sec; + + return 0; +} + +static struct rib_ops r_ops = { + .read = ipcp_rib_read, + .readdir = ipcp_rib_readdir, + .getattr = ipcp_rib_getattr +}; + static void * acceptloop(void * o) { - int csockfd; - struct timeval tv = {(SOCKET_TIMEOUT / 1000), - (SOCKET_TIMEOUT % 1000) * 1000}; + int csockfd; (void) o; @@ -118,10 +225,6 @@ static void * acceptloop(void * o) if (csockfd < 0) continue; - if (setsockopt(csockfd, SOL_SOCKET, SO_RCVTIMEO, - (void *) &tv, sizeof(tv))) - log_warn("Failed to set timeout on socket."); - cmd = malloc(sizeof(*cmd)); if (cmd == NULL) { log_err("Out of memory"); @@ -129,7 +232,7 @@ static void * acceptloop(void * o) break; } - pthread_cleanup_push(close_ptr, &csockfd); + pthread_cleanup_push(__cleanup_close_ptr, &csockfd); pthread_cleanup_push(free, cmd); cmd->len = read(csockfd, cmd->cbuf, SOCK_BUF_SIZE); @@ -158,35 +261,401 @@ static void * acceptloop(void * o) return (void *) 0; } +int ipcp_wait_flow_req_arr(const uint8_t * dst, + qosspec_t qs, + time_t mpl, + const buffer_t * data) +{ + struct timespec ts = TIMESPEC_INIT_MS(ALLOC_TIMEOUT); + struct timespec abstime; + int fd; + buffer_t hash; + + hash.data = (uint8_t *) dst; + hash.len = ipcp_dir_hash_len(); + + 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_err("Won't allocate over non-operational IPCP."); + return -EIPCPSTATE; + } + + assert(ipcpi.alloc_id == -1); + + fd = ipcp_flow_req_arr(&hash, qs, mpl, data); + if (fd < 0) { + pthread_mutex_unlock(&ipcpi.alloc_lock); + log_err("Failed to get fd for flow."); + return fd; + } + + ipcpi.alloc_id = fd; + pthread_cond_broadcast(&ipcpi.alloc_cond); + + pthread_mutex_unlock(&ipcpi.alloc_lock); + + return fd; + +} + +int ipcp_wait_flow_resp(const int fd) +{ + struct timespec ts = TIMESPEC_INIT_MS(ALLOC_TIMEOUT); + struct timespec abstime; + + 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; + } + + assert(ipcpi.alloc_id == fd); + + ipcpi.alloc_id = -1; + pthread_cond_broadcast(&ipcpi.alloc_cond); + + pthread_mutex_unlock(&ipcpi.alloc_lock); + + return 0; +} + static void free_msg(void * o) { ipcp_msg__free_unpacked((ipcp_msg_t *) o, NULL); } + +static void do_bootstrap(ipcp_config_msg_t * conf_msg, + ipcp_msg_t * ret_msg) +{ + struct ipcp_config conf; + + log_info("Bootstrapping..."); + + if (ipcpi.ops->ipcp_bootstrap == NULL) { + log_err("Bootstrap unsupported."); + ret_msg->result = -ENOTSUP; + goto finish; + } + + if (ipcp_get_state() != IPCP_INIT) { + log_err("IPCP in wrong state."); + ret_msg->result = -EIPCPSTATE; + goto finish; + } + + conf = ipcp_config_msg_to_s(conf_msg); + ret_msg->result = ipcpi.ops->ipcp_bootstrap(&conf); + if (ret_msg->result == 0) { + ret_msg->layer_info = layer_info_s_to_msg(&conf.layer_info); + ipcp_set_state(IPCP_OPERATIONAL); + } + finish: + log_info("Finished bootstrapping: %d.", ret_msg->result); +} + +static void do_enroll(const char * dst, + ipcp_msg_t * ret_msg) +{ + struct layer_info info; + + log_info("Enrolling with %s...", dst); + + if (ipcpi.ops->ipcp_enroll == NULL) { + log_err("Enroll unsupported."); + ret_msg->result = -ENOTSUP; + goto finish; + } + + if (ipcp_get_state() != IPCP_INIT) { + log_err("IPCP in wrong state."); + ret_msg->result = -EIPCPSTATE; + goto finish; + } + + ret_msg->result = ipcpi.ops->ipcp_enroll(dst, &info); + if (ret_msg->result == 0) { + ret_msg->layer_info = layer_info_s_to_msg(&info); + ipcp_set_state(IPCP_OPERATIONAL); + } + finish: + log_info("Finished enrolling with %s: %d.", dst, ret_msg->result); +} + +static void do_connect(const char * dst, + const char * comp, + qosspec_t qs, + ipcp_msg_t * ret_msg) +{ + log_info("Connecting %s to %s...", comp, dst); + + if (ipcpi.ops->ipcp_connect == NULL) { + log_err("Connect unsupported."); + ret_msg->result = -ENOTSUP; + goto finish; + } + + ret_msg->result = ipcpi.ops->ipcp_connect(dst, comp, qs); + finish: + log_info("Finished connecting: %d.", ret_msg->result); +} + +static void do_disconnect(const char * dst, + const char * comp, + ipcp_msg_t * ret_msg) +{ + log_info("Disconnecting %s from %s...", comp, dst); + + if (ipcpi.ops->ipcp_disconnect == NULL) { + log_err("Disconnect unsupported."); + ret_msg->result = -ENOTSUP; + goto finish; + } + + ret_msg->result = ipcpi.ops->ipcp_disconnect(dst, comp); + + finish: + log_info("Finished disconnecting %s from %s: %d.", + comp, dst, ret_msg->result); +} + +static void do_reg(const uint8_t * hash, + ipcp_msg_t * ret_msg) +{ + + log_info("Registering " HASH_FMT32 "...", HASH_VAL32(hash)); + + if (ipcpi.ops->ipcp_reg == NULL) { + log_err("Registration unsupported."); + ret_msg->result = -ENOTSUP; + goto finish; + } + + ret_msg->result = ipcpi.ops->ipcp_reg(hash); + finish: + log_info("Finished registering " HASH_FMT32 " : %d.", + HASH_VAL32(hash), ret_msg->result); +} + +static void do_unreg(const uint8_t * hash, + ipcp_msg_t * ret_msg) +{ + log_info("Unregistering " HASH_FMT32 "...", HASH_VAL32(hash)); + + if (ipcpi.ops->ipcp_unreg == NULL) { + log_err("Unregistration unsupported."); + ret_msg->result = -ENOTSUP; + goto finish; + } + + ret_msg->result = ipcpi.ops->ipcp_unreg(hash); + finish: + log_info("Finished unregistering " HASH_FMT32 ": %d.", + HASH_VAL32(hash), ret_msg->result); +} + +static void do_query(const uint8_t * hash, + ipcp_msg_t * ret_msg) +{ + /* TODO: Log this operation when IRMd has internal caches. */ + + if (ipcpi.ops->ipcp_query == NULL) { + log_err("Directory query unsupported."); + ret_msg->result = -ENOTSUP; + return; + } + + if (ipcp_get_state() != IPCP_OPERATIONAL) { + log_err("IPCP in wrong state."); + ret_msg->result = -EIPCPSTATE; + return; + } + + ret_msg->result = ipcpi.ops->ipcp_query(hash); +} + +static void do_flow_alloc(pid_t pid, + int flow_id, + uint8_t * dst, + qosspec_t qs, + const buffer_t * data, + ipcp_msg_t * ret_msg) +{ + int fd; + + log_info("Allocating flow %d for %d to " HASH_FMT32 ".", + flow_id, pid, HASH_VAL32(dst)); + + if (ipcpi.ops->ipcp_flow_alloc == NULL) { + log_err("Flow allocation unsupported."); + ret_msg->result = -ENOTSUP; + goto finish; + } + + if (ipcp_get_state() != IPCP_OPERATIONAL) { + log_err("IPCP in wrong state."); + ret_msg->result = -EIPCPSTATE; + goto finish; + } + + fd = np1_flow_alloc(pid, flow_id); + if (fd < 0) { + log_err("Failed allocating n + 1 fd on flow_id %d: %d", + flow_id, fd); + ret_msg->result = -EFLOWDOWN; + goto finish; + } + + ret_msg->result = ipcpi.ops->ipcp_flow_alloc(fd, dst, qs, data); + finish: + log_info("Finished allocating flow %d to " HASH_FMT32 ": %d.", + flow_id, HASH_VAL32(dst), ret_msg->result); +} + + +static void do_flow_join(pid_t pid, + int flow_id, + const uint8_t * dst, + qosspec_t qs, + ipcp_msg_t * ret_msg) +{ + int fd; + + log_info("Joining layer " HASH_FMT32 ".", HASH_VAL32(dst)); + + if (ipcpi.ops->ipcp_flow_join == NULL) { + log_err("Broadcast unsupported."); + ret_msg->result = -ENOTSUP; + goto finish; + } + + if (ipcp_get_state() != IPCP_OPERATIONAL) { + log_err("IPCP in wrong state."); + ret_msg->result = -EIPCPSTATE; + goto finish; + } + + fd = np1_flow_alloc(pid, flow_id); + if (fd < 0) { + log_err("Failed allocating n + 1 fd on flow_id %d.", flow_id); + ret_msg->result = -1; + goto finish; + } + + ret_msg->result = ipcpi.ops->ipcp_flow_join(fd, dst, qs); + finish: + log_info("Finished joining layer " HASH_FMT32 ".", HASH_VAL32(dst)); +} + +static void do_flow_alloc_resp(int resp, + int flow_id, + const buffer_t * data, + ipcp_msg_t * ret_msg) +{ + int fd = -1; + + log_info("Responding %d to alloc on flow_id %d.", resp, flow_id); + + if (ipcpi.ops->ipcp_flow_alloc_resp == NULL) { + log_err("Flow_alloc_resp unsupported."); + ret_msg->result = -ENOTSUP; + goto finish; + } + + if (ipcp_get_state() != IPCP_OPERATIONAL) { + log_err("IPCP in wrong state."); + ret_msg->result = -EIPCPSTATE; + goto finish; + } + + if (resp == 0) { + fd = np1_flow_resp(flow_id); + if (fd < 0) { + log_warn("Flow_id %d is not known.", flow_id); + ret_msg->result = -1; + goto finish; + } + } + + ret_msg->result = ipcpi.ops->ipcp_flow_alloc_resp(fd, resp, data); + finish: + log_info("Finished responding to allocation request: %d", + ret_msg->result); +} + +static void do_flow_dealloc(int flow_id, + int timeo_sec, + ipcp_msg_t * ret_msg) +{ + int fd; + + log_info("Deallocating flow %d.", flow_id); + + if (ipcpi.ops->ipcp_flow_dealloc == NULL) { + log_err("Flow deallocation unsupported."); + ret_msg->result = -ENOTSUP; + goto finish; + } + + if (ipcp_get_state() != IPCP_OPERATIONAL) { + log_err("IPCP in wrong state."); + ret_msg->result = -EIPCPSTATE; + goto finish; + } + + fd = np1_flow_dealloc(flow_id, timeo_sec); + if (fd < 0) { + log_warn("Could not deallocate flow_id %d.", flow_id); + ret_msg->result = -1; + goto finish; + } + + ret_msg->result = ipcpi.ops->ipcp_flow_dealloc(fd); + finish: + log_info("Finished deallocating flow %d: %d.", + flow_id, ret_msg->result); +} + static void * mainloop(void * o) { int sfd; buffer_t buffer; - struct ipcp_config conf; - struct layer_info info; - ipcp_config_msg_t * conf_msg; ipcp_msg_t * msg; (void) o; while (true) { - ipcp_msg_t ret_msg = IPCP_MSG__INIT; - layer_info_msg_t layer_info = LAYER_INFO_MSG__INIT; - int fd = -1; - struct cmd * cmd; - qosspec_t qs; + ipcp_msg_t ret_msg = IPCP_MSG__INIT; + qosspec_t qs; + struct cmd * cmd; + buffer_t data; ret_msg.code = IPCP_MSG_CODE__IPCP_REPLY; pthread_mutex_lock(&ipcpi.cmd_lock); - pthread_cleanup_push((void *)(void *) pthread_mutex_unlock, - &ipcpi.cmd_lock); + pthread_cleanup_push(__cleanup_mutex_unlock, &ipcpi.cmd_lock); while (list_is_empty(&ipcpi.cmds)) pthread_cond_wait(&ipcpi.cmd_cond, &ipcpi.cmd_lock); @@ -208,328 +677,68 @@ static void * mainloop(void * o) tpm_dec(ipcpi.tpm); - pthread_cleanup_push(close_ptr, &sfd); + pthread_cleanup_push(__cleanup_close_ptr, &sfd); pthread_cleanup_push(free_msg, msg); + ret_msg.has_result = true; + switch (msg->code) { case IPCP_MSG_CODE__IPCP_BOOTSTRAP: - ret_msg.has_result = true; - - if (ipcpi.ops->ipcp_bootstrap == NULL) { - log_err("Bootstrap unsupported."); - ret_msg.result = -ENOTSUP; - break; - } - - if (ipcp_get_state() != IPCP_INIT) { - log_err("IPCP in wrong state."); - ret_msg.result = -EIPCPSTATE; - break; - } - - conf_msg = msg->conf; - conf.type = conf_msg->ipcp_type; - strcpy(conf.layer_info.layer_name, - conf_msg->layer_info->layer_name); - - switch(conf_msg->ipcp_type) { - case IPCP_LOCAL: - break; - case IPCP_UNICAST: - conf.addr_size = conf_msg->addr_size; - conf.eid_size = conf_msg->eid_size; - conf.max_ttl = conf_msg->max_ttl; - conf.addr_auth_type = conf_msg->addr_auth_type; - conf.routing_type = conf_msg->routing_type; - break; - case IPCP_ETH_DIX: - conf.ethertype = conf_msg->ethertype; - /* FALLTHRU */ - case IPCP_ETH_LLC: - conf.dev = conf_msg->dev; - break; - case IPCP_UDP: - conf.ip_addr = conf_msg->ip_addr; - conf.dns_addr = conf_msg->dns_addr; - conf.clt_port = conf_msg->clt_port; - conf.srv_port = conf_msg->srv_port; - conf.layer_info.dir_hash_algo = HASH_MD5; - layer_info.dir_hash_algo = HASH_MD5; - break; - case IPCP_BROADCAST: - conf.layer_info.dir_hash_algo = HASH_SHA3_256; - layer_info.dir_hash_algo = HASH_SHA3_256; - break; - default: - log_err("Unknown IPCP type: %d.", conf_msg->ipcp_type); - } - - /* UDP and broadcast use fixed hash algorithm. */ - if (conf_msg->ipcp_type != IPCP_UDP && - conf_msg->ipcp_type != IPCP_BROADCAST) { - switch(conf_msg->layer_info->dir_hash_algo) { - case DIR_HASH_SHA3_224: - conf.layer_info.dir_hash_algo = - HASH_SHA3_224; - break; - case DIR_HASH_SHA3_256: - conf.layer_info.dir_hash_algo = - HASH_SHA3_256; - break; - case DIR_HASH_SHA3_384: - conf.layer_info.dir_hash_algo = - HASH_SHA3_384; - break; - case DIR_HASH_SHA3_512: - conf.layer_info.dir_hash_algo = - HASH_SHA3_512; - break; - default: - assert(false); - } - - layer_info.dir_hash_algo = - conf.layer_info.dir_hash_algo; - } - - ipcpi.dir_hash_algo = conf.layer_info.dir_hash_algo; - - ret_msg.result = ipcpi.ops->ipcp_bootstrap(&conf); - if (ret_msg.result == 0) { - ret_msg.layer_info = &layer_info; - layer_info.layer_name = - conf.layer_info.layer_name; - } + do_bootstrap(msg->conf, &ret_msg); break; case IPCP_MSG_CODE__IPCP_ENROLL: - ret_msg.has_result = true; - - if (ipcpi.ops->ipcp_enroll == NULL) { - log_err("Enroll unsupported."); - ret_msg.result = -ENOTSUP; - break; - } - - if (ipcp_get_state() != IPCP_INIT) { - log_err("IPCP in wrong state."); - ret_msg.result = -EIPCPSTATE; - break; - } - - ret_msg.result = ipcpi.ops->ipcp_enroll(msg->dst, - &info); - if (ret_msg.result == 0) { - ret_msg.layer_info = &layer_info; - layer_info.dir_hash_algo = info.dir_hash_algo; - layer_info.layer_name = info.layer_name; - } + do_enroll(msg->dst, &ret_msg); break; case IPCP_MSG_CODE__IPCP_CONNECT: - ret_msg.has_result = true; - - if (ipcpi.ops->ipcp_connect == NULL) { - log_err("Connect unsupported."); - ret_msg.result = -ENOTSUP; - break; - } - - qs = msg_to_spec(msg->qosspec); - ret_msg.result = ipcpi.ops->ipcp_connect(msg->dst, - msg->comp, - qs); + qs = qos_spec_msg_to_s(msg->qosspec); + do_connect(msg->dst, msg->comp, qs, &ret_msg); break; case IPCP_MSG_CODE__IPCP_DISCONNECT: - ret_msg.has_result = true; - - if (ipcpi.ops->ipcp_disconnect == NULL) { - log_err("Disconnect unsupported."); - ret_msg.result = -ENOTSUP; - break; - } - - ret_msg.result = ipcpi.ops->ipcp_disconnect(msg->dst, - msg->comp); + do_disconnect(msg->dst, msg->comp, &ret_msg); break; case IPCP_MSG_CODE__IPCP_REG: - ret_msg.has_result = true; - - if (ipcpi.ops->ipcp_reg == NULL) { - log_err("Registration unsupported."); - ret_msg.result = -ENOTSUP; - break; - } - assert(msg->hash.len == ipcp_dir_hash_len()); - - ret_msg.result = - ipcpi.ops->ipcp_reg(msg->hash.data); + do_reg(msg->hash.data, &ret_msg); break; case IPCP_MSG_CODE__IPCP_UNREG: - ret_msg.has_result = true; - - if (ipcpi.ops->ipcp_unreg == NULL) { - log_err("Unregistration unsupported."); - ret_msg.result = -ENOTSUP; - break; - } - assert(msg->hash.len == ipcp_dir_hash_len()); - - ret_msg.result = - ipcpi.ops->ipcp_unreg(msg->hash.data); + do_unreg(msg->hash.data, &ret_msg); break; case IPCP_MSG_CODE__IPCP_QUERY: - ret_msg.has_result = true; - - if (ipcpi.ops->ipcp_query == NULL) { - log_err("Directory query unsupported."); - ret_msg.result = -ENOTSUP; - break; - } - assert(msg->hash.len == ipcp_dir_hash_len()); - - if (ipcp_get_state() != IPCP_OPERATIONAL) { - log_err("IPCP in wrong state."); - ret_msg.result = -EIPCPSTATE; - break; - } - - ret_msg.result = - ipcpi.ops->ipcp_query(msg->hash.data); + do_query(msg->hash.data, &ret_msg); break; case IPCP_MSG_CODE__IPCP_FLOW_ALLOC: - ret_msg.has_result = true; - - if (ipcpi.ops->ipcp_flow_alloc == NULL) { - log_err("Flow allocation unsupported."); - ret_msg.result = -ENOTSUP; - break; - } - assert(msg->hash.len == ipcp_dir_hash_len()); assert(msg->pk.len > 0 ? msg->pk.data != NULL : msg->pk.data == NULL); - - if (ipcp_get_state() != IPCP_OPERATIONAL) { - log_err("IPCP in wrong state."); - ret_msg.result = -EIPCPSTATE; - break; - } - - qs = msg_to_spec(msg->qosspec); - fd = np1_flow_alloc(msg->pid, - msg->flow_id, - qs); - if (fd < 0) { - log_err("Failed allocating fd on flow_id %d.", - msg->flow_id); - ret_msg.result = -1; - break; - } - - ret_msg.result = - ipcpi.ops->ipcp_flow_alloc(fd, - msg->hash.data, - qs, - msg->pk.data, - msg->pk.len); + data.len = msg->pk.len; + data.data = msg->pk.data; + qs = qos_spec_msg_to_s(msg->qosspec); + do_flow_alloc(msg->pid, msg->flow_id, + msg->hash.data, qs, + &data, &ret_msg); break; case IPCP_MSG_CODE__IPCP_FLOW_JOIN: - ret_msg.has_result = true; - - if (ipcpi.ops->ipcp_flow_join == NULL) { - log_err("Broadcast unsupported."); - ret_msg.result = -ENOTSUP; - break; - } - assert(msg->hash.len == ipcp_dir_hash_len()); - - if (ipcp_get_state() != IPCP_OPERATIONAL) { - log_err("IPCP in wrong state."); - ret_msg.result = -EIPCPSTATE; - break; - } - - qs = msg_to_spec(msg->qosspec); - fd = np1_flow_alloc(msg->pid, - msg->flow_id, - qs); - if (fd < 0) { - log_err("Failed allocating fd on flow_id %d.", - msg->flow_id); - ret_msg.result = -1; - break; - } - - ret_msg.result = - ipcpi.ops->ipcp_flow_join(fd, - msg->hash.data, - qs); + qs = qos_spec_msg_to_s(msg->qosspec); + do_flow_join(msg->pid, msg->flow_id, + msg->hash.data, qs, &ret_msg); break; case IPCP_MSG_CODE__IPCP_FLOW_ALLOC_RESP: - ret_msg.has_result = true; - if (ipcpi.ops->ipcp_flow_alloc_resp == NULL) { - log_err("Flow_alloc_resp unsupported."); - ret_msg.result = -ENOTSUP; - break; - } - - if (ipcp_get_state() != IPCP_OPERATIONAL) { - log_err("IPCP in wrong state."); - ret_msg.result = -EIPCPSTATE; - break; - } - - if (!msg->response) { - fd = np1_flow_resp(msg->flow_id); - if (fd < 0) { - log_warn("Port_id %d is not known.", - msg->flow_id); - ret_msg.result = -1; - break; - } - } - assert(msg->pk.len > 0 ? msg->pk.data != NULL - : msg->pk.data == NULL); - - ret_msg.result = - ipcpi.ops->ipcp_flow_alloc_resp(fd, - msg->response, - msg->pk.data, - msg->pk.len); + : msg->pk.data == NULL); + data.len = msg->pk.len; + data.data = msg->pk.data; + do_flow_alloc_resp(msg->response, msg->flow_id, + &data, &ret_msg); break; case IPCP_MSG_CODE__IPCP_FLOW_DEALLOC: - ret_msg.has_result = true; - if (ipcpi.ops->ipcp_flow_dealloc == NULL) { - log_err("Flow deallocation unsupported."); - ret_msg.result = -ENOTSUP; - break; - } - - if (ipcp_get_state() != IPCP_OPERATIONAL) { - log_err("IPCP in wrong state."); - ret_msg.result = -EIPCPSTATE; - break; - } - - fd = np1_flow_dealloc(msg->flow_id); - if (fd < 0) { - log_warn("Could not deallocate flow_id %d.", - msg->flow_id); - ret_msg.result = -1; - break; - } - - ret_msg.result = - ipcpi.ops->ipcp_flow_dealloc(fd); + do_flow_dealloc(msg->flow_id, msg->timeo_sec, &ret_msg); break; default: - ret_msg.has_result = true; - ret_msg.result = -1; - log_err("Don't know that message code"); + ret_msg.result = -1; + log_err("Unknown message code: %d.", msg->code); break; } @@ -554,12 +763,16 @@ static void * mainloop(void * o) ipcp_msg__pack(&ret_msg, buffer.data); - pthread_cleanup_push(close_ptr, &sfd); + if (ret_msg.layer_info != NULL) + layer_info_msg__free_unpacked(ret_msg.layer_info, NULL); + + pthread_cleanup_push(__cleanup_close_ptr, &sfd); + pthread_cleanup_push(free, buffer.data) if (write(sfd, buffer.data, buffer.len) == -1) log_warn("Failed to send reply message"); - free(buffer.data); + pthread_cleanup_pop(true); pthread_cleanup_pop(true); tpm_inc(ipcpi.tpm); @@ -595,7 +808,8 @@ static int parse_args(int argc, int ipcp_init(int argc, char ** argv, - struct ipcp_ops * ops) + struct ipcp_ops * ops, + enum ipcp_type type) { bool log; pthread_condattr_t cattr; @@ -608,7 +822,11 @@ int ipcp_init(int argc, ipcpi.irmd_fd = -1; ipcpi.state = IPCP_NULL; + ipcpi.type = type; +#if defined (__linux__) + prctl(PR_SET_TIMERSLACK, IPCP_LINUX_SLACK_NS, 0, 0, 0); +#endif ipcpi.sock_path = ipcp_sock_path(getpid()); if (ipcpi.sock_path == NULL) goto fail_sock_path; @@ -659,14 +877,39 @@ int ipcp_init(int argc, goto fail_cmd_cond; } + if (rib_init(ipcpi.name)) { + log_err("Failed to initialize RIB."); + goto fail_rib_init; + } + + if (rib_reg(IPCP_INFO, &r_ops)) { + log_err("Failed to register rib."); + goto fail_rib_reg; + } + + ipcpi.tpm = tpm_create(IPCP_MIN_THREADS, IPCP_ADD_THREADS, + mainloop, NULL); + if (ipcpi.tpm == NULL) { + log_err("Failed to create threadpool manager."); + goto fail_tpm_create; + } + list_head_init(&ipcpi.cmds); ipcpi.alloc_id = -1; pthread_condattr_destroy(&cattr); + ipcp_set_state(IPCP_INIT); + return 0; + fail_tpm_create: + rib_unreg(IPCP_INFO); + fail_rib_reg: + rib_fini(); + fail_rib_init: + pthread_cond_destroy(&ipcpi.cmd_cond); fail_cmd_cond: pthread_mutex_destroy(&ipcpi.cmd_lock); fail_cmd_lock: @@ -687,48 +930,62 @@ int ipcp_init(int argc, return ret; } -int ipcp_boot() +int ipcp_start(void) { - sigset_t sigset; + sigset_t sigset; + struct ipcp_info info; + sigemptyset(&sigset); sigaddset(&sigset, SIGINT); sigaddset(&sigset, SIGQUIT); sigaddset(&sigset, SIGHUP); sigaddset(&sigset, SIGPIPE); - ipcpi.tpm = tpm_create(IPCP_MIN_THREADS, IPCP_ADD_THREADS, - mainloop, NULL); - if (ipcpi.tpm == NULL) - goto fail_tpm_create; - pthread_sigmask(SIG_BLOCK, &sigset, NULL); + info.pid = getpid(); + info.type = ipcpi.type; + strcpy(info.name, ipcpi.name); + info.state = IPCP_OPERATIONAL; + if (tpm_start(ipcpi.tpm)) goto fail_tpm_start; - ipcp_set_state(IPCP_INIT); - if (pthread_create(&ipcpi.acceptor, NULL, acceptloop, NULL)) { log_err("Failed to create acceptor thread."); - ipcp_set_state(IPCP_NULL); goto fail_acceptor; } + info.state = IPCP_OPERATIONAL; + + if (ipcp_create_r(&info)) { + log_err("Failed to notify IRMd we are initialized."); + goto fail_create_r; + } + return 0; + fail_create_r: + pthread_cancel(ipcpi.acceptor); + pthread_join(ipcpi.acceptor, NULL); fail_acceptor: tpm_stop(ipcpi.tpm); fail_tpm_start: tpm_destroy(ipcpi.tpm); - fail_tpm_create: + ipcp_set_state(IPCP_NULL); + info.state = IPCP_NULL; + ipcp_create_r(&info); return -1; } -void ipcp_shutdown() +void ipcp_sigwait(void) { + siginfo_t info; sigset_t sigset; - +#ifdef __APPLE__ + int sig; +#endif sigemptyset(&sigset); sigaddset(&sigset, SIGINT); sigaddset(&sigset, SIGQUIT); @@ -738,15 +995,27 @@ void ipcp_shutdown() while(ipcp_get_state() != IPCP_NULL && ipcp_get_state() != IPCP_SHUTDOWN) { +#ifdef __APPLE__ + if (sigwait(&sigset, &sig) < 0) { +#else if (sigwaitinfo(&sigset, &info) < 0) { +#endif log_warn("Bad signal."); continue; } +#ifdef __APPLE__ + memset(&info, 0, sizeof(info)); + info.si_signo = sig; + info.si_pid = ipcpi.irmd_pid; +#endif switch(info.si_signo) { case SIGINT: + /* FALLTHRU */ case SIGTERM: + /* FALLTHRU */ case SIGHUP: + /* FALLTHRU */ case SIGQUIT: if (info.si_pid == ipcpi.irmd_pid) { if (ipcp_get_state() == IPCP_INIT) @@ -758,22 +1027,32 @@ void ipcp_shutdown() break; case SIGPIPE: log_dbg("Ignored SIGPIPE."); + continue; default: continue; } } +} - pthread_cancel(ipcpi.acceptor); +void ipcp_stop(void) +{ + log_info("IPCP %d shutting down.", getpid()); + pthread_cancel(ipcpi.acceptor); pthread_join(ipcpi.acceptor, NULL); - tpm_stop(ipcpi.tpm); - tpm_destroy(ipcpi.tpm); - log_info("IPCP %d shutting down.", getpid()); + tpm_stop(ipcpi.tpm); } -void ipcp_fini() +void ipcp_fini(void) { + + tpm_destroy(ipcpi.tpm); + + rib_unreg(IPCP_INFO); + + rib_fini(); + close(ipcpi.sockfd); if (unlink(ipcpi.sock_path)) log_warn("Could not unlink %s.", ipcpi.sock_path); @@ -802,7 +1081,7 @@ void ipcp_set_state(enum ipcp_state state) pthread_mutex_unlock(&ipcpi.state_mtx); } -enum ipcp_state ipcp_get_state() +enum ipcp_state ipcp_get_state(void) { enum ipcp_state state; @@ -815,38 +1094,6 @@ enum ipcp_state ipcp_get_state() return state; } -int ipcp_wait_state(enum ipcp_state state, - const struct timespec * timeout) -{ - struct timespec abstime; - int ret = 0; - - clock_gettime(PTHREAD_COND_CLOCK, &abstime); - ts_add(&abstime, timeout, &abstime); - - pthread_mutex_lock(&ipcpi.state_mtx); - - pthread_cleanup_push((void *)(void *) pthread_mutex_unlock, - &ipcpi.state_mtx); - - while (ipcpi.state != state - && ipcpi.state != IPCP_SHUTDOWN - && ipcpi.state != IPCP_NULL - && ret != -ETIMEDOUT) { - if (timeout == NULL) - ret = -pthread_cond_wait(&ipcpi.state_cond, - &ipcpi.state_mtx); - else - ret = -pthread_cond_timedwait(&ipcpi.state_cond, - &ipcpi.state_mtx, - &abstime); - } - - pthread_cleanup_pop(true); - - return ret; -} - void ipcp_lock_to_core(void) { #if defined(__linux__) && !defined(DISABLE_CORE_LOCK) diff --git a/src/ipcpd/ipcp.h b/src/ipcpd/ipcp.h index 02c74f50..aab490c7 100644 --- a/src/ipcpd/ipcp.h +++ b/src/ipcpd/ipcp.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * IPC process structure * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -26,19 +26,14 @@ #include <ouroboros/hash.h> #include <ouroboros/ipcp.h> #include <ouroboros/list.h> +#include <ouroboros/protobuf.h> +#include <ouroboros/qos.h> #include <ouroboros/sockets.h> #include <ouroboros/tpm.h> #include <pthread.h> #include <time.h> -enum ipcp_state { - IPCP_NULL = 0, - IPCP_INIT, - IPCP_OPERATIONAL, - IPCP_SHUTDOWN -}; - struct ipcp_ops { int (* ipcp_bootstrap)(const struct ipcp_config * conf); @@ -58,20 +53,18 @@ struct ipcp_ops { int (* ipcp_query)(const uint8_t * hash); - int (* ipcp_flow_alloc)(int fd, - const uint8_t * dst, - qosspec_t qs, - const void * data, - size_t len); + int (* ipcp_flow_alloc)(int fd, + const uint8_t * dst, + qosspec_t qs, + const buffer_t * data); int (* ipcp_flow_join)(int fd, const uint8_t * dst, qosspec_t qs); - int (* ipcp_flow_alloc_resp)(int fd, - int response, - const void * data, - size_t len); + int (* ipcp_flow_alloc_resp)(int fd, + int response, + const buffer_t * data); int (* ipcp_flow_dealloc)(int fd); }; @@ -79,12 +72,12 @@ struct ipcp_ops { #define ipcp_dir_hash_strlen() (hash_len(ipcpi.dir_hash_algo) * 2) #define ipcp_dir_hash_len() (hash_len(ipcpi.dir_hash_algo)) -struct ipcp { +extern struct ipcp { pid_t irmd_pid; char * name; enum ipcp_type type; - char * layer_name; + char layer_name[LAYER_NAME_SIZE + 1]; uint64_t dt_addr; @@ -94,9 +87,8 @@ struct ipcp { int irmd_fd; enum ipcp_state state; - pthread_rwlock_t state_lock; - pthread_mutex_t state_mtx; pthread_cond_t state_cond; + pthread_mutex_t state_mtx; int sockfd; char * sock_path; @@ -116,11 +108,14 @@ struct ipcp { int ipcp_init(int argc, char ** argv, - struct ipcp_ops * ops); + struct ipcp_ops * ops, + enum ipcp_type type); -int ipcp_boot(void); +int ipcp_start(void); -void ipcp_shutdown(void); +void ipcp_sigwait(void); + +void ipcp_stop(void); void ipcp_fini(void); @@ -128,12 +123,17 @@ void ipcp_set_state(enum ipcp_state state); enum ipcp_state ipcp_get_state(void); -int ipcp_wait_state(enum ipcp_state state, - const struct timespec * timeout); - int ipcp_parse_arg(int argc, char * argv[]); +/* Helper functions to handle races during flow allocation */ +int ipcp_wait_flow_req_arr(const uint8_t * dst, + qosspec_t qs, + time_t mpl, + const buffer_t * data); + +int ipcp_wait_flow_resp(const int fd); + /* Helper functions for directory entries, could be moved */ uint8_t * ipcp_hash_dup(const uint8_t * hash); diff --git a/src/ipcpd/local/CMakeLists.txt b/src/ipcpd/local/CMakeLists.txt index a84f4f1b..10fd0120 100644 --- a/src/ipcpd/local/CMakeLists.txt +++ b/src/ipcpd/local/CMakeLists.txt @@ -13,6 +13,8 @@ include_directories(${CMAKE_SOURCE_DIR}/include) include_directories(${CMAKE_BINARY_DIR}/include) set(IPCP_LOCAL_TARGET ipcpd-local CACHE INTERNAL "") +set(IPCP_LOCAL_MPL 2 CACHE STRING + "Default maximum packet lifetime for the Ethernet IPCPs, in seconds") set(LOCAL_SOURCES # Add source files here diff --git a/src/ipcpd/local/main.c b/src/ipcpd/local/main.c index a2e20017..160e07e0 100644 --- a/src/ipcpd/local/main.c +++ b/src/ipcpd/local/main.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Local IPC process * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -48,8 +48,9 @@ #include <sys/wait.h> #include <assert.h> -#define THIS_TYPE IPCP_LOCAL -#define ALLOC_TIMEOUT 10 /* ms */ +#define THIS_TYPE IPCP_LOCAL + +struct ipcp ipcpi; struct { struct shim_data * shim_data; @@ -70,34 +71,39 @@ static int local_data_init(void) local_data.flows = fset_create(); if (local_data.flows == NULL) - return -ENFILE; + goto fail_fset; local_data.fq = fqueue_create(); - if (local_data.fq == NULL) { - fset_destroy(local_data.flows); - return -ENOMEM; - } + if (local_data.fq == NULL) + goto fail_fqueue; local_data.shim_data = shim_data_create(); - if (local_data.shim_data == NULL) { - fqueue_destroy(local_data.fq); - fset_destroy(local_data.flows); - return -ENOMEM; - } + if (local_data.shim_data == NULL) + goto fail_shim_data; - pthread_rwlock_init(&local_data.lock, NULL); + if (pthread_rwlock_init(&local_data.lock, NULL) < 0) + goto fail_rwlock_init; return 0; + + fail_rwlock_init: + shim_data_destroy(local_data.shim_data); + fail_shim_data: + fqueue_destroy(local_data.fq); + fail_fqueue: + fset_destroy(local_data.flows); + fail_fset: + return -ENOMEM; } static void local_data_fini(void){ + pthread_rwlock_destroy(&local_data.lock); shim_data_destroy(local_data.shim_data); - fset_destroy(local_data.flows); fqueue_destroy(local_data.fq); - pthread_rwlock_destroy(&local_data.lock); + fset_destroy(local_data.flows); } -static void * ipcp_local_packet_loop(void * o) +static void * local_ipcp_packet_loop(void * o) { (void) o; @@ -133,49 +139,45 @@ static void * ipcp_local_packet_loop(void * o) return (void *) 0; } -static int ipcp_local_bootstrap(const struct ipcp_config * conf) +static int local_ipcp_bootstrap(const struct ipcp_config * conf) { assert(conf); assert(conf->type == THIS_TYPE); - (void) conf; - - ipcp_set_state(IPCP_OPERATIONAL); + ipcpi.dir_hash_algo = (enum hash_algo) conf->layer_info.dir_hash_algo; + strcpy(ipcpi.layer_name,conf->layer_info.name); if (pthread_create(&local_data.packet_loop, NULL, - ipcp_local_packet_loop, NULL)) { + local_ipcp_packet_loop, NULL)) { + log_err("Failed to create pthread: %s", strerror(errno)); ipcp_set_state(IPCP_INIT); return -1; } - log_info("Bootstrapped local IPCP with pid %d.", getpid()); - return 0; } -static int ipcp_local_reg(const uint8_t * hash) +static int local_ipcp_reg(const uint8_t * hash) { if (shim_data_reg_add_entry(local_data.shim_data, hash)) { - log_dbg("Failed to add " HASH_FMT " to local registry.", - HASH_VAL(hash)); + log_err("Failed to add " HASH_FMT32 " to local registry.", + HASH_VAL32(hash)); return -1; } - log_info("Registered " HASH_FMT ".", HASH_VAL(hash)); - return 0; } -static int ipcp_local_unreg(const uint8_t * hash) +static int local_ipcp_unreg(const uint8_t * hash) { shim_data_reg_del_entry(local_data.shim_data, hash); - log_info("Unregistered " HASH_FMT ".", HASH_VAL(hash)); + log_info("Unregistered " HASH_FMT32 ".", HASH_VAL32(hash)); return 0; } -static int ipcp_local_query(const uint8_t * hash) +static int local_ipcp_query(const uint8_t * hash) { int ret; @@ -184,41 +186,19 @@ static int ipcp_local_query(const uint8_t * hash) return ret; } -static int ipcp_local_flow_alloc(int fd, - const uint8_t * dst, - qosspec_t qs, - const void * data, - size_t len) +static int local_ipcp_flow_alloc(int fd, + const uint8_t * dst, + qosspec_t qs, + const buffer_t * data) { - struct timespec ts = {0, ALLOC_TIMEOUT * MILLION}; - struct timespec abstime; - int out_fd = -1; + int out_fd = -1; - log_dbg("Allocating flow to " HASH_FMT " on fd %d.", HASH_VAL(dst), fd); + log_dbg("Allocating flow to " HASH_FMT32 " on fd %d.", + HASH_VAL32(dst), fd); assert(dst); - 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) { - log_dbg("Won't allocate over non-operational IPCP."); - pthread_mutex_unlock(&ipcpi.alloc_lock); - return -1; - } - - assert(ipcpi.alloc_id == -1); - - out_fd = ipcp_flow_req_arr(dst, ipcp_dir_hash_len(), qs, data, len); + out_fd = ipcp_wait_flow_req_arr(dst, qs, IPCP_LOCAL_MPL, data); if (out_fd < 0) { - pthread_mutex_unlock(&ipcpi.alloc_lock); log_dbg("Flow allocation failed: %d", out_fd); return -1; } @@ -230,11 +210,6 @@ static int ipcp_local_flow_alloc(int fd, pthread_rwlock_unlock(&local_data.lock); - ipcpi.alloc_id = out_fd; - pthread_cond_broadcast(&ipcpi.alloc_cond); - - pthread_mutex_unlock(&ipcpi.alloc_lock); - fset_add(local_data.flows, fd); log_info("Pending local allocation request on fd %d.", fd); @@ -242,40 +217,21 @@ static int ipcp_local_flow_alloc(int fd, return 0; } -static int ipcp_local_flow_alloc_resp(int fd, - int response, - const void * data, - size_t len) +static int local_ipcp_flow_alloc_resp(int fd, + int response, + const buffer_t * data) { - struct timespec ts = {0, ALLOC_TIMEOUT * MILLION}; - struct timespec abstime; - int out_fd = -1; - int ret = -1; - - clock_gettime(PTHREAD_COND_CLOCK, &abstime); - - pthread_mutex_lock(&ipcpi.alloc_lock); + struct timespec wait = TIMESPEC_INIT_MS(1); + time_t mpl = IPCP_LOCAL_MPL; + int out_fd; - 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); + if (ipcp_wait_flow_resp(fd) < 0) { + log_err("Failed waiting for IRMd response."); return -1; } - ipcpi.alloc_id = -1; - pthread_cond_broadcast(&ipcpi.alloc_cond); - - pthread_mutex_unlock(&ipcpi.alloc_lock); - - pthread_rwlock_wrlock(&local_data.lock); - - if (response) { + if (response < 0) { + pthread_rwlock_wrlock(&local_data.lock); if (local_data.in_out[fd] != -1) local_data.in_out[local_data.in_out[fd]] = fd; local_data.in_out[fd] = -1; @@ -283,25 +239,38 @@ static int ipcp_local_flow_alloc_resp(int fd, return 0; } + pthread_rwlock_rdlock(&local_data.lock); + out_fd = local_data.in_out[fd]; if (out_fd == -1) { pthread_rwlock_unlock(&local_data.lock); - return -1; + log_dbg("Potential race detected"); + nanosleep(&wait, NULL); + pthread_rwlock_rdlock(&local_data.lock); + out_fd = local_data.in_out[fd]; } pthread_rwlock_unlock(&local_data.lock); + if (out_fd == -1) { + log_err("Invalid out_fd."); + return -1; + } + fset_add(local_data.flows, fd); - if ((ret = ipcp_flow_alloc_reply(out_fd, response, data, len)) < 0) + if (ipcp_flow_alloc_reply(out_fd, response, mpl, data) < 0) { + log_err("Failed to reply to allocation"); + fset_del(local_data.flows, fd); return -1; + } log_info("Flow allocation completed, fds (%d, %d).", out_fd, fd); return 0; } -static int ipcp_local_flow_dealloc(int fd) +static int local_ipcp_flow_dealloc(int fd) { assert(!(fd < 0)); @@ -315,7 +284,7 @@ static int ipcp_local_flow_dealloc(int fd) pthread_rwlock_unlock(&local_data.lock); - flow_dealloc(fd); + ipcp_flow_dealloc(fd); log_info("Flow with fd %d deallocated.", fd); @@ -323,60 +292,54 @@ static int ipcp_local_flow_dealloc(int fd) } static struct ipcp_ops local_ops = { - .ipcp_bootstrap = ipcp_local_bootstrap, + .ipcp_bootstrap = local_ipcp_bootstrap, .ipcp_enroll = NULL, .ipcp_connect = NULL, .ipcp_disconnect = NULL, - .ipcp_reg = ipcp_local_reg, - .ipcp_unreg = ipcp_local_unreg, - .ipcp_query = ipcp_local_query, - .ipcp_flow_alloc = ipcp_local_flow_alloc, + .ipcp_reg = local_ipcp_reg, + .ipcp_unreg = local_ipcp_unreg, + .ipcp_query = local_ipcp_query, + .ipcp_flow_alloc = local_ipcp_flow_alloc, .ipcp_flow_join = NULL, - .ipcp_flow_alloc_resp = ipcp_local_flow_alloc_resp, - .ipcp_flow_dealloc = ipcp_local_flow_dealloc + .ipcp_flow_alloc_resp = local_ipcp_flow_alloc_resp, + .ipcp_flow_dealloc = local_ipcp_flow_dealloc }; int main(int argc, char * argv[]) { - if (ipcp_init(argc, argv, &local_ops) < 0) - goto fail_init; - if (local_data_init() < 0) { log_err("Failed to init local data."); goto fail_data_init; } - if (ipcp_boot() < 0) { - log_err("Failed to boot IPCP."); - goto fail_boot; - } + if (ipcp_init(argc, argv, &local_ops, THIS_TYPE) < 0) + goto fail_init; - if (ipcp_create_r(0)) { - log_err("Failed to notify IRMd we are initialized."); - goto fail_create_r; + if (ipcp_start() < 0) { + log_err("Failed to start IPCP."); + goto fail_start; } - ipcp_shutdown(); + ipcp_sigwait(); if (ipcp_get_state() == IPCP_SHUTDOWN) { pthread_cancel(local_data.packet_loop); pthread_join(local_data.packet_loop, NULL); } - local_data_fini(); + ipcp_stop(); ipcp_fini(); - exit(EXIT_SUCCESS); - fail_create_r: - ipcp_set_state(IPCP_NULL); - ipcp_shutdown(); - fail_boot: local_data_fini(); - fail_data_init: + + exit(EXIT_SUCCESS); + + fail_start: ipcp_fini(); fail_init: - ipcp_create_r(-1); + local_data_fini(); + fail_data_init: exit(EXIT_FAILURE); } diff --git a/src/ipcpd/raptor/CMakeLists.txt b/src/ipcpd/raptor/CMakeLists.txt deleted file mode 100644 index 1883d9bb..00000000 --- a/src/ipcpd/raptor/CMakeLists.txt +++ /dev/null @@ -1,50 +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) - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux") - find_path(RAPTOR_KERNEL_MODULE - NAMES - raptor.ko.gz - raptor.ko.xz - HINTS - /lib/modules/${CMAKE_SYSTEM_VERSION}/extra - ) - - mark_as_advanced(RAPTOR_KERNEL_MODULE) - - if (RAPTOR_KERNEL_MODULE) - set(DISABLE_RAPTOR FALSE CACHE BOOL - "Disable support for raptor devices") - if (NOT DISABLE_RAPTOR) - message(STATUS "Kernel module for raptor found. Building raptor.") - set(IPCP_RAPTOR_TARGET ipcpd-raptor CACHE INTERNAL "") - - set(RAPTOR_SOURCES - # Add source files here - ${CMAKE_CURRENT_SOURCE_DIR}/main.c) - - add_executable(ipcpd-raptor ${RAPTOR_SOURCES} ${IPCP_SOURCES}) - target_link_libraries(ipcpd-raptor LINK_PUBLIC ouroboros-dev) - - include(AddCompileFlags) - if (CMAKE_BUILD_TYPE MATCHES "Debug*") - add_compile_flags(ipcpd-raptor -DCONFIG_OUROBOROS_DEBUG) - endif () - - install(TARGETS ipcpd-raptor RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}) - else () - message(STATUS "Raptor support disabled by user") - endif () - endif () -endif () diff --git a/src/ipcpd/raptor/main.c b/src/ipcpd/raptor/main.c deleted file mode 100644 index 5cd7d50e..00000000 --- a/src/ipcpd/raptor/main.c +++ /dev/null @@ -1,1114 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2020 - * - * IPC process using the Raptor FPGA. - * - * Alexander D'hoore <dhoore.alexander@gmail.com> - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> - * - * 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 _DEFAULT_SOURCE - -#include "config.h" - -#define OUROBOROS_PREFIX "ipcpd/raptor" - -#include <ouroboros/hash.h> -#include <ouroboros/errno.h> -#include <ouroboros/list.h> -#include <ouroboros/utils.h> -#include <ouroboros/bitmap.h> -#include <ouroboros/dev.h> -#include <ouroboros/local-dev.h> -#include <ouroboros/ipcp-dev.h> -#include <ouroboros/fqueue.h> -#include <ouroboros/logs.h> -#include <ouroboros/time_utils.h> - -#include "ipcp.h" -#include "shim-data.h" - -#include <net/if.h> -#include <signal.h> -#include <stdlib.h> -#include <pthread.h> -#include <fcntl.h> -#include <unistd.h> -#include <string.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/ioctl.h> -#include <netinet/in.h> -#include <malloc.h> - -#ifdef __linux__ -#include <linux/if_packet.h> -#include <linux/if_ether.h> -#endif - -#include <poll.h> -#include <sys/mman.h> - -#define THIS_TYPE IPCP_RAPTOR -#define MGMT_EID 0x01 -#define MAC_SIZE 6 -#define MAX_EIDS 64 - -#define EVENT_WAIT_TIMEOUT 100 /* us */ -#define NAME_QUERY_TIMEOUT 2000 /* ms */ -#define MGMT_TIMEOUT 100 /* ms */ - -#define IOCTL_SEND 0xAD420000 -#define IOCTL_RECV 0xAD430000 -#define IOCTL_SEND_DONE 0xAD440000 -#define IOCTL_RECV_DONE 0xAD450000 -#define IOCTL_RECV_NEED 0xAD460000 - -#define RAPTOR_PAGE ((1 << 12) - 200) /* 4kB - 200 */ -#define RAPTOR_PAGE_MASK (~0xFFF) - -#define RAPTOR_BATCH 100 -#define RAPTOR_HEADER 3 - -#define FLOW_REQ 0 -#define FLOW_REPLY 1 -#define NAME_QUERY_REQ 2 -#define NAME_QUERY_REPLY 3 - -struct mgmt_msg { - uint8_t code; - uint8_t seid; - uint8_t deid; - int8_t response; - /* QoS parameters from spec, aligned */ - uint32_t loss; - uint64_t bandwidth; - uint32_t ber; - uint32_t max_gap; - uint32_t delay; - uint8_t in_order; - uint8_t availability; -} __attribute__((packed)); - -struct ef { - int8_t eid; - int8_t r_eid; -}; - -struct mgmt_frame { - struct list_head next; - uint8_t buf[RAPTOR_PAGE]; - size_t len; -}; - -struct { - struct shim_data * shim_data; - - int ioctl_fd; - - struct bmp * eids; - fset_t * np1_flows; - fqueue_t * fq; - int * ef_to_fd; - struct ef * fd_to_ef; - pthread_rwlock_t flows_lock; - - pthread_t send_thread; - pthread_t recv_thread; - pthread_t send_done_thread; - pthread_t recv_done_thread; - - /* Handle mgmt frames in a different thread */ - pthread_t mgmt_handler; - pthread_mutex_t mgmt_lock; - pthread_cond_t mgmt_cond; - struct list_head mgmt_frames; - -} raptor_data; - -static int raptor_data_init(void) -{ - int i; - int ret = -ENOMEM; - pthread_condattr_t cattr; - - raptor_data.fd_to_ef = - malloc(sizeof(*raptor_data.fd_to_ef) * SYS_MAX_FLOWS); - if (raptor_data.fd_to_ef == NULL) - goto fail_fd_to_ef; - - raptor_data.ef_to_fd = - malloc(sizeof(*raptor_data.ef_to_fd) * MAX_EIDS); - if (raptor_data.ef_to_fd == NULL) - goto fail_ef_to_fd; - - raptor_data.eids = bmp_create(MAX_EIDS, 2); - if (raptor_data.eids == NULL) - goto fail_eids; - - raptor_data.np1_flows = fset_create(); - if (raptor_data.np1_flows == NULL) - goto fail_np1_flows; - - raptor_data.fq = fqueue_create(); - if (raptor_data.fq == NULL) - goto fail_fq; - - for (i = 0; i < MAX_EIDS; ++i) - raptor_data.ef_to_fd[i] = -1; - - for (i = 0; i < SYS_MAX_FLOWS; ++i) { - raptor_data.fd_to_ef[i].eid = -1; - raptor_data.fd_to_ef[i].r_eid = -1; - } - - raptor_data.shim_data = shim_data_create(); - if (raptor_data.shim_data == NULL) - goto fail_shim_data; - - ret = -1; - - if (pthread_rwlock_init(&raptor_data.flows_lock, NULL)) - goto fail_flows_lock; - - if (pthread_mutex_init(&raptor_data.mgmt_lock, NULL)) - goto fail_mgmt_lock; - - if (pthread_condattr_init(&cattr)) - goto fail_condattr; - -#ifndef __APPLE__ - pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK); -#endif - - if (pthread_cond_init(&raptor_data.mgmt_cond, &cattr)) - goto fail_mgmt_cond; - - pthread_condattr_destroy(&cattr); - - list_head_init(&raptor_data.mgmt_frames); - - return 0; - - fail_mgmt_cond: - pthread_condattr_destroy(&cattr); - fail_condattr: - pthread_mutex_destroy(&raptor_data.mgmt_lock); - fail_mgmt_lock: - pthread_rwlock_destroy(&raptor_data.flows_lock); - fail_flows_lock: - shim_data_destroy(raptor_data.shim_data); - fail_shim_data: - fqueue_destroy(raptor_data.fq); - fail_fq: - fset_destroy(raptor_data.np1_flows); - fail_np1_flows: - bmp_destroy(raptor_data.eids); - fail_eids: - free(raptor_data.ef_to_fd); - fail_ef_to_fd: - free(raptor_data.fd_to_ef); - fail_fd_to_ef: - return ret; -} - -static void raptor_data_fini(void) -{ - close(raptor_data.ioctl_fd); - pthread_cond_destroy(&raptor_data.mgmt_cond); - pthread_mutex_destroy(&raptor_data.mgmt_lock); - pthread_rwlock_destroy(&raptor_data.flows_lock); - fqueue_destroy(raptor_data.fq); - fset_destroy(raptor_data.np1_flows); - bmp_destroy(raptor_data.eids); - free(raptor_data.fd_to_ef); - free(raptor_data.ef_to_fd); -} - -static int raptor_send_frame(struct shm_du_buff * sdb, - uint8_t deid) -{ - uint8_t * frame; - size_t frame_len; - uint8_t * payload; - size_t len; - - payload = shm_du_buff_head(sdb); - len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb); - - frame_len = RAPTOR_HEADER + len; - - if (frame_len >= RAPTOR_PAGE) { - log_err("Payload too large."); - return -1; - } - - frame = memalign(1 << 12, 1 << 12); - if (frame == NULL) { - log_err("frame == NULL"); - return -1; - } - - if ((uint64_t)frame & 0xFFF) { - log_err("page offset not zero"); - return -1; - } - - frame[0] = (frame_len & 0x00FF) >> 0; - frame[1] = (frame_len & 0xFF00) >> 8; - frame[2] = deid; - - memcpy(&frame[RAPTOR_HEADER], payload, len); - - if (ioctl(raptor_data.ioctl_fd, IOCTL_SEND | 1, &frame) != 1) { - log_err("Ioctl send failed."); - free(frame); - return -1; - } - - return 0; -} - -static int raptor_eid_alloc(uint8_t seid, - const uint8_t * hash, - qosspec_t qs) -{ - struct mgmt_msg * msg; - struct shm_du_buff * sdb; - - if (ipcp_sdb_reserve(&sdb, sizeof(*msg) + ipcp_dir_hash_len()) < 0) { - log_err("failed to reserve sdb for management frame."); - return -1; - } - - msg = (struct mgmt_msg *) shm_du_buff_head(sdb); - msg->code = FLOW_REQ; - msg->seid = seid; - 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, hash, ipcp_dir_hash_len()); - - if (raptor_send_frame(sdb, MGMT_EID)) { - log_err("Failed to send management frame."); - ipcp_sdb_release(sdb); - return -1; - } - - ipcp_sdb_release(sdb); - - return 0; -} - -static int raptor_eid_alloc_resp(uint8_t seid, - uint8_t deid, - int response) -{ - struct mgmt_msg * msg; - struct shm_du_buff * sdb; - - if (ipcp_sdb_reserve(&sdb, sizeof(*msg)) < 0) { - log_err("Failed to reserve sdb for management frame."); - return -1; - } - - msg = (struct mgmt_msg *) shm_du_buff_head(sdb); - msg->code = FLOW_REPLY; - msg->seid = seid; - msg->deid = deid; - msg->response = response; - - if (raptor_send_frame(sdb, MGMT_EID)) { - log_err("Failed to send management frame."); - ipcp_sdb_release(sdb); - return -1; - } - - ipcp_sdb_release(sdb); - - return 0; -} - -static int raptor_eid_req(uint8_t r_eid, - const uint8_t * dst, - qosspec_t qs) -{ - struct timespec ts = {0, EVENT_WAIT_TIMEOUT * 1000}; - struct timespec abstime; - int fd; - - 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) { - log_dbg("Won't allocate over non-operational IPCP."); - pthread_mutex_unlock(&ipcpi.alloc_lock); - return -1; - } - - /* reply to IRM, called under lock to prevent race */ - fd = ipcp_flow_req_arr(getpid(), dst, ipcp_dir_hash_len(), qs); - if (fd < 0) { - pthread_mutex_unlock(&ipcpi.alloc_lock); - log_err("Could not get new flow from IRMd."); - return -1; - } - - pthread_rwlock_wrlock(&raptor_data.flows_lock); - - raptor_data.fd_to_ef[fd].r_eid = r_eid; - - ipcpi.alloc_id = fd; - pthread_cond_broadcast(&ipcpi.alloc_cond); - - pthread_rwlock_unlock(&raptor_data.flows_lock); - pthread_mutex_unlock(&ipcpi.alloc_lock); - - log_dbg("New flow request, fd %d, remote EID %d.", fd, r_eid); - - return 0; -} - -static int raptor_eid_alloc_reply(uint8_t seid, - int deid, - int response) -{ - int ret = 0; - int fd = -1; - - pthread_rwlock_wrlock(&raptor_data.flows_lock); - - fd = raptor_data.ef_to_fd[deid]; - if (fd < 0) { - pthread_rwlock_unlock(& raptor_data.flows_lock); - log_err("No flow found with that EID."); - return -1; /* -EFLOWNOTFOUND */ - } - - if (response) - bmp_release(raptor_data.eids, raptor_data.fd_to_ef[fd].eid); - else - raptor_data.fd_to_ef[fd].r_eid = seid; - - pthread_rwlock_unlock(&raptor_data.flows_lock); - - log_dbg("Flow reply, fd %d, SEID %d, DEID %d.", fd, seid, deid); - - if ((ret = ipcp_flow_alloc_reply(fd, response)) < 0) - return -1; - - return ret; - -} - -static int raptor_name_query_req(const uint8_t * hash) -{ - struct mgmt_msg * msg; - struct shm_du_buff * sdb; - - if (!shim_data_reg_has(raptor_data.shim_data, hash)) - return 0; - - if (ipcp_sdb_reserve(&sdb, sizeof(*msg) + ipcp_dir_hash_len()) < 0) { - log_err("Failed to reserve sdb for management frame."); - return -1; - } - - msg = (struct mgmt_msg *) shm_du_buff_head(sdb); - msg->code = NAME_QUERY_REPLY; - - memcpy(msg + 1, hash, ipcp_dir_hash_len()); - - if (raptor_send_frame(sdb, MGMT_EID)) { - log_err("Failed to send management frame."); - ipcp_sdb_release(sdb); - return -1; - } - - ipcp_sdb_release(sdb); - - return 0; -} - -static int raptor_name_query_reply(const uint8_t * hash) -{ - shim_data_dir_add_entry(raptor_data.shim_data, hash, 0); - - shim_data_dir_query_respond(raptor_data.shim_data, hash); - - return 0; -} - -static int raptor_mgmt_frame(const uint8_t * buf, - size_t len) -{ - struct mgmt_msg * msg = (struct mgmt_msg *) buf; - uint8_t * hash = (uint8_t *) (msg + 1); - qosspec_t qs; - - switch (msg->code) { - case FLOW_REQ: - if (len != sizeof(*msg) + ipcp_dir_hash_len()) { - log_err("Corrupt message received."); - return -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); - - if (shim_data_reg_has(raptor_data.shim_data, hash)) - raptor_eid_req(msg->seid, hash, qs); - break; - case FLOW_REPLY: - if (len != sizeof(*msg)) { - log_err("Corrupt message received."); - return -1; - } - - raptor_eid_alloc_reply(msg->seid, msg->deid, msg->response); - break; - case NAME_QUERY_REQ: - if (len != sizeof(*msg) + ipcp_dir_hash_len()) { - log_err("Corrupt message received."); - return -1; - } - - raptor_name_query_req(hash); - break; - case NAME_QUERY_REPLY: - if (len != sizeof(*msg) + ipcp_dir_hash_len()) { - log_err("Corrupt message received."); - return -1; - } - - raptor_name_query_reply(hash); - break; - default: - log_err("Unknown message received %d.", msg->code); - return -1; - } - - return 0; -} - -static void * raptor_mgmt_handler(void * o) -{ - int ret; - struct timespec timeout = {(MGMT_TIMEOUT / 1000), - (MGMT_TIMEOUT % 1000) * MILLION}; - struct timespec abstime; - struct mgmt_frame * frame; - - (void) o; - - while (true) { - ret = 0; - - if (ipcp_get_state() != IPCP_OPERATIONAL) - break; - - clock_gettime(PTHREAD_COND_CLOCK, &abstime); - ts_add(&abstime, &timeout, &abstime); - - pthread_mutex_lock(&raptor_data.mgmt_lock); - - while (list_is_empty(&raptor_data.mgmt_frames) && - ret != -ETIMEDOUT) - ret = -pthread_cond_timedwait(&raptor_data.mgmt_cond, - &raptor_data.mgmt_lock, - &abstime); - - if (ret == -ETIMEDOUT) { - pthread_mutex_unlock(&raptor_data.mgmt_lock); - continue; - } - - frame = list_first_entry((&raptor_data.mgmt_frames), - struct mgmt_frame, next); - if (frame == NULL) { - pthread_mutex_unlock(&raptor_data.mgmt_lock); - continue; - } - - list_del(&frame->next); - pthread_mutex_unlock(&raptor_data.mgmt_lock); - - raptor_mgmt_frame(frame->buf, frame->len); - free(frame); - } - - return NULL; -} - -static void raptor_recv_frame(uint8_t * frame) -{ - uint8_t deid; - uint8_t * payload; - size_t frame_len; - size_t length; - int fd; - struct mgmt_frame * mgmt_frame; - struct shm_du_buff * sdb; - size_t idx; - - sdb = (struct shm_du_buff *)((uint64_t) frame & RAPTOR_PAGE_MASK); - idx = shm_du_buff_get_idx(sdb); - - frame_len = frame[0] | (frame[1] << 8); - if (frame_len < RAPTOR_HEADER) { - log_err("Received packet smaller than header alone."); - ipcp_sdb_release(sdb); - return; - } - - if (frame_len >= RAPTOR_PAGE) { - log_err("Received packet too large."); - ipcp_sdb_release(sdb); - return; - } - - deid = frame[2]; - payload = &frame[RAPTOR_HEADER]; - length = frame_len - RAPTOR_HEADER; - - shm_du_buff_head_release(sdb, RAPTOR_HEADER); - shm_du_buff_tail_release(sdb, RAPTOR_PAGE - frame_len); - - if (deid == MGMT_EID) { - pthread_mutex_lock(&raptor_data.mgmt_lock); - - mgmt_frame = malloc(sizeof(*mgmt_frame)); - if (mgmt_frame == NULL) { - pthread_mutex_unlock(&raptor_data.mgmt_lock); - ipcp_sdb_release(sdb); - return; - } - - memcpy(mgmt_frame->buf, payload, length); - mgmt_frame->len = length; - list_add(&mgmt_frame->next, &raptor_data.mgmt_frames); - pthread_cond_signal(&raptor_data.mgmt_cond); - pthread_mutex_unlock(&raptor_data.mgmt_lock); - - ipcp_sdb_release(sdb); - } else { - pthread_rwlock_rdlock(&raptor_data.flows_lock); - - fd = raptor_data.ef_to_fd[deid]; - if (fd < 0) { - pthread_rwlock_unlock(&raptor_data.flows_lock); - ipcp_sdb_release(sdb); - return; - } - - pthread_rwlock_unlock(&raptor_data.flows_lock); - - local_flow_write(fd, idx); - } -} - -static void * raptor_recv_done_thread(void * o) -{ - uint8_t * frames[RAPTOR_BATCH]; - int count; - int i; - - (void) o; - - while (true) { - if (ipcp_get_state() != IPCP_OPERATIONAL) - break; - - count = ioctl(raptor_data.ioctl_fd, - IOCTL_RECV_DONE | RAPTOR_BATCH, frames); - - if (count <= 0) - continue; - - for (i = 0; i < count; i++) - raptor_recv_frame(frames[i]); - } - - return NULL; -} - -static void * raptor_send_thread(void * o) -{ - struct timespec timeout = {0, EVENT_WAIT_TIMEOUT * 1000}; - int fd; - struct shm_du_buff * sdb; - uint8_t deid; - - (void) o; - - while (fevent(raptor_data.np1_flows, raptor_data.fq, &timeout)) { - if (ipcp_get_state() != IPCP_OPERATIONAL) - break; - - pthread_rwlock_rdlock(&raptor_data.flows_lock); - while ((fd = fqueue_next(raptor_data.fq)) >= 0) { - if (ipcp_flow_read(fd, &sdb)) { - log_err("Bad read from fd %d.", fd); - continue; - } - - deid = raptor_data.fd_to_ef[fd].r_eid; - - raptor_send_frame(sdb, deid); - } - pthread_rwlock_unlock(&raptor_data.flows_lock); - } - - return NULL; -} - -static void * raptor_send_done_thread(void * o) -{ - uint8_t * frames[RAPTOR_BATCH]; - int count; - int i; - - (void) o; - - while (true) { - if (ipcp_get_state() != IPCP_OPERATIONAL) - break; - - count = ioctl(raptor_data.ioctl_fd, - IOCTL_SEND_DONE | RAPTOR_BATCH, frames); - - if (count <= 0) - continue; - - for (i = 0; i < count; i++) - free(frames[i]); - } - - return NULL; -} - -static void * raptor_recv_thread(void * o) -{ - struct shm_du_buff * sdb; - uint8_t * frames[RAPTOR_BATCH]; - uint8_t ** head; - int needed = 0; - int count; - int i; - - (void) o; - - while (true) { - if (ipcp_get_state() != IPCP_OPERATIONAL) - break; - - needed = ioctl(raptor_data.ioctl_fd, - IOCTL_RECV_NEED | RAPTOR_BATCH, NULL); - - if (needed <= 0) - continue; - - for (i = 0; i < needed; i++) { - if (ipcp_sdb_reserve(&sdb, RAPTOR_PAGE) < 0) { - log_err("Recv thread: reserve sdb failed."); - return NULL; - } - - if ((uint64_t)sdb & (~RAPTOR_PAGE_MASK)) { - log_err("Recv thread: sdb not at offset 0."); - return NULL; - } - - frames[i] = shm_du_buff_head(sdb); - - if ((uint64_t)frames[i] & 0x7) { - log_err("Recv thread: frame not aligned."); - return NULL; - } - } - - head = frames; - - do { - count = ioctl(raptor_data.ioctl_fd, - IOCTL_RECV | needed, head); - if (count <= 0) - continue; - - assert(count <= needed); - - needed -= count; - head += count; - - } while (needed > 0 && ipcp_get_state() == IPCP_OPERATIONAL); - } - - return NULL; -} - -static int raptor_bootstrap(const struct ipcp_config * conf) -{ - assert(conf); - assert(conf->type == THIS_TYPE); - - (void) conf; - - raptor_data.ioctl_fd = open("/dev/raptor", 0); - if (raptor_data.ioctl_fd < 0) { - log_err("Failed to open /dev/raptor."); - goto fail_ioctl; - } - - ipcp_set_state(IPCP_OPERATIONAL); - - if (pthread_create(&raptor_data.mgmt_handler, - NULL, - raptor_mgmt_handler, - NULL)) { - ipcp_set_state(IPCP_INIT); - goto fail_mgmt_handler; - } - - if (pthread_create(&raptor_data.send_thread, - NULL, - raptor_send_thread, - NULL)) { - ipcp_set_state(IPCP_INIT); - goto fail_send_thread; - } - - if (pthread_create(&raptor_data.recv_thread, - NULL, - raptor_recv_thread, - NULL)) { - ipcp_set_state(IPCP_INIT); - goto fail_recv_thread; - } - - if (pthread_create(&raptor_data.send_done_thread, - NULL, - raptor_send_done_thread, - NULL)) { - ipcp_set_state(IPCP_INIT); - goto fail_send_done_thread; - } - - if (pthread_create(&raptor_data.recv_done_thread, - NULL, - raptor_recv_done_thread, - NULL)) { - ipcp_set_state(IPCP_INIT); - goto fail_recv_done_thread; - } - - log_dbg("Bootstrapped raptor IPCP with api %d.", getpid()); - - return 0; - - fail_recv_done_thread: - pthread_join(raptor_data.send_done_thread, NULL); - fail_send_done_thread: - pthread_join(raptor_data.recv_thread, NULL); - fail_recv_thread: - pthread_join(raptor_data.send_thread, NULL); - fail_send_thread: - pthread_join(raptor_data.mgmt_handler, NULL); - fail_mgmt_handler: - close(raptor_data.ioctl_fd); - fail_ioctl: - return -1; -} - -static int raptor_reg(const uint8_t * hash) -{ - uint8_t * hash_dup; - - hash_dup = ipcp_hash_dup(hash); - if (hash_dup == NULL) { - log_err("Failed to duplicate hash."); - return -ENOMEM; - } - - if (shim_data_reg_add_entry(raptor_data.shim_data, hash_dup)) { - log_err("Failed to add " HASH_FMT " to local registry.", - HASH_VAL(hash)); - free(hash_dup); - return -1; - } - - log_dbg("Registered " HASH_FMT ".", HASH_VAL(hash)); - - return 0; -} - -static int raptor_unreg(const uint8_t * hash) -{ - shim_data_reg_del_entry(raptor_data.shim_data, hash); - - return 0; -} - -static int raptor_query(const uint8_t * hash) -{ - struct timespec timeout = {(NAME_QUERY_TIMEOUT / 1000), - (NAME_QUERY_TIMEOUT % 1000) * MILLION}; - struct mgmt_msg * msg; - struct dir_query * query; - int ret; - struct shm_du_buff * sdb; - - if (shim_data_dir_has(raptor_data.shim_data, hash)) - return 0; - - if (ipcp_sdb_reserve(&sdb, sizeof(*msg) + ipcp_dir_hash_len()) < 0) { - log_err("failed to reserve sdb for management frame."); - return -1; - } - - msg = (struct mgmt_msg *) shm_du_buff_head(sdb); - msg->code = NAME_QUERY_REQ; - - memcpy(msg + 1, hash, ipcp_dir_hash_len()); - - query = shim_data_dir_query_create(raptor_data.shim_data, hash); - if (query == NULL) { - ipcp_sdb_release(sdb); - return -1; - } - - if (raptor_send_frame(sdb, MGMT_EID)) { - log_err("Failed to send management frame."); - ipcp_sdb_release(sdb); - return -1; - } - - ret = shim_data_dir_query_wait(query, &timeout); - - shim_data_dir_query_destroy(raptor_data.shim_data, query); - - return ret; -} - -static int raptor_flow_alloc(int fd, - const uint8_t * hash, - qosspec_t qs) -{ - uint8_t seid = 0; - - log_dbg("Allocating flow to " HASH_FMT ".", HASH_VAL(hash)); - - assert(hash); - - if (!shim_data_dir_has(raptor_data.shim_data, hash)) { - log_err("Destination unreachable."); - return -1; - } - - pthread_rwlock_wrlock(&raptor_data.flows_lock); - - seid = bmp_allocate(raptor_data.eids); - if (!bmp_is_id_valid(raptor_data.eids, seid)) { - pthread_rwlock_unlock(&raptor_data.flows_lock); - return -1; - } - - raptor_data.fd_to_ef[fd].eid = seid; - raptor_data.ef_to_fd[seid] = fd; - - pthread_rwlock_unlock(&raptor_data.flows_lock); - - if (raptor_eid_alloc(seid, hash, qs) < 0) { - pthread_rwlock_wrlock(&raptor_data.flows_lock); - bmp_release(raptor_data.eids, raptor_data.fd_to_ef[fd].eid); - raptor_data.fd_to_ef[fd].eid = -1; - raptor_data.ef_to_fd[seid] = -1; - pthread_rwlock_unlock(&raptor_data.flows_lock); - return -1; - } - - fset_add(raptor_data.np1_flows, fd); - - log_dbg("Pending flow with fd %d on EID %d.", fd, seid); - - return 0; -} - -static int raptor_flow_alloc_resp(int fd, - int response) -{ - struct timespec ts = {0, EVENT_WAIT_TIMEOUT * 1000}; - struct timespec abstime; - uint8_t seid = 0; - uint8_t r_eid = 0; - - 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); - - pthread_rwlock_wrlock(&raptor_data.flows_lock); - - seid = bmp_allocate(raptor_data.eids); - if (!bmp_is_id_valid(raptor_data.eids, seid)) { - pthread_rwlock_unlock(&raptor_data.flows_lock); - return -1; - } - - raptor_data.fd_to_ef[fd].eid = seid; - r_eid = raptor_data.fd_to_ef[fd].r_eid; - raptor_data.ef_to_fd[seid] = fd; - - pthread_rwlock_unlock(&raptor_data.flows_lock); - - if (raptor_eid_alloc_resp(seid, r_eid, response) < 0) { - pthread_rwlock_wrlock(&raptor_data.flows_lock); - bmp_release(raptor_data.eids, raptor_data.fd_to_ef[fd].eid); - pthread_rwlock_unlock(&raptor_data.flows_lock); - return -1; - } - - fset_add(raptor_data.np1_flows, fd); - - log_dbg("Accepted flow, fd %d, EID %d.", fd, (uint8_t)seid); - - return 0; -} - -static int raptor_flow_dealloc(int fd) -{ - uint8_t eid; - - ipcp_flow_fini(fd); - - pthread_rwlock_wrlock(&raptor_data.flows_lock); - - fset_del(raptor_data.np1_flows, fd); - - eid = raptor_data.fd_to_ef[fd].eid; - bmp_release(raptor_data.eids, eid); - raptor_data.fd_to_ef[fd].eid = -1; - raptor_data.fd_to_ef[fd].r_eid = -1; - - raptor_data.ef_to_fd[eid] = -1; - - pthread_rwlock_unlock(&raptor_data.flows_lock); - - flow_dealloc(fd); - - log_dbg("Flow with fd %d deallocated.", fd); - - return 0; -} - -static struct ipcp_ops raptor_ops = { - .ipcp_bootstrap = raptor_bootstrap, - .ipcp_enroll = NULL, - .ipcp_reg = raptor_reg, - .ipcp_unreg = raptor_unreg, - .ipcp_query = raptor_query, - .ipcp_flow_alloc = raptor_flow_alloc, - .ipcp_flow_join = NULL, - .ipcp_flow_alloc_resp = raptor_flow_alloc_resp, - .ipcp_flow_dealloc = raptor_flow_dealloc -}; - -int main(int argc, - char * argv[]) -{ - if (ipcp_init(argc, argv, &raptor_ops) < 0) { - log_err("Failed to init IPCP."); - goto fail_init; - } - - if (raptor_data_init() < 0) { - log_err("Failed to init shim-eth-llc data."); - goto fail_data_init; - } - - if (ipcp_boot() < 0) { - log_err("Failed to boot IPCP."); - goto fail_boot; - } - - if (ipcp_create_r(getpid(), 0)) { - log_err("Failed to notify IRMd we are initialized."); - ipcp_set_state(IPCP_NULL); - goto fail_create_r; - } - - log_info("Raptor created."); - - ipcp_shutdown(); - - if (ipcp_get_state() == IPCP_SHUTDOWN) { - pthread_join(raptor_data.send_thread, NULL); - pthread_join(raptor_data.recv_thread, NULL); - pthread_join(raptor_data.send_done_thread, NULL); - pthread_join(raptor_data.recv_done_thread, NULL); - pthread_join(raptor_data.mgmt_handler, NULL); - } - - raptor_data_fini(); - - ipcp_fini(); - - exit(EXIT_SUCCESS); - - fail_create_r: - ipcp_shutdown(); - fail_boot: - raptor_data_fini(); - fail_data_init: - ipcp_fini(); - fail_init: - ipcp_create_r(getpid(), -1); - exit(EXIT_FAILURE); -} diff --git a/src/ipcpd/shim-data.c b/src/ipcpd/shim-data.c index 60f0245a..1fac63ac 100644 --- a/src/ipcpd/shim-data.c +++ b/src/ipcpd/shim-data.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * IPC process utilities * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -30,18 +30,18 @@ #define OUROBOROS_PREFIX "shim-data" -#include <ouroboros/endian.h> -#include <ouroboros/logs.h> -#include <ouroboros/list.h> -#include <ouroboros/time_utils.h> #include <ouroboros/errno.h> +#include <ouroboros/hash.h> +#include <ouroboros/list.h> +#include <ouroboros/logs.h> +#include <ouroboros/time.h> #include "shim-data.h" #include "ipcp.h" -#include <string.h> -#include <stdlib.h> #include <assert.h> +#include <stdlib.h> +#include <string.h> struct reg_entry { struct list_head list; @@ -74,6 +74,9 @@ static void destroy_dir_query(struct dir_query * query) case QUERY_DESTROY: pthread_mutex_unlock(&query->lock); return; + default: + assert(false); + return; } while (query->state != QUERY_DONE) @@ -136,9 +139,11 @@ static void dir_entry_destroy(struct dir_entry * entry) free(entry); } -struct shim_data * shim_data_create() +struct shim_data * shim_data_create(void) { - struct shim_data * sd = malloc(sizeof(*sd)); + struct shim_data * sd; + + sd = malloc(sizeof(*sd)); if (sd == NULL) return NULL; @@ -148,11 +153,23 @@ struct shim_data * shim_data_create() list_head_init(&sd->dir_queries); /* init the locks */ - pthread_rwlock_init(&sd->reg_lock, NULL); - pthread_rwlock_init(&sd->dir_lock, NULL); - pthread_mutex_init(&sd->dir_queries_lock, NULL); + if (pthread_rwlock_init(&sd->reg_lock, NULL) < 0) + goto fail_reg_lock_init; + + if (pthread_rwlock_init(&sd->dir_lock, NULL) < 0) + goto fail_dir_lock_init; + + if (pthread_mutex_init(&sd->dir_queries_lock, NULL) < 0) + goto fail_mutex_init; return sd; + + fail_mutex_init: + pthread_rwlock_destroy(&sd->dir_lock); + fail_dir_lock_init: + pthread_rwlock_destroy(&sd->reg_lock); + fail_reg_lock_init: + return NULL; } static void clear_registry(struct shim_data * data) @@ -280,8 +297,8 @@ int shim_data_reg_add_entry(struct shim_data * data, if (find_reg_entry_by_hash(data, hash)) { pthread_rwlock_unlock(&data->reg_lock); - log_dbg(HASH_FMT " was already in the directory.", - HASH_VAL(hash)); + log_dbg(HASH_FMT32 " was already in the directory.", + HASH_VAL32(hash)); return 0; } @@ -429,9 +446,9 @@ uint64_t shim_data_dir_get_addr(struct shim_data * data, pthread_rwlock_rdlock(&data->dir_lock); entry = find_dir_entry_any(data, hash); - if (entry == NULL) { pthread_rwlock_unlock(&data->dir_lock); + log_warn("No address for " HASH_FMT32 ".", HASH_VAL32(hash)); return 0; /* undefined behaviour, 0 may be a valid address */ } diff --git a/src/ipcpd/shim-data.h b/src/ipcpd/shim-data.h index af937f07..372b4ea7 100644 --- a/src/ipcpd/shim-data.h +++ b/src/ipcpd/shim-data.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Utitilies for building IPC processes * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 diff --git a/src/ipcpd/udp/CMakeLists.txt b/src/ipcpd/udp/CMakeLists.txt index f1a29ef6..8ae5518e 100644 --- a/src/ipcpd/udp/CMakeLists.txt +++ b/src/ipcpd/udp/CMakeLists.txt @@ -58,6 +58,8 @@ set(IPCP_UDP_RD_THR 3 CACHE STRING "Number of reader threads in UDP IPCP") set(IPCP_UDP_WR_THR 3 CACHE STRING "Number of writer threads in UDP IPCP") +set(IPCP_UDP_MPL 60 CACHE STRING + "Default maximum packet lifetime for the UDP IPCP, in seconds") include(AddCompileFlags) if (CMAKE_BUILD_TYPE MATCHES "Debug*") diff --git a/src/ipcpd/udp/main.c b/src/ipcpd/udp/main.c index 04c21a8b..2e8d84ce 100644 --- a/src/ipcpd/udp/main.c +++ b/src/ipcpd/udp/main.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * IPC process over UDP * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -31,6 +31,7 @@ #define OUROBOROS_PREFIX "ipcpd/udp" #include <ouroboros/bitmap.h> +#include <ouroboros/endian.h> #include <ouroboros/hash.h> #include <ouroboros/list.h> #include <ouroboros/utils.h> @@ -39,6 +40,7 @@ #include <ouroboros/fqueue.h> #include <ouroboros/errno.h> #include <ouroboros/logs.h> +#include <ouroboros/pthread.h> #include "ipcp.h" #include "shim-data.h" @@ -51,7 +53,6 @@ #include <netinet/in.h> #include <signal.h> #include <stdlib.h> -#include <pthread.h> #include <sys/wait.h> #include <fcntl.h> @@ -65,18 +66,23 @@ #define IPCP_UDP_BUF_SIZE 8980 #define IPCP_UDP_MSG_SIZE 8980 #define DNS_TTL 86400 -#define FD_UPDATE_TIMEOUT 100 /* microseconds */ -#define SERV_PORT udp_data.s_saddr.sin_port; -#define SERV_SADDR ((struct sockaddr *) &udp_data.s_saddr) -#define CLNT_SADDR ((struct sockaddr *) &udp_data.c_saddr) -#define SERV_SADDR_SIZE (sizeof(udp_data.s_saddr)) +#define SADDR ((struct sockaddr *) &udp_data.s_saddr) +#define SADDR_SIZE (sizeof(udp_data.s_saddr)) #define LOCAL_IP (udp_data.s_saddr.sin_addr.s_addr) #define MGMT_EID 0 #define MGMT_FRAME_SIZE (sizeof(struct mgmt_msg)) #define MGMT_FRAME_BUF_SIZE 2048 +#ifdef __linux__ +#define SENDTO_FLAGS MSG_CONFIRM +#else +#define SENDTO_FLAGS 0 +#endif + +struct ipcp ipcpi; + /* Keep order for alignment. */ struct mgmt_msg { uint32_t eid; @@ -92,7 +98,9 @@ struct mgmt_msg { uint32_t loss; uint32_t ber; uint32_t max_gap; + uint32_t timeout; uint16_t cypher_s; + } __attribute__((packed)); struct mgmt_frame { @@ -104,20 +112,17 @@ struct mgmt_frame { /* UDP flow */ struct uf { - int d_eid; - /* IP details are stored through connect(). */ - int skfd; + int d_eid; + struct sockaddr_in r_saddr; }; struct { struct shim_data * shim_data; uint32_t dns_addr; - /* server socket */ + struct sockaddr_in s_saddr; int s_fd; - /* client port */ - int clt_port; fset_t * np1_flows; struct uf fd_to_uf[SYS_MAX_FLOWS]; @@ -135,21 +140,25 @@ struct { static int udp_data_init(void) { - int i; + int i; + pthread_condattr_t cattr; if (pthread_rwlock_init(&udp_data.flows_lock, NULL)) goto fail_rwlock_init; - if (pthread_cond_init(&udp_data.mgmt_cond, NULL)) + if (pthread_condattr_init(&cattr)) + goto fail_condattr; +#ifndef __APPLE__ + pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK); +#endif + if (pthread_cond_init(&udp_data.mgmt_cond, &cattr)) goto fail_mgmt_cond; if (pthread_mutex_init(&udp_data.mgmt_lock, NULL)) goto fail_mgmt_lock; - for (i = 0; i < SYS_MAX_FLOWS; ++i) { - udp_data.fd_to_uf[i].skfd = -1; + for (i = 0; i < SYS_MAX_FLOWS; ++i) udp_data.fd_to_uf[i].d_eid = -1; - } udp_data.np1_flows = fset_create(); if (udp_data.np1_flows == NULL) @@ -159,9 +168,12 @@ static int udp_data_init(void) if (udp_data.shim_data == NULL) goto fail_data; + pthread_condattr_destroy(&cattr); + list_head_init(&udp_data.mgmt_frames); return 0; + fail_data: fset_destroy(udp_data.np1_flows); fail_fset: @@ -169,6 +181,8 @@ static int udp_data_init(void) fail_mgmt_lock: pthread_cond_destroy(&udp_data.mgmt_cond); fail_mgmt_cond: + pthread_condattr_destroy(&cattr); + fail_condattr: pthread_rwlock_destroy(&udp_data.flows_lock); fail_rwlock_init: return -1; @@ -185,22 +199,21 @@ static void udp_data_fini(void) pthread_mutex_destroy(&udp_data.mgmt_lock); } -static int ipcp_udp_port_alloc(int skfd, - uint32_t s_eid, - const uint8_t * dst, - qosspec_t qs, - const void * data, - size_t dlen) +static int udp_ipcp_port_alloc(const struct sockaddr_in * r_saddr, + uint32_t s_eid, + const uint8_t * dst, + qosspec_t qs, + const buffer_t * data) { uint8_t * buf; struct mgmt_msg * msg; size_t len; - assert(dlen > 0 ? data != NULL : data == NULL); + assert(data->len > 0 ? data->data != NULL : data->data == NULL); len = sizeof(*msg) + ipcp_dir_hash_len(); - buf = malloc(len + dlen); + buf = malloc(len + data->len); if (buf == NULL) return -1; @@ -216,11 +229,15 @@ static int ipcp_udp_port_alloc(int skfd, msg->in_order = qs.in_order; msg->max_gap = hton32(qs.max_gap); msg->cypher_s = hton16(qs.cypher_s); + msg->timeout = hton32(qs.timeout); memcpy(msg + 1, dst, ipcp_dir_hash_len()); - memcpy(buf + len, data, dlen); + if (data->len > 0) + memcpy(buf + len, data->data, data->len); - if (write(skfd, msg, len + dlen) < 0) { + if (sendto(udp_data.s_fd, msg, len + data->len, + SENDTO_FLAGS, + (const struct sockaddr *) r_saddr, sizeof(*r_saddr)) < 0) { free(buf); return -1; } @@ -230,16 +247,15 @@ static int ipcp_udp_port_alloc(int skfd, return 0; } -static int ipcp_udp_port_alloc_resp(int skfd, - uint32_t s_eid, - uint32_t d_eid, - int8_t response, - const void * data, - size_t len) +static int udp_ipcp_port_alloc_resp(const struct sockaddr_in * r_saddr, + uint32_t s_eid, + uint32_t d_eid, + int8_t response, + const buffer_t * data) { - struct mgmt_msg * msg; + struct mgmt_msg * msg; - msg = malloc(sizeof(*msg) + len); + msg = malloc(sizeof(*msg) + data->len); if (msg == NULL) return -1; @@ -249,9 +265,12 @@ static int ipcp_udp_port_alloc_resp(int skfd, msg->d_eid = hton32(d_eid); msg->response = response; - memcpy(msg + 1, data, len); + if (data->len > 0) + memcpy(msg + 1, data->data, data->len); - if (write(skfd, msg, sizeof(*msg) + len) < 0) { + if (sendto(udp_data.s_fd, msg, sizeof(*msg) + data->len, + SENDTO_FLAGS, + (const struct sockaddr *) r_saddr, sizeof(*r_saddr)) < 0 ) { free(msg); return -1; } @@ -261,134 +280,74 @@ static int ipcp_udp_port_alloc_resp(int skfd, return 0; } -static int ipcp_udp_port_req(struct sockaddr_in * c_saddr, +static int udp_ipcp_port_req(struct sockaddr_in * c_saddr, int d_eid, const uint8_t * dst, qosspec_t qs, - const void * data, - size_t len) + const buffer_t * data) { - struct timespec ts = {0, FD_UPDATE_TIMEOUT * 1000}; - struct timespec abstime; - int skfd; - int fd; - - skfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (skfd < 0) { - log_err("Could not create UDP socket."); - return -1; - } - - /* Remote listens on server port. Mod of c_saddr allowed. */ - c_saddr->sin_port = udp_data.s_saddr.sin_port; + int fd; - /* Connect stores the remote address in the file descriptor. */ - if (connect(skfd, (struct sockaddr *) c_saddr, sizeof(*c_saddr)) < 0) { - log_err("Could not connect to remote UDP client."); - close(skfd); - return -1; - } - - 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) { - log_dbg("Won't allocate over non-operational IPCP."); - pthread_mutex_unlock(&ipcpi.alloc_lock); - close(skfd); - return -1; - } - - /* reply to IRM */ - fd = ipcp_flow_req_arr(dst, ipcp_dir_hash_len(), qs, data, len); + fd = ipcp_wait_flow_req_arr(dst, qs, IPCP_UDP_MPL, data); if (fd < 0) { - pthread_mutex_unlock(&ipcpi.alloc_lock); log_err("Could not get new flow from IRMd."); - close(skfd); return -1; } pthread_rwlock_wrlock(&udp_data.flows_lock); - udp_data.fd_to_uf[fd].skfd = skfd; - udp_data.fd_to_uf[fd].d_eid = d_eid; + udp_data.fd_to_uf[fd].r_saddr = *c_saddr; + udp_data.fd_to_uf[fd].d_eid = d_eid; pthread_rwlock_unlock(&udp_data.flows_lock); - ipcpi.alloc_id = fd; - pthread_cond_broadcast(&ipcpi.alloc_cond); - - pthread_mutex_unlock(&ipcpi.alloc_lock); - log_dbg("Pending allocation request, fd %d, remote eid %d.", fd, d_eid); return 0; } -static int ipcp_udp_port_alloc_reply(uint32_t s_eid, - uint32_t d_eid, - int8_t response, - const void * data, - size_t len) +static int udp_ipcp_port_alloc_reply(const struct sockaddr_in * saddr, + uint32_t s_eid, + uint32_t d_eid, + int8_t response, + const buffer_t * data) { - struct sockaddr_in t_saddr; - socklen_t t_saddr_len; - int ret = 0; - int skfd = -1; - - t_saddr_len = sizeof(t_saddr); + time_t mpl = IPCP_UDP_MPL; pthread_rwlock_wrlock(&udp_data.flows_lock); - skfd = udp_data.fd_to_uf[s_eid].skfd; - if (skfd < 0) { + if (memcmp(&udp_data.fd_to_uf[s_eid].r_saddr, saddr, sizeof(*saddr))) { pthread_rwlock_unlock(&udp_data.flows_lock); - log_err("Got reply for unknown UDP eid: %u.", s_eid); + log_err("Flow allocation reply for %u from wrong source.", + s_eid); return -1; } - udp_data.fd_to_uf[s_eid].d_eid = d_eid; + if (response == 0) + udp_data.fd_to_uf[s_eid].d_eid = d_eid; pthread_rwlock_unlock(&udp_data.flows_lock); - if (getpeername(skfd, (struct sockaddr *) &t_saddr, &t_saddr_len) < 0) { - log_dbg("Flow with fd %d has no peer.", s_eid); - close(skfd); - return -1; - } - - if (connect(skfd, (struct sockaddr *) &t_saddr, sizeof(t_saddr)) < 0) { - log_dbg("Could not connect flow to remote."); - close(skfd); - return -1; - } - - if (ipcp_flow_alloc_reply(s_eid, response, data, len) < 0) { - log_dbg("Failed to reply to flow allocation."); + if (ipcp_flow_alloc_reply(s_eid, response, mpl, data) < 0) { + log_err("Failed to reply to flow allocation."); return -1; } log_dbg("Flow allocation completed on eids (%d, %d).", s_eid, d_eid); - return ret; + return 0; } -static int ipcp_udp_mgmt_frame(const uint8_t * buf, +static int udp_ipcp_mgmt_frame(const uint8_t * buf, size_t len, struct sockaddr_in c_saddr) { struct mgmt_msg * msg; size_t msg_len; qosspec_t qs; + buffer_t data; msg = (struct mgmt_msg *) buf; @@ -398,6 +357,10 @@ static int ipcp_udp_mgmt_frame(const uint8_t * buf, assert(len >= msg_len); + data.len = len - msg_len; + data.data = (uint8_t *) buf + msg_len; + + qs.delay = ntoh32(msg->delay); qs.bandwidth = ntoh64(msg->bandwidth); qs.availability = msg->availability; @@ -406,31 +369,33 @@ static int ipcp_udp_mgmt_frame(const uint8_t * buf, qs.in_order = msg->in_order; qs.max_gap = ntoh32(msg->max_gap); qs.cypher_s = ntoh16(msg->cypher_s); + qs.timeout = ntoh32(msg->timeout); - return ipcp_udp_port_req(&c_saddr, ntoh32(msg->s_eid), + return udp_ipcp_port_req(&c_saddr, ntoh32(msg->s_eid), (uint8_t *) (msg + 1), qs, - buf + msg_len, - len - msg_len); + &data); case FLOW_REPLY: assert(len >= sizeof(*msg)); - return ipcp_udp_port_alloc_reply(ntoh32(msg->s_eid), + data.len = len - sizeof(*msg); + data.data = (uint8_t *) buf + sizeof(*msg); + + return udp_ipcp_port_alloc_reply(&c_saddr, + ntoh32(msg->s_eid), ntoh32(msg->d_eid), msg->response, - buf + sizeof(*msg), - len - sizeof(*msg)); + &data); default: log_err("Unknown message received %d.", msg->code); return -1; } } -static void * ipcp_udp_mgmt_handler(void * o) +static void * udp_ipcp_mgmt_handler(void * o) { (void) o; - pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, - (void *) &udp_data.mgmt_lock); + pthread_cleanup_push(__cleanup_mutex_unlock, &udp_data.mgmt_lock); while (true) { struct mgmt_frame * frame; @@ -448,7 +413,7 @@ static void * ipcp_udp_mgmt_handler(void * o) pthread_mutex_unlock(&udp_data.mgmt_lock); - ipcp_udp_mgmt_frame(frame->buf, frame->len, frame->r_saddr); + udp_ipcp_mgmt_frame(frame->buf, frame->len, frame->r_saddr); free(frame); } @@ -458,7 +423,7 @@ static void * ipcp_udp_mgmt_handler(void * o) return (void *) 0; } -static void * ipcp_udp_packet_reader(void * o) +static void * udp_ipcp_packet_reader(void * o) { uint8_t buf[IPCP_UDP_MAX_PACKET_SIZE]; uint8_t * data; @@ -468,13 +433,17 @@ static void * ipcp_udp_packet_reader(void * o) (void) o; + ipcp_lock_to_core(); + data = buf + sizeof(uint32_t); eid_p = (uint32_t *) buf; while (true) { - struct mgmt_frame * frame; - struct sockaddr_in r_saddr; - socklen_t len; + struct mgmt_frame * frame; + struct sockaddr_in r_saddr; + socklen_t len; + struct shm_du_buff * sdb; + uint8_t * head; len = sizeof(r_saddr); @@ -515,18 +484,31 @@ static void * ipcp_udp_packet_reader(void * o) continue; } - flow_write(eid, data, n - sizeof(eid)); + n-= sizeof(eid); + + if (ipcp_sdb_reserve(&sdb, n)) + continue; + + head = shm_du_buff_head(sdb); + memcpy(head, data, n); + if (np1_flow_write(eid, sdb) < 0) + ipcp_sdb_release(sdb); } - return 0; + return (void *) 0; } -static void cleanup_writer(void * o) +static void cleanup_fqueue(void * fq) { - fqueue_destroy((fqueue_t *) o); + fqueue_destroy((fqueue_t *) fq); } -static void * ipcp_udp_packet_writer(void * o) +static void cleanup_sdb(void * sdb) +{ + ipcp_sdb_release((struct shm_du_buff *) sdb); +} + +static void * udp_ipcp_packet_writer(void * o) { fqueue_t * fq; @@ -538,11 +520,12 @@ static void * ipcp_udp_packet_writer(void * o) ipcp_lock_to_core(); - pthread_cleanup_push(cleanup_writer, fq); + pthread_cleanup_push(cleanup_fqueue, fq); while (true) { - int fd; - int eid; + struct sockaddr_in saddr; + int eid; + int fd; fevent(udp_data.np1_flows, fq, NULL); while ((fd = fqueue_next(fq)) >= 0) { struct shm_du_buff * sdb; @@ -552,12 +535,12 @@ static void * ipcp_udp_packet_writer(void * o) if (fqueue_type(fq) != FLOW_PKT) continue; - if (ipcp_flow_read(fd, &sdb)) { + if (np1_flow_read(fd, &sdb)) { log_dbg("Bad read from fd %d.", fd); continue; } - len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb); + len = shm_du_buff_len(sdb); if (len > IPCP_UDP_MAX_PACKET_SIZE) { log_dbg("Packet length exceeds MTU."); ipcp_sdb_release(sdb); @@ -574,16 +557,18 @@ static void * ipcp_udp_packet_writer(void * o) pthread_rwlock_rdlock(&udp_data.flows_lock); eid = hton32(udp_data.fd_to_uf[fd].d_eid); - fd = udp_data.fd_to_uf[fd].skfd; + saddr = udp_data.fd_to_uf[fd].r_saddr; pthread_rwlock_unlock(&udp_data.flows_lock); memcpy(buf, &eid, sizeof(eid)); - pthread_cleanup_push((void (*)(void *)) - ipcp_sdb_release, (void *) sdb); + pthread_cleanup_push(cleanup_sdb, sdb); - if (write(fd, buf, len + OUR_HEADER_LEN) < 0) + if (sendto(udp_data.s_fd, buf, len + OUR_HEADER_LEN, + SENDTO_FLAGS, + (const struct sockaddr *) &saddr, + sizeof(saddr)) < 0) log_err("Failed to send packet."); pthread_cleanup_pop(true); @@ -595,30 +580,36 @@ static void * ipcp_udp_packet_writer(void * o) return (void *) 1; } -static int ipcp_udp_bootstrap(const struct ipcp_config * conf) +static const char * inet4_ntop(const void * addr, + char * buf) +{ + return inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN); +} + +static int udp_ipcp_bootstrap(const struct ipcp_config * conf) { char ipstr[INET_ADDRSTRLEN]; char dnsstr[INET_ADDRSTRLEN]; - char portstr[128]; /* port is max 64535 = 5 chars */ int i = 1; assert(conf); assert(conf->type == THIS_TYPE); - if (inet_ntop(AF_INET, &conf->ip_addr, ipstr, INET_ADDRSTRLEN) - == NULL) { - log_err("Failed to convert IP address"); + ipcpi.dir_hash_algo = HASH_MD5; + strcpy(ipcpi.layer_name, conf->layer_info.name); + + if (inet4_ntop(&conf->udp.ip_addr, ipstr) == NULL) { + log_err("Failed to convert IP address."); return -1; } - if (conf->dns_addr != 0) { - if (inet_ntop(AF_INET, &conf->dns_addr, dnsstr, INET_ADDRSTRLEN) - == NULL) { - log_err("Failed to convert DNS address"); + if (conf->udp.dns_addr != 0) { + if (inet4_ntop(&conf->udp.dns_addr, dnsstr) == NULL) { + log_err("Failed to convert DNS address."); return -1; } #ifndef HAVE_DDNS - log_warn("DNS disabled at compile time, address ignored"); + log_warn("DNS disabled at compile time, address ignored."); #endif } else { strcpy(dnsstr, "not set"); @@ -631,54 +622,48 @@ static int ipcp_udp_bootstrap(const struct ipcp_config * conf) goto fail_socket; } - if (setsockopt(udp_data.s_fd, SOL_SOCKET, SO_REUSEADDR, - &i, sizeof(i)) < 0) - log_warn("Failed to set SO_REUSEADDR."); - memset((char *) &udp_data.s_saddr, 0, sizeof(udp_data.s_saddr)); udp_data.s_saddr.sin_family = AF_INET; - udp_data.s_saddr.sin_addr.s_addr = conf->ip_addr; - udp_data.s_saddr.sin_port = htons(conf->srv_port); + udp_data.s_saddr.sin_addr.s_addr = conf->udp.ip_addr; + udp_data.s_saddr.sin_port = htons(conf->udp.port); - if (bind(udp_data.s_fd, SERV_SADDR, SERV_SADDR_SIZE) < 0) { - log_err("Couldn't bind to %s.", ipstr); + if (bind(udp_data.s_fd, SADDR, SADDR_SIZE) < 0) { + log_err("Couldn't bind to %s:%d. %s.", + ipstr, conf->udp.port, strerror(errno)); goto fail_bind; } - udp_data.dns_addr = conf->dns_addr; - udp_data.clt_port = htons(conf->clt_port); - - ipcp_set_state(IPCP_OPERATIONAL); + udp_data.dns_addr = conf->udp.dns_addr; if (pthread_create(&udp_data.mgmt_handler, NULL, - ipcp_udp_mgmt_handler, NULL)) { - ipcp_set_state(IPCP_INIT); + udp_ipcp_mgmt_handler, NULL)) { + log_err("Failed to create management thread."); goto fail_bind; } for (i = 0; i < IPCP_UDP_RD_THR; ++i) { if (pthread_create(&udp_data.packet_reader[i], NULL, - ipcp_udp_packet_reader, NULL)) { - ipcp_set_state(IPCP_INIT); + udp_ipcp_packet_reader, NULL)) { + log_err("Failed to create reader thread."); goto fail_packet_reader; } } for (i = 0; i < IPCP_UDP_WR_THR; ++i) { if (pthread_create(&udp_data.packet_writer[i], NULL, - ipcp_udp_packet_writer, NULL)) { - ipcp_set_state(IPCP_INIT); + udp_ipcp_packet_writer, NULL)) { + log_err("Failed to create writer thread."); goto fail_packet_writer; } } - sprintf(portstr, "%d", conf->clt_port); - log_dbg("Bootstrapped IPCP over UDP with pid %d.", getpid()); log_dbg("Bound to IP address %s.", ipstr); - log_dbg("Client port is %s.", conf->clt_port == 0 ? "random" : portstr); - log_dbg("Server port is %u.", conf->srv_port); - log_dbg("DNS server address is %s.", dnsstr); + log_dbg("Using port %u.", conf->udp.port); + if (conf->udp.dns_addr != 0) + log_dbg("DNS server address is %s.", dnsstr); + else + log_dbg("DNS server not in use."); return 0; @@ -706,20 +691,22 @@ static int ipcp_udp_bootstrap(const struct ipcp_config * conf) /* NOTE: Disgusted with this crap */ static int ddns_send(char * cmd) { - pid_t pid = -1; + pid_t pid; int wstatus; int pipe_fd[2]; char * argv[] = {NSUPDATE_EXEC, 0}; char * envp[] = {0}; if (pipe(pipe_fd)) { - log_err("Failed to create pipe."); + log_err("Failed to create pipe: %s.", strerror(errno)); return -1; } pid = fork(); if (pid == -1) { - log_err("Failed to fork."); + log_err("Failed to fork: %s.", strerror(errno)); + close(pipe_fd[0]); + close(pipe_fd[1]); return -1; } @@ -727,12 +714,15 @@ static int ddns_send(char * cmd) close(pipe_fd[1]); dup2(pipe_fd[0], 0); execve(argv[0], &argv[0], envp); + log_err("Failed to execute: %s", strerror(errno)); + exit(1); } close(pipe_fd[0]); if (write(pipe_fd[1], cmd, strlen(cmd)) == -1) { - log_err("Failed to communicate with nsupdate."); + log_err("Failed to communicate with nsupdate: %s.", + strerror(errno)); close(pipe_fd[1]); return -1; } @@ -762,18 +752,20 @@ static uint32_t ddns_resolve(char * name, char * addr_str = "Address:"; uint32_t ip_addr = 0; - if (inet_ntop(AF_INET, &dns_addr, dnsstr, INET_ADDRSTRLEN) == NULL) + if (inet4_ntop(&dns_addr, dnsstr) == NULL) return 0; if (pipe(pipe_fd)) { - log_err("Failed to create pipe."); + log_err("Failed to create pipe: %s.", strerror(errno)); return 0; } pid = fork(); if (pid == -1) { - log_err("Failed to fork."); - return 0; + log_err("Failed to fork: %s.", strerror(errno)); + close(pipe_fd[0]); + close(pipe_fd[1]); + return -1; } if (pid == 0) { @@ -783,11 +775,13 @@ static uint32_t ddns_resolve(char * name, close(pipe_fd[0]); dup2(pipe_fd[1], 1); execve(argv[0], &argv[0], envp); + log_err("Failed to execute: %s", strerror(errno)); + exit(1); } close(pipe_fd[1]); - count = read(pipe_fd[0], buf, IPCP_UDP_BUF_SIZE); + count = read(pipe_fd[0], buf, IPCP_UDP_BUF_SIZE - 1); if (count <= 0) { log_err("Failed to communicate with nslookup."); close(pipe_fd[0]); @@ -798,7 +792,7 @@ static uint32_t ddns_resolve(char * name, waitpid(pid, &wstatus, 0); if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0 && - count != IPCP_UDP_BUF_SIZE) + count != IPCP_UDP_BUF_SIZE - 1) log_dbg("Succesfully communicated with nslookup."); else log_err("Failed to resolve DNS address."); @@ -824,7 +818,7 @@ static uint32_t ddns_resolve(char * name, } #endif -static int ipcp_udp_reg(const uint8_t * hash) +static int udp_ipcp_reg(const uint8_t * hash) { #ifdef HAVE_DDNS char ipstr[INET_ADDRSTRLEN]; @@ -836,16 +830,18 @@ static int ipcp_udp_reg(const uint8_t * hash) char * hashstr; hashstr = malloc(ipcp_dir_hash_strlen() + 1); - if (hashstr == NULL) + if (hashstr == NULL) { + log_err("Failed to malloc hashstr."); return -1; + } assert(hash); ipcp_hash_str(hashstr, hash); if (shim_data_reg_add_entry(udp_data.shim_data, hash)) { - log_err("Failed to add " HASH_FMT " to local registry.", - HASH_VAL(hash)); + log_err("Failed to add " HASH_FMT32 " to local registry.", + HASH_VAL32(hash)); free(hashstr); return -1; } @@ -858,14 +854,14 @@ static int ipcp_udp_reg(const uint8_t * hash) if (dns_addr != 0) { ip_addr = udp_data.s_saddr.sin_addr.s_addr; - if (inet_ntop(AF_INET, &ip_addr, - ipstr, INET_ADDRSTRLEN) == NULL) { + if (inet4_ntop(&ip_addr, ipstr) == NULL) { + log_err("Failed to convert IP address to string."); free(hashstr); return -1; } - if (inet_ntop(AF_INET, &dns_addr, - dnsstr, INET_ADDRSTRLEN) == NULL) { + if (inet4_ntop(&dns_addr, dnsstr) == NULL) { + log_err("Failed to convert DNS address to string."); free(hashstr); return -1; } @@ -874,20 +870,19 @@ static int ipcp_udp_reg(const uint8_t * hash) dnsstr, hashstr, DNS_TTL, ipstr); if (ddns_send(cmd)) { + log_err("Failed to send DDNS message."); shim_data_reg_del_entry(udp_data.shim_data, hash); free(hashstr); return -1; } } #endif - log_dbg("Registered " HASH_FMT ".", HASH_VAL(hash)); - free(hashstr); return 0; } -static int ipcp_udp_unreg(const uint8_t * hash) +static int udp_ipcp_unreg(const uint8_t * hash) { #ifdef HAVE_DDNS char dnsstr[INET_ADDRSTRLEN]; @@ -900,8 +895,10 @@ static int ipcp_udp_unreg(const uint8_t * hash) assert(hash); hashstr = malloc(ipcp_dir_hash_strlen() + 1); - if (hashstr == NULL) + if (hashstr == NULL) { + log_err("Failed to malloc hashstr."); return -1; + } ipcp_hash_str(hashstr, hash); @@ -911,8 +908,8 @@ static int ipcp_udp_unreg(const uint8_t * hash) dns_addr = udp_data.dns_addr; if (dns_addr != 0) { - if (inet_ntop(AF_INET, &dns_addr, dnsstr, INET_ADDRSTRLEN) - == NULL) { + if (inet4_ntop(&dns_addr, dnsstr) == NULL) { + log_err("Failed to convert DNS address to string."); free(hashstr); return -1; } @@ -925,14 +922,12 @@ static int ipcp_udp_unreg(const uint8_t * hash) shim_data_reg_del_entry(udp_data.shim_data, hash); - log_dbg("Unregistered " HASH_FMT ".", HASH_VAL(hash)); - free(hashstr); return 0; } -static int ipcp_udp_query(const uint8_t * hash) +static int udp_ipcp_query(const uint8_t * hash) { uint32_t ip_addr = 0; char * hashstr; @@ -943,8 +938,10 @@ static int ipcp_udp_query(const uint8_t * hash) assert(hash); hashstr = malloc(ipcp_dir_hash_strlen() + 1); - if (hashstr == NULL) + if (hashstr == NULL) { + log_err("Failed to malloc hashstr."); return -ENOMEM; + } ipcp_hash_str(hashstr, hash); @@ -959,7 +956,7 @@ static int ipcp_udp_query(const uint8_t * hash) if (dns_addr != 0) { ip_addr = ddns_resolve(hashstr, dns_addr); if (ip_addr == 0) { - log_dbg("Could not resolve %s.", hashstr); + log_err("Could not resolve %s.", hashstr); free(hashstr); return -1; } @@ -967,7 +964,7 @@ static int ipcp_udp_query(const uint8_t * hash) #endif h = gethostbyname(hashstr); if (h == NULL) { - log_dbg("Could not resolve %s.", hashstr); + log_err("Could not resolve %s.", hashstr); free(hashstr); return -1; } @@ -988,190 +985,116 @@ static int ipcp_udp_query(const uint8_t * hash) return 0; } -static int ipcp_udp_flow_alloc(int fd, - const uint8_t * dst, - qosspec_t qs, - const void * data, - size_t len) +static int udp_ipcp_flow_alloc(int fd, + const uint8_t * dst, + qosspec_t qs, + const buffer_t * data) { struct sockaddr_in r_saddr; /* Server address */ - struct sockaddr_in c_saddr; /* Client address */ - socklen_t c_saddr_len; - int skfd; uint32_t ip_addr = 0; - char ip_str[INET_ADDRSTRLEN]; - - c_saddr_len = sizeof(c_saddr); - - log_dbg("Allocating flow to " HASH_FMT ".", HASH_VAL(dst)); + char ipstr[INET_ADDRSTRLEN]; (void) qs; assert(dst); - skfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (skfd < 0) { - log_err("Could not create socket."); - return -1; - } - - /* This socket is for the flow. */ - memset((char *) &c_saddr, 0, sizeof(c_saddr)); - c_saddr.sin_family = AF_INET; - c_saddr.sin_addr.s_addr = LOCAL_IP; - c_saddr.sin_port = udp_data.clt_port; - - if (bind(skfd, (struct sockaddr *) &c_saddr, sizeof(c_saddr)) < 0) { - log_dbg("Could not bind socket to client address."); - close(skfd); + if (!shim_data_dir_has(udp_data.shim_data, dst)) { + log_err("Could not resolve destination."); return -1; } - if (getsockname(skfd, (struct sockaddr *) &c_saddr, &c_saddr_len) < 0) { - log_err("Could not get address from fd."); - close(skfd); - return -1; - } + ip_addr = (uint32_t) shim_data_dir_get_addr(udp_data.shim_data, dst); - if (!shim_data_dir_has(udp_data.shim_data, dst)) { - log_dbg("Could not resolve destination."); - close(skfd); + if (inet4_ntop(&ip_addr, ipstr) == NULL) { + log_err("Could not convert IP address."); return -1; } - ip_addr = (uint32_t) shim_data_dir_get_addr(udp_data.shim_data, dst); - - inet_ntop(AF_INET, &ip_addr, ip_str, INET_ADDRSTRLEN); - log_dbg("Destination UDP ipcp resolved at %s.", ip_str); + log_dbg("Destination " HASH_FMT32 " resolved at IP %s.", + HASH_VAL32(dst), ipstr); - /* Connect to server and store the remote IP address in the skfd. */ memset((char *) &r_saddr, 0, sizeof(r_saddr)); r_saddr.sin_family = AF_INET; r_saddr.sin_addr.s_addr = ip_addr; r_saddr.sin_port = udp_data.s_saddr.sin_port; - if (connect(skfd, (struct sockaddr *) &r_saddr, sizeof(r_saddr)) < 0) { - log_dbg("Could not connect socket to remote."); - close(skfd); - return -1; - } - - if (ipcp_udp_port_alloc(skfd, fd, dst, qs, data, len) < 0) { + if (udp_ipcp_port_alloc(&r_saddr, fd, dst, qs, data) < 0) { log_err("Could not allocate port."); - close(skfd); return -1; } pthread_rwlock_wrlock(&udp_data.flows_lock); - udp_data.fd_to_uf[fd].d_eid = -1; - udp_data.fd_to_uf[fd].skfd = skfd; - - fset_add(udp_data.np1_flows, fd); + udp_data.fd_to_uf[fd].d_eid = -1; + udp_data.fd_to_uf[fd].r_saddr = r_saddr; pthread_rwlock_unlock(&udp_data.flows_lock); - log_dbg("Flow pending on fd %d, UDP src port %d, dst port %d.", - fd, ntohs(c_saddr.sin_port), ntohs(r_saddr.sin_port)); + fset_add(udp_data.np1_flows, fd); return 0; } -static int ipcp_udp_flow_alloc_resp(int fd, - int resp, - const void * data, - size_t len) +static int udp_ipcp_flow_alloc_resp(int fd, + int resp, + const buffer_t * data) { - struct timespec ts = {0, FD_UPDATE_TIMEOUT * 1000}; - struct timespec abstime; - int skfd; - int d_eid; - - if (resp) - return 0; - - 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); - } + struct sockaddr_in saddr; + int d_eid; - if (ipcp_get_state() != IPCP_OPERATIONAL) { - pthread_mutex_unlock(&ipcpi.alloc_lock); + if (ipcp_wait_flow_resp(fd) < 0) { + log_err("Failed to wait for flow response."); return -1; } - ipcpi.alloc_id = -1; - pthread_cond_broadcast(&ipcpi.alloc_cond); - - pthread_mutex_unlock(&ipcpi.alloc_lock); - pthread_rwlock_rdlock(&udp_data.flows_lock); - skfd = udp_data.fd_to_uf[fd].skfd; + saddr = udp_data.fd_to_uf[fd].r_saddr; d_eid = udp_data.fd_to_uf[fd].d_eid; - fset_add(udp_data.np1_flows, fd); - pthread_rwlock_unlock(&udp_data.flows_lock); - if (ipcp_udp_port_alloc_resp(skfd, d_eid, fd, resp, data, len) < 0) { - pthread_rwlock_rdlock(&udp_data.flows_lock); + if (udp_ipcp_port_alloc_resp(&saddr, d_eid, fd, resp, data) < 0) { fset_del(udp_data.np1_flows, fd); - pthread_rwlock_unlock(&udp_data.flows_lock); log_err("Failed to respond to flow request."); return -1; } - log_dbg("Accepted flow, fd %d on eid %d.", - fd, d_eid); + fset_add(udp_data.np1_flows, fd); return 0; } -static int ipcp_udp_flow_dealloc(int fd) +static int udp_ipcp_flow_dealloc(int fd) { - int skfd = -1; - ipcp_flow_fini(fd); - pthread_rwlock_wrlock(&udp_data.flows_lock); - fset_del(udp_data.np1_flows, fd); - skfd = udp_data.fd_to_uf[fd].skfd; + pthread_rwlock_wrlock(&udp_data.flows_lock); udp_data.fd_to_uf[fd].d_eid = -1; - udp_data.fd_to_uf[fd].skfd = -1; - - close(skfd); + memset(&udp_data.fd_to_uf[fd].r_saddr, 0, SADDR_SIZE); pthread_rwlock_unlock(&udp_data.flows_lock); - flow_dealloc(fd); - - log_dbg("Flow with fd %d deallocated.", fd); + ipcp_flow_dealloc(fd); return 0; } static struct ipcp_ops udp_ops = { - .ipcp_bootstrap = ipcp_udp_bootstrap, + .ipcp_bootstrap = udp_ipcp_bootstrap, .ipcp_enroll = NULL, .ipcp_connect = NULL, .ipcp_disconnect = NULL, - .ipcp_reg = ipcp_udp_reg, - .ipcp_unreg = ipcp_udp_unreg, - .ipcp_query = ipcp_udp_query, - .ipcp_flow_alloc = ipcp_udp_flow_alloc, + .ipcp_reg = udp_ipcp_reg, + .ipcp_unreg = udp_ipcp_unreg, + .ipcp_query = udp_ipcp_query, + .ipcp_flow_alloc = udp_ipcp_flow_alloc, .ipcp_flow_join = NULL, - .ipcp_flow_alloc_resp = ipcp_udp_flow_alloc_resp, - .ipcp_flow_dealloc = ipcp_udp_flow_dealloc + .ipcp_flow_alloc_resp = udp_ipcp_flow_alloc_resp, + .ipcp_flow_dealloc = udp_ipcp_flow_dealloc }; int main(int argc, @@ -1179,53 +1102,51 @@ int main(int argc, { int i; - if (ipcp_init(argc, argv, &udp_ops) < 0) - goto fail_init; if (udp_data_init() < 0) { log_err("Failed to init udp data."); goto fail_data_init; } - if (ipcp_boot() < 0) { - log_err("Failed to boot IPCP."); - goto fail_boot; + if (ipcp_init(argc, argv, &udp_ops, THIS_TYPE) < 0) { + log_err("Failed to initialize IPCP."); + goto fail_init; } - if (ipcp_create_r(0)) { - log_err("Failed to notify IRMd we are initialized."); - goto fail_create_r; + if (ipcp_start() < 0) { + log_err("Failed to start IPCP."); + goto fail_start; } - ipcp_shutdown(); + ipcp_sigwait(); if (ipcp_get_state() == IPCP_SHUTDOWN) { - for (i = 0; i < IPCP_UDP_RD_THR; ++i) - pthread_cancel(udp_data.packet_reader[i]); for (i = 0; i < IPCP_UDP_WR_THR; ++i) pthread_cancel(udp_data.packet_writer[i]); + for (i = 0; i < IPCP_UDP_RD_THR; ++i) + pthread_cancel(udp_data.packet_reader[i]); pthread_cancel(udp_data.mgmt_handler); - for (i = 0; i < IPCP_UDP_RD_THR; ++i) - pthread_join(udp_data.packet_reader[i], NULL); for (i = 0; i < IPCP_UDP_WR_THR; ++i) pthread_join(udp_data.packet_writer[i], NULL); + for (i = 0; i < IPCP_UDP_RD_THR; ++i) + pthread_join(udp_data.packet_reader[i], NULL); pthread_join(udp_data.mgmt_handler, NULL); + close(udp_data.s_fd); } - udp_data_fini(); + ipcp_stop(); ipcp_fini(); - exit(EXIT_SUCCESS); - fail_create_r: - ipcp_set_state(IPCP_NULL); - ipcp_shutdown(); - fail_boot: udp_data_fini(); - fail_data_init: + + exit(EXIT_SUCCESS); + + fail_start: ipcp_fini(); fail_init: - ipcp_create_r(-1); + udp_data_fini(); + fail_data_init: exit(EXIT_FAILURE); } diff --git a/src/ipcpd/unicast/CMakeLists.txt b/src/ipcpd/unicast/CMakeLists.txt index c0c55519..ca742871 100644 --- a/src/ipcpd/unicast/CMakeLists.txt +++ b/src/ipcpd/unicast/CMakeLists.txt @@ -13,8 +13,10 @@ include_directories(${CMAKE_SOURCE_DIR}/include) include_directories(${CMAKE_BINARY_DIR}/include) set(IPCP_UNICAST_TARGET ipcpd-unicast CACHE INTERNAL "") +set(IPCP_UNICAST_MPL 60 CACHE STRING + "Default maximum packet lifetime for the unicast IPCP, in seconds") -protobuf_generate_c(KAD_PROTO_SRCS KAD_PROTO_HDRS kademlia.proto) +protobuf_generate_c(DHT_PROTO_SRCS DHT_PROTO_HDRS dir/dht.proto) math(EXPR PFT_EXPR "1 << 12") set(PFT_SIZE ${PFT_EXPR} CACHE STRING @@ -29,32 +31,33 @@ if (HAVE_FUSE) endif () endif () - set(SOURCE_FILES # Add source files here - addr_auth.c + addr-auth.c + ca.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/pft.c - pol/flat.c - pol/link_state.c - pol/graph.c - pol/simple_pff.c - pol/alternate_pff.c - pol/multipath_pff.c + addr-auth/flat.c + ca/mb-ecn.c + ca/nop.c + dir/dht.c + pff/simple.c + pff/alternate.c + pff/multipath.c + pff/pft.c + routing/link-state.c + routing/graph.c ) -add_executable(ipcpd-unicast ${SOURCE_FILES} ${IPCP_SOURCES} - ${KAD_PROTO_SRCS} ${LAYER_CONFIG_PROTO_SRCS}) +add_executable(ipcpd-unicast ${SOURCE_FILES} ${IPCP_SOURCES} ${COMMON_SOURCES} + ${DHT_PROTO_SRCS} ${LAYER_CONFIG_PROTO_SRCS}) target_link_libraries(ipcpd-unicast LINK_PUBLIC ouroboros-dev) include(AddCompileFlags) @@ -64,8 +67,9 @@ endif () install(TARGETS ipcpd-unicast RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}) -add_subdirectory(pol/tests) +add_subdirectory(pff/tests) +add_subdirectory(routing/tests) if (NOT GNU) - add_subdirectory(tests) + add_subdirectory(dir/tests) endif () diff --git a/src/ipcpd/unicast/addr_auth.c b/src/ipcpd/unicast/addr-auth.c index e82ea254..908a4aa1 100644 --- a/src/ipcpd/unicast/addr_auth.c +++ b/src/ipcpd/unicast/addr-auth.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Address authority * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -24,13 +24,12 @@ #include <ouroboros/logs.h> -#include "addr_auth.h" -#include "pol-addr-auth-ops.h" -#include "pol/flat.h" +#include "addr-auth.h" +#include "addr-auth/pol.h" #include <stdlib.h> -struct pol_addr_auth_ops * ops; +struct addr_auth_ops * ops; int addr_auth_init(enum pol_addr_auth type, const void * info) diff --git a/src/ipcpd/unicast/addr_auth.h b/src/ipcpd/unicast/addr-auth.h index 6bedf420..e119dff3 100644 --- a/src/ipcpd/unicast/addr_auth.h +++ b/src/ipcpd/unicast/addr-auth.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Address authority * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 diff --git a/src/ipcpd/unicast/pol/flat.c b/src/ipcpd/unicast/addr-auth/flat.c index 6e5c96ab..c4562935 100644 --- a/src/ipcpd/unicast/pol/flat.c +++ b/src/ipcpd/unicast/addr-auth/flat.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Policy for flat addresses in a distributed way * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -29,19 +29,11 @@ #define OUROBOROS_PREFIX "flat-addr-auth" #include <ouroboros/logs.h> -#include <ouroboros/errno.h> -#include <ouroboros/time_utils.h> -#include <ouroboros/utils.h> +#include <ouroboros/random.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 { @@ -50,7 +42,7 @@ struct { #define INVALID_ADDRESS 0 -struct pol_addr_auth_ops flat_ops = { +struct addr_auth_ops flat_ops = { .init = flat_init, .fini = flat_fini, .address = flat_address @@ -75,13 +67,13 @@ int flat_fini(void) 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; + uint32_t addr = INVALID_ADDRESS; +#if defined (CONFIG_OUROBOROS_DEBUG) && defined (IPCP_DEBUG_LOCAL) + addr = getpid(); +#else + while (addr == INVALID_ADDRESS) + random_buffer(&addr,sizeof(addr)); +#endif return addr; } diff --git a/src/ipcpd/unicast/pol/flat.h b/src/ipcpd/unicast/addr-auth/flat.h index 54460bb3..d4b672c7 100644 --- a/src/ipcpd/unicast/pol/flat.h +++ b/src/ipcpd/unicast/addr-auth/flat.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Policy for flat addresses in a distributed way * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -23,7 +23,7 @@ #ifndef OUROBOROS_IPCPD_UNICAST_FLAT_H #define OUROBOROS_IPCPD_UNICAST_FLAT_H -#include "pol-addr-auth-ops.h" +#include "ops.h" int flat_init(const void * info); @@ -31,6 +31,6 @@ int flat_fini(void); uint64_t flat_address(void); -struct pol_addr_auth_ops flat_ops; +extern struct addr_auth_ops flat_ops; #endif /* OUROBOROS_IPCPD_UNICAST_FLAT_H */ diff --git a/src/ipcpd/unicast/pol-addr-auth-ops.h b/src/ipcpd/unicast/addr-auth/ops.h index 1096eecb..06b24cec 100644 --- a/src/ipcpd/unicast/pol-addr-auth-ops.h +++ b/src/ipcpd/unicast/addr-auth/ops.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Address authority policy ops * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -20,10 +20,10 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#ifndef OUROBOROS_IPCPD_UNICAST_POL_ADDR_AUTH_OPS_H -#define OUROBOROS_IPCPD_UNICAST_POL_ADDR_AUTH_OPS_H +#ifndef OUROBOROS_IPCPD_UNICAST_ADDR_AUTH_OPS_H +#define OUROBOROS_IPCPD_UNICAST_ADDR_AUTH_OPS_H -struct pol_addr_auth_ops { +struct addr_auth_ops { int (* init)(const void * info); int (* fini)(void); @@ -31,4 +31,4 @@ struct pol_addr_auth_ops { uint64_t (* address)(void); }; -#endif /* OUROBOROS_IPCPD_UNICAST_POL_ADDR_AUTH_OPS_H */ +#endif /* OUROBOROS_IPCPD_UNICAST_ADDR_AUTH_OPS_H */ diff --git a/src/ipcpd/unicast/addr-auth/pol.h b/src/ipcpd/unicast/addr-auth/pol.h new file mode 100644 index 00000000..844308c6 --- /dev/null +++ b/src/ipcpd/unicast/addr-auth/pol.h @@ -0,0 +1,23 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Address Authority policies + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * 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/. + */ + +#include "flat.h" diff --git a/src/ipcpd/unicast/ca.c b/src/ipcpd/unicast/ca.c new file mode 100644 index 00000000..287eaf41 --- /dev/null +++ b/src/ipcpd/unicast/ca.c @@ -0,0 +1,109 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Congestion Avoidance + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * 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 "ca" + +#include <ouroboros/logs.h> + +#include "ca.h" +#include "ca/pol.h" + +struct { + struct ca_ops * ops; +} ca; + +int ca_init(enum pol_cong_avoid pol) +{ + switch(pol) { + case CA_NONE: + log_dbg("Disabling congestion control."); + ca.ops = &nop_ca_ops; + break; + case CA_MB_ECN: + log_dbg("Using multi-bit ECN."); + ca.ops = &mb_ecn_ca_ops; + break; + default: + return -1; + } + + return 0; +} + + +void ca_fini(void) +{ + ca.ops = NULL; +} + +void * ca_ctx_create(void) +{ + return ca.ops->ctx_create(); +} + +void ca_ctx_destroy(void * ctx) +{ + return ca.ops->ctx_destroy(ctx); +} + +ca_wnd_t ca_ctx_update_snd(void * ctx, + size_t len) +{ + return ca.ops->ctx_update_snd(ctx, len); +} + +bool ca_ctx_update_rcv(void * ctx, + size_t len, + uint8_t ecn, + uint16_t * ece) +{ + return ca.ops->ctx_update_rcv(ctx, len, ecn, ece); +} + +void ca_ctx_update_ece(void * ctx, + uint16_t ece) +{ + return ca.ops->ctx_update_ece(ctx, ece); +} + +void ca_wnd_wait(ca_wnd_t wnd) +{ + return ca.ops->wnd_wait(wnd); +} + +int ca_calc_ecn(int fd, + uint8_t * ecn, + qoscube_t qc, + size_t len) +{ + return ca.ops->calc_ecn(fd, ecn, qc, len); +} + +ssize_t ca_print_stats(void * ctx, + char * buf, + size_t len) +{ + if (ca.ops->print_stats == NULL) + return 0; + + return ca.ops->print_stats(ctx, buf, len); +} diff --git a/src/ipcpd/unicast/ca.h b/src/ipcpd/unicast/ca.h new file mode 100644 index 00000000..ea803e17 --- /dev/null +++ b/src/ipcpd/unicast/ca.h @@ -0,0 +1,68 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Congestion avoidance + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * 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_UNICAST_CA_H +#define OUROBOROS_IPCPD_UNICAST_CA_H + +#include <ouroboros/ipcp.h> +#include <ouroboros/qoscube.h> + +#include <stdbool.h> +#include <sys/types.h> + +typedef union { + time_t wait; +} ca_wnd_t; + +int ca_init(enum pol_cong_avoid ca); + +void ca_fini(void); + + +/* OPS */ +void * ca_ctx_create(void); + +void ca_ctx_destroy(void * ctx); + +ca_wnd_t ca_ctx_update_snd(void * ctx, + size_t len); + +bool ca_ctx_update_rcv(void * ctx, + size_t len, + uint8_t ecn, + uint16_t * ece); + +void ca_ctx_update_ece(void * ctx, + uint16_t ece); + +void ca_wnd_wait(ca_wnd_t wnd); + +int ca_calc_ecn(int fd, + uint8_t * ecn, + qoscube_t qc, + size_t len); + +ssize_t ca_print_stats(void * ctx, + char * buf, + size_t len); + +#endif /* OUROBOROS_IPCPD_UNICAST_CA_H */ diff --git a/src/ipcpd/unicast/ca/mb-ecn.c b/src/ipcpd/unicast/ca/mb-ecn.c new file mode 100644 index 00000000..d9a204b0 --- /dev/null +++ b/src/ipcpd/unicast/ca/mb-ecn.c @@ -0,0 +1,296 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Multi-bit ECN Congestion Avoidance + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * 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" + +#include <ouroboros/ipcp-dev.h> +#include <ouroboros/time.h> + +#include "mb-ecn.h" + +#include <inttypes.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +/* congestion avoidance constants */ +#define CA_SHFT 5 /* Average over 32 pkts */ +#define CA_WND (1 << CA_SHFT) /* 32 pkts receiver wnd */ +#define CA_UPD (1 << (CA_SHFT - 2)) /* Update snd every 8 pkt */ +#define CA_SLOT 24 /* Initial slot = 16 ms */ +#define CA_INC 1UL << 16 /* ~4MiB/s^2 additive inc */ +#define CA_IWL 1UL << 16 /* Initial limit ~4MiB/s */ +#define CA_MINPS 8 /* Mimimum pkts / slot */ +#define CA_MAXPS 64 /* Maximum pkts / slot */ +#define ECN_Q_SHFT 4 +#define ts_to_ns(ts) ((size_t) ts.tv_sec * BILLION + ts.tv_nsec) + +struct mb_ecn_ctx { + uint16_t rx_ece; /* Level of congestion (upstream) */ + size_t rx_ctr; /* Receiver side packet counter */ + + uint16_t tx_ece; /* Level of congestion (downstream) */ + size_t tx_ctr; /* Sender side packet counter */ + size_t tx_wbc; /* Window byte count */ + size_t tx_wpc; /* Window packet count */ + size_t tx_wbl; /* Window byte limit */ + bool tx_cav; /* Congestion avoidance */ + size_t tx_mul; /* Slot size multiplier */ + size_t tx_inc; /* Additive increase */ + size_t tx_slot; +}; + +struct ca_ops mb_ecn_ca_ops = { + .ctx_create = mb_ecn_ctx_create, + .ctx_destroy = mb_ecn_ctx_destroy, + .ctx_update_snd = mb_ecn_ctx_update_snd, + .ctx_update_rcv = mb_ecn_ctx_update_rcv, + .ctx_update_ece = mb_ecn_ctx_update_ece, + .wnd_wait = mb_ecn_wnd_wait, + .calc_ecn = mb_ecn_calc_ecn, + .print_stats = mb_ecn_print_stats +}; + +void * mb_ecn_ctx_create(void) +{ + struct timespec now; + struct mb_ecn_ctx * ctx; + + ctx = malloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + clock_gettime(PTHREAD_COND_CLOCK, &now); + + memset(ctx, 0, sizeof(*ctx)); + + ctx->tx_mul = CA_SLOT; + ctx->tx_wbl = CA_IWL; + ctx->tx_inc = CA_INC; + ctx->tx_slot = ts_to_ns(now) >> ctx->tx_mul; + + return (void *) ctx; +} + +void mb_ecn_ctx_destroy(void * ctx) +{ + free(ctx); +} + +#define _slot_after(new, old) ((int64_t) (old - new) < 0) + +ca_wnd_t mb_ecn_ctx_update_snd(void * _ctx, + size_t len) +{ + struct timespec now; + size_t slot; + ca_wnd_t wnd; + struct mb_ecn_ctx * ctx = _ctx; + + clock_gettime(PTHREAD_COND_CLOCK, &now); + + slot = ts_to_ns(now) >> ctx->tx_mul; + + ctx->tx_ctr++; + ctx->tx_wpc++; + ctx->tx_wbc += len; + + if (ctx->tx_ctr > CA_WND) + ctx->tx_ece = 0; + + if (_slot_after(slot, ctx->tx_slot)) { + bool carry = false; /* may carry over if window increases */ + + ctx->tx_slot = slot; + + if (!ctx->tx_cav) { /* Slow start */ + if (ctx->tx_wbc > ctx->tx_wbl) + ctx->tx_wbl <<= 1; + } else { + if (ctx->tx_ece) /* Mult. Decrease */ + ctx->tx_wbl -= (ctx->tx_wbl * ctx->tx_ece) + >> (CA_SHFT + 8); + else /* Add. Increase */ + ctx->tx_wbl = ctx->tx_wbc + ctx->tx_inc; + } + + /* Window scaling */ + if (ctx->tx_wpc < CA_MINPS) { + size_t fact = 0; /* factor to scale the window up */ + size_t pkts = ctx->tx_wpc; + while (pkts < CA_MINPS) { + pkts <<= 1; + fact++; + } + ctx->tx_mul += fact; + ctx->tx_slot >>= fact; + if ((ctx->tx_slot & ((1 << fact) - 1)) == 0) { + carry = true; + ctx->tx_slot += 1; + } + ctx->tx_wbl <<= fact; + ctx->tx_inc <<= fact; + } else if (ctx->tx_wpc > CA_MAXPS) { + size_t fact = 0; /* factor to scale the window down */ + size_t pkts = ctx->tx_wpc; + while (pkts > CA_MAXPS) { + pkts >>= 1; + fact++; + } + ctx->tx_mul -= fact; + ctx->tx_slot <<= fact; + ctx->tx_wbl >>= fact; + ctx->tx_inc >>= fact; + } else { + ctx->tx_slot = slot; + } + + if (!carry) { + ctx->tx_wbc = 0; + ctx->tx_wpc = 0; + } + } + + if (ctx->tx_wbc > ctx->tx_wbl) + wnd.wait = ((ctx->tx_slot + 1) << ctx->tx_mul) - ts_to_ns(now); + else + wnd.wait = 0; + + return wnd; +} + +void mb_ecn_wnd_wait(ca_wnd_t wnd) +{ + if (wnd.wait > 0) { + struct timespec s = TIMESPEC_INIT_S(0); + if (wnd.wait > BILLION) /* Don't care throttling < 1s */ + s.tv_sec = 1; + else + s.tv_nsec = wnd.wait; + + nanosleep(&s, NULL); + } +} + +bool mb_ecn_ctx_update_rcv(void * _ctx, + size_t len, + uint8_t ecn, + uint16_t * ece) +{ + struct mb_ecn_ctx* ctx = _ctx; + bool update; + + (void) len; + + if ((ctx->rx_ece | ecn) == 0) + return false; + + if (ecn == 0) { /* End of congestion */ + ctx->rx_ece >>= 2; + update = ctx->rx_ece == 0; + } else { + if (ctx->rx_ece == 0) { /* Start of congestion */ + ctx->rx_ece = ecn; + ctx->rx_ctr = 0; + update = true; + } else { /* Congestion update */ + ctx->rx_ece -= ctx->rx_ece >> CA_SHFT; + ctx->rx_ece += ecn; + update = (ctx->rx_ctr++ & (CA_UPD - 1)) == true; + } + } + + *ece = ctx->rx_ece; + + return update; +} + + +void mb_ecn_ctx_update_ece(void * _ctx, + uint16_t ece) +{ + struct mb_ecn_ctx* ctx = _ctx; + + ctx->tx_ece = ece; + ctx->tx_ctr = 0; + ctx->tx_cav = true; +} + +int mb_ecn_calc_ecn(int fd, + uint8_t * ecn, + qoscube_t qc, + size_t len) +{ + size_t q; + + (void) len; + (void) qc; + + q = ipcp_flow_queued(fd); + + *ecn |= (uint8_t) (q >> ECN_Q_SHFT); + + return 0; +} + +ssize_t mb_ecn_print_stats(void * _ctx, + char * buf, + size_t len) +{ + struct mb_ecn_ctx* ctx = _ctx; + char * regime; + + if (len < 1024) + return 0; + + if (!ctx->tx_cav) + regime = "Slow start"; + else if (ctx->tx_ece) + regime = "Multiplicative dec"; + else + regime = "Additive inc"; + + sprintf(buf, + "Congestion avoidance algorithm: %20s\n" + "Upstream congestion level: %20u\n" + "Upstream packet counter: %20zu\n" + "Downstream congestion level: %20u\n" + "Downstream packet counter: %20zu\n" + "Congestion window size (ns): %20" PRIu64 "\n" + "Packets in this window: %20zu\n" + "Bytes in this window: %20zu\n" + "Max bytes in this window: %20zu\n" + "Current congestion regime: %20s\n", + "Multi-bit ECN", + ctx->tx_ece, ctx->tx_ctr, + ctx->rx_ece, ctx->rx_ctr, (uint64_t) (1ULL << ctx->tx_mul), + ctx->tx_wpc, ctx->tx_wbc, ctx->tx_wbl, + regime); + + return strlen(buf); +} diff --git a/src/ipcpd/unicast/ca/mb-ecn.h b/src/ipcpd/unicast/ca/mb-ecn.h new file mode 100644 index 00000000..9a2c8b49 --- /dev/null +++ b/src/ipcpd/unicast/ca/mb-ecn.h @@ -0,0 +1,56 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Multi-bit ECN Congestion Avoidance + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * 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_UNICAST_CA_MB_ECN_H +#define OUROBOROS_IPCPD_UNICAST_CA_MB_ECN_H + +#include "ops.h" + +void * mb_ecn_ctx_create(void); + +void mb_ecn_ctx_destroy(void * ctx); + +ca_wnd_t mb_ecn_ctx_update_snd(void * ctx, + size_t len); + +bool mb_ecn_ctx_update_rcv(void * ctx, + size_t len, + uint8_t ecn, + uint16_t * ece); + +void mb_ecn_ctx_update_ece(void * ctx, + uint16_t ece); + +void mb_ecn_wnd_wait(ca_wnd_t wnd); + +int mb_ecn_calc_ecn(int fd, + uint8_t * ecn, + qoscube_t qc, + size_t len); + +ssize_t mb_ecn_print_stats(void * ctx, + char * buf, + size_t len); + +extern struct ca_ops mb_ecn_ca_ops; + +#endif /* OUROBOROS_IPCPD_UNICAST_CA_MB_ECN_H */ diff --git a/src/ipcpd/unicast/ca/nop.c b/src/ipcpd/unicast/ca/nop.c new file mode 100644 index 00000000..617fc15b --- /dev/null +++ b/src/ipcpd/unicast/ca/nop.c @@ -0,0 +1,98 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Dummy Congestion Avoidance + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * 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/. + */ + +#include "nop.h" + +#include <string.h> + +struct ca_ops nop_ca_ops = { + .ctx_create = nop_ctx_create, + .ctx_destroy = nop_ctx_destroy, + .ctx_update_snd = nop_ctx_update_snd, + .ctx_update_rcv = nop_ctx_update_rcv, + .ctx_update_ece = nop_ctx_update_ece, + .wnd_wait = nop_wnd_wait, + .calc_ecn = nop_calc_ecn, + .print_stats = NULL +}; + +void * nop_ctx_create(void) +{ + return (void *) 1; +} + +void nop_ctx_destroy(void * ctx) +{ + (void) ctx; +} + +ca_wnd_t nop_ctx_update_snd(void * ctx, + size_t len) +{ + ca_wnd_t wnd; + + (void) ctx; + (void) len; + + memset(&wnd, 0, sizeof(wnd)); + + return wnd; +} + +void nop_wnd_wait(ca_wnd_t wnd) +{ + (void) wnd; +} + +bool nop_ctx_update_rcv(void * ctx, + size_t len, + uint8_t ecn, + uint16_t * ece) +{ + (void) ctx; + (void) len; + (void) ecn; + (void) ece; + + return false; +} + +void nop_ctx_update_ece(void * ctx, + uint16_t ece) +{ + (void) ctx; + (void) ece; +} + + +int nop_calc_ecn(int fd, + uint8_t * ecn, + qoscube_t qc, + size_t len) +{ + (void) fd; + (void) len; + (void) ecn; + (void) qc; + + return 0; +} diff --git a/src/ipcpd/unicast/ca/nop.h b/src/ipcpd/unicast/ca/nop.h new file mode 100644 index 00000000..248b198d --- /dev/null +++ b/src/ipcpd/unicast/ca/nop.h @@ -0,0 +1,52 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Dummy Congestion Avoidance + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * 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_UNICAST_CA_NOP_H +#define OUROBOROS_IPCPD_UNICAST_CA_NOP_H + +#include "ops.h" + +void * nop_ctx_create(void); + +void nop_ctx_destroy(void * ctx); + +ca_wnd_t nop_ctx_update_snd(void * ctx, + size_t len); + +bool nop_ctx_update_rcv(void * ctx, + size_t len, + uint8_t ecn, + uint16_t * ece); + +void nop_ctx_update_ece(void * ctx, + uint16_t ece); + +void nop_wnd_wait(ca_wnd_t wnd); + +int nop_calc_ecn(int fd, + uint8_t * ecn, + qoscube_t qc, + size_t len); + +extern struct ca_ops nop_ca_ops; + +#endif /* OUROBOROS_IPCPD_UNICAST_CA_NOP_H */ diff --git a/src/ipcpd/unicast/ca/ops.h b/src/ipcpd/unicast/ca/ops.h new file mode 100644 index 00000000..3a7b7248 --- /dev/null +++ b/src/ipcpd/unicast/ca/ops.h @@ -0,0 +1,58 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Congestion avoidance policy ops + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * 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_UNICAST_CA_OPS_H +#define OUROBOROS_IPCPD_UNICAST_CA_OPS_H + +#include "ca.h" + +struct ca_ops { + void * (* ctx_create)(void); + + void (* ctx_destroy)(void * ctx); + + ca_wnd_t (* ctx_update_snd)(void * ctx, + size_t len); + + bool (* ctx_update_rcv)(void * ctx, + size_t len, + uint8_t ecn, + uint16_t * ece); + + void (* ctx_update_ece)(void * ctx, + uint16_t ece); + + void (* wnd_wait)(ca_wnd_t wnd); + + int (* calc_ecn)(int fd, + uint8_t * ecn, + qoscube_t qc, + size_t len); + + /* Optional, can be NULL */ + ssize_t (* print_stats)(void * ctx, + char * buf, + size_t len); + +}; + +#endif /* OUROBOROS_IPCPD_UNICAST_CA_OPS_H */ diff --git a/src/ipcpd/unicast/ca/pol.h b/src/ipcpd/unicast/ca/pol.h new file mode 100644 index 00000000..db0a1a11 --- /dev/null +++ b/src/ipcpd/unicast/ca/pol.h @@ -0,0 +1,24 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Congestion avoidance policies + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * 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/. + */ + +#include "mb-ecn.h" +#include "nop.h" diff --git a/src/ipcpd/unicast/connmgr.c b/src/ipcpd/unicast/connmgr.c index 3ebef7f9..11c5d5b6 100644 --- a/src/ipcpd/unicast/connmgr.c +++ b/src/ipcpd/unicast/connmgr.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Handles connections between components * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -20,506 +20,20 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ +#include "config.h" + #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; +#include <ouroboros/ipcp.h> - if (pthread_mutex_init(&comp->lock, NULL)) - return -1; +#define BUILD_IPCP_UNICAST - 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(); + #include "dir.h" #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; -} +#include "common/connmgr.c" diff --git a/src/ipcpd/unicast/dht.h b/src/ipcpd/unicast/dht.h deleted file mode 100644 index 39dfc07e..00000000 --- a/src/ipcpd/unicast/dht.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2020 - * - * Distributed Hash Table based on Kademlia - * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> - * - * 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_UNICAST_DHT_H -#define OUROBOROS_IPCPD_UNICAST_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_UNICAST_DHT_H */ diff --git a/src/ipcpd/unicast/dir.c b/src/ipcpd/unicast/dir.c index 43ee94f0..e0cb09fc 100644 --- a/src/ipcpd/unicast/dir.c +++ b/src/ipcpd/unicast/dir.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * - * Directory + * Directory Management * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -34,8 +34,7 @@ #include <ouroboros/utils.h> #include "dir.h" -#include "dht.h" -#include "ipcp.h" +#include "dir/pol.h" #include <stdlib.h> #include <string.h> @@ -43,59 +42,52 @@ #include <inttypes.h> #include <limits.h> -#define KAD_B (hash_len(ipcpi.dir_hash_algo) * CHAR_BIT) - -struct dht * dht; +struct { + struct dir_ops * ops; + void * dir; +} dirmgr; int dir_init(void) { - dht = dht_create(ipcpi.dt_addr); - if (dht == NULL) + dirmgr.ops = &dht_dir_ops; + + dirmgr.dir = dirmgr.ops->create(); + if (dirmgr.dir == NULL) { + dirmgr.ops = NULL; return -ENOMEM; + } return 0; } void dir_fini(void) { - dht_destroy(dht); + dirmgr.ops->destroy(dirmgr.dir); + dirmgr.ops = NULL; + dirmgr.dir = NULL; } -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_bootstrap(void) +{ + return dirmgr.ops->bootstrap(dirmgr.dir); } int dir_reg(const uint8_t * hash) { - return dht_reg(dht, hash); + return dirmgr.ops->reg(dirmgr.dir, hash); } int dir_unreg(const uint8_t * hash) { - return dht_unreg(dht, hash); + return dirmgr.ops->unreg(dirmgr.dir, hash); } uint64_t dir_query(const uint8_t * hash) { - return dht_query(dht, hash); + return dirmgr.ops->query(dirmgr.dir, hash); } int dir_wait_running(void) { - if (dht_wait_running(dht)) { - log_warn("Directory did not bootstrap."); - return -1; - } - - return 0; + return dirmgr.ops->wait_running(dirmgr.dir); } diff --git a/src/ipcpd/unicast/dir.h b/src/ipcpd/unicast/dir.h index 1b67a08c..b261ea2c 100644 --- a/src/ipcpd/unicast/dir.h +++ b/src/ipcpd/unicast/dir.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Directory * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -23,6 +23,8 @@ #ifndef OUROBOROS_IPCPD_UNICAST_DIR_H #define OUROBOROS_IPCPD_UNICAST_DIR_H +#include <inttypes.h> + int dir_init(void); void dir_fini(void); diff --git a/src/ipcpd/unicast/dht.c b/src/ipcpd/unicast/dir/dht.c index 8555312e..08a5a5a9 100644 --- a/src/ipcpd/unicast/dht.c +++ b/src/ipcpd/unicast/dir/dht.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Distributed Hash Table based on Kademlia * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -31,6 +31,7 @@ #define DHT "dht" #define OUROBOROS_PREFIX DHT +#include <ouroboros/endian.h> #include <ouroboros/hash.h> #include <ouroboros/ipcp-dev.h> #include <ouroboros/bitmap.h> @@ -39,24 +40,26 @@ #include <ouroboros/list.h> #include <ouroboros/notifier.h> #include <ouroboros/random.h> -#include <ouroboros/time_utils.h> +#include <ouroboros/time.h> #include <ouroboros/tpm.h> #include <ouroboros/utils.h> +#include <ouroboros/pthread.h> -#include "connmgr.h" +#include "common/connmgr.h" #include "dht.h" #include "dt.h" +#include "ipcp.h" +#include "ops.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; +#include "dht.pb-c.h" +typedef DhtMsg dht_msg_t; +typedef DhtContactMsg dht_contact_msg_t; #ifndef CLOCK_REALTIME_COARSE #define CLOCK_REALTIME_COARSE CLOCK_REALTIME @@ -208,6 +211,16 @@ struct cmd { struct shm_du_buff * sdb; }; +struct dir_ops dht_dir_ops = { + .create = dht_create, + .destroy = dht_destroy, + .bootstrap = dht_bootstrap, + .reg = dht_reg, + .unreg = dht_unreg, + .query = dht_query, + .wait_running = dht_wait_running +}; + struct dht { size_t alpha; size_t b; @@ -239,7 +252,7 @@ struct dht { pthread_rwlock_t lock; - int fd; + uint64_t eid; struct tpm * tpm; @@ -302,14 +315,16 @@ static int dht_set_state(struct dht * dht, return 0; } -int dht_wait_running(struct dht * dht) +int dht_wait_running(void * dir) { - int ret = 0; + struct dht * dht; + int ret = 0; + + dht = (struct dht *) dir; pthread_mutex_lock(&dht->mtx); - pthread_cleanup_push((void *)(void *) pthread_mutex_unlock, - &dht->mtx); + pthread_cleanup_push(__cleanup_mutex_unlock, &dht->mtx); while (dht->state == DHT_JOINING) pthread_cond_wait(&dht->cond, &dht->mtx); @@ -339,7 +354,7 @@ static uint8_t * create_id(size_t len) } static void kad_req_create(struct dht * dht, - kad_msg_t * msg, + dht_msg_t * msg, uint64_t addr) { struct kad_req * req; @@ -347,14 +362,14 @@ static void kad_req_create(struct dht * dht, struct timespec t; size_t b; + clock_gettime(CLOCK_REALTIME_COARSE, &t); + req = malloc(sizeof(*req)); if (req == NULL) - return; + goto fail_malloc; 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; @@ -368,30 +383,22 @@ static void kad_req_create(struct dht * dht, if (msg->has_key) { req->key = dht_dup_key(msg->key.data, b); - if (req->key == NULL) { - free(req); - return; - } + if (req->key == NULL) + goto fail_dup_key; } - if (pthread_mutex_init(&req->lock, NULL)) { - free(req->key); - free(req); - return; - } + if (pthread_mutex_init(&req->lock, NULL)) + goto fail_mutex; - pthread_condattr_init(&cattr); + + if (pthread_condattr_init(&cattr)) + goto fail_condattr; #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; - } + if (pthread_cond_init(&req->cond, &cattr)) + goto fail_cond_init; pthread_condattr_destroy(&cattr); @@ -400,6 +407,19 @@ static void kad_req_create(struct dht * dht, list_add(&req->next, &dht->requests); pthread_rwlock_unlock(&dht->lock); + + return; + + fail_cond_init: + pthread_condattr_destroy(&cattr); + fail_condattr: + pthread_mutex_destroy(&req->lock); + fail_mutex: + free(req->key); + fail_dup_key: + free(req); + fail_malloc: + return; } static void cancel_req_destroy(void * o) @@ -429,7 +449,7 @@ static void kad_req_destroy(struct kad_req * req) return; case REQ_PENDING: req->state = REQ_DESTROY; - pthread_cond_signal(&req->cond); + pthread_cond_broadcast(&req->cond); break; case REQ_INIT: case REQ_DONE: @@ -452,12 +472,14 @@ static void kad_req_destroy(struct kad_req * req) static int kad_req_wait(struct kad_req * req, time_t t) { - struct timespec timeo = {t, 0}; + struct timespec timeo = TIMESPEC_INIT_S(0); struct timespec abs; int ret = 0; assert(req); + timeo.tv_sec = t; + clock_gettime(PTHREAD_COND_CLOCK, &abs); ts_add(&abs, &timeo, &abs); @@ -466,8 +488,7 @@ static int kad_req_wait(struct kad_req * req, req->state = REQ_PENDING; - pthread_cleanup_push((void *)(void *) pthread_mutex_unlock, - &req->lock); + pthread_cleanup_push(__cleanup_mutex_unlock, &req->lock); while (req->state == REQ_PENDING && ret != -ETIMEDOUT) ret = -pthread_cond_timedwait(&req->cond, &req->lock, &abs); @@ -774,7 +795,7 @@ static void lookup_destroy(struct lookup * lu) static void lookup_update(struct dht * dht, struct lookup * lu, - kad_msg_t * msg) + dht_msg_t * msg) { struct list_head * p = NULL; struct list_head * h; @@ -819,8 +840,7 @@ static void lookup_update(struct dht * dht, return; } - pthread_cleanup_push((void *)(void *) pthread_mutex_unlock, - &lu->lock); + pthread_cleanup_push(__cleanup_mutex_unlock, &lu->lock); while (lu->state == LU_INIT) { pthread_rwlock_unlock(&dht->lock); @@ -967,7 +987,7 @@ static void lookup_set_state(struct lookup * lu, pthread_mutex_unlock(&lu->lock); } -static void cleanup_wait(void * o) +static void cancel_lookup_wait(void * o) { struct lookup * lu = (struct lookup *) o; lu->state = LU_NULL; @@ -977,7 +997,7 @@ static void cleanup_wait(void * o) static enum lookup_state lookup_wait(struct lookup * lu) { - struct timespec timeo = {KAD_T_RESP, 0}; + struct timespec timeo = TIMESPEC_INIT_S(KAD_T_RESP); struct timespec abs; enum lookup_state state; int ret = 0; @@ -991,7 +1011,7 @@ static enum lookup_state lookup_wait(struct lookup * lu) if (lu->state == LU_INIT || lu->state == LU_UPDATE) lu->state = LU_PENDING; - pthread_cleanup_push(cleanup_wait, lu); + pthread_cleanup_push(cancel_lookup_wait, lu); while (lu->state == LU_PENDING && ret != -ETIMEDOUT) ret = -pthread_cond_timedwait(&lu->cond, &lu->lock, &abs); @@ -1009,7 +1029,7 @@ static enum lookup_state lookup_wait(struct lookup * lu) } static struct kad_req * dht_find_request(struct dht * dht, - kad_msg_t * msg) + dht_msg_t * msg) { struct list_head * p; @@ -1257,7 +1277,7 @@ static void bucket_refresh(struct dht * dht, struct contact * d; c = list_first_entry(&b->contacts, struct contact, next); d = contact_create(c->id, dht->b, c->addr); - if (c != NULL) + if (d != NULL) list_add(&d->next, r); return; } @@ -1446,7 +1466,7 @@ static int dht_update_bucket(struct dht * dht, } static int send_msg(struct dht * dht, - kad_msg_t * msg, + dht_msg_t * msg, uint64_t addr) { #ifndef __DHT_TEST__ @@ -1479,7 +1499,7 @@ static int send_msg(struct dht * dht, pthread_rwlock_unlock(&dht->lock); #ifndef __DHT_TEST__ - len = kad_msg__get_packed_size(msg); + len = dht_msg__get_packed_size(msg); if (len == 0) goto fail_msg; @@ -1487,9 +1507,9 @@ static int send_msg(struct dht * dht, if (ipcp_sdb_reserve(&sdb, len)) goto fail_msg; - kad_msg__pack(msg, shm_du_buff_head(sdb)); + dht_msg__pack(msg, shm_du_buff_head(sdb)); - if (dt_write_packet(addr, QOS_CUBE_BE, dht->fd, sdb) == 0) + if (dt_write_packet(addr, QOS_CUBE_BE, dht->eid, sdb) == 0) break; ipcp_sdb_release(sdb); @@ -1534,7 +1554,7 @@ static struct dht_entry * dht_find_entry(struct dht * dht, } static int kad_add(struct dht * dht, - const kad_contact_msg_t * contacts, + const dht_contact_msg_t * contacts, ssize_t n, time_t exp) { @@ -1573,7 +1593,7 @@ static int kad_add(struct dht * dht, } static int wait_resp(struct dht * dht, - kad_msg_t * msg, + dht_msg_t * msg, time_t timeo) { struct kad_req * req; @@ -1600,9 +1620,9 @@ static int kad_store(struct dht * dht, 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]; + dht_msg_t msg = DHT_MSG__INIT; + dht_contact_msg_t cmsg = DHT_CONTACT_MSG__INIT; + dht_contact_msg_t * cmsgp[1]; cmsg.id.data = (uint8_t *) key; cmsg.addr = addr; @@ -1632,7 +1652,7 @@ static ssize_t kad_find(struct dht * dht, const uint64_t * addrs, enum kad_code code) { - kad_msg_t msg = KAD_MSG__INIT; + dht_msg_t msg = DHT_MSG__INIT; ssize_t sent = 0; assert(dht); @@ -1729,7 +1749,7 @@ static struct lookup * kad_lookup(struct dht * dht, } } - assert(state = LU_COMPLETE); + assert(state == LU_COMPLETE); lookup_detach(dht, lu); @@ -1772,7 +1792,7 @@ static void kad_publish(struct dht * dht, while (n-- > 0) { if (addrs[n] == dht->addr) { - kad_contact_msg_t msg = KAD_CONTACT_MSG__INIT; + dht_contact_msg_t msg = DHT_CONTACT_MSG__INIT; msg.id.data = (uint8_t *) key; msg.id.len = dht->b; msg.addr = addr; @@ -1791,7 +1811,7 @@ static void kad_publish(struct dht * dht, static int kad_join(struct dht * dht, uint64_t addr) { - kad_msg_t msg = KAD_MSG__INIT; + dht_msg_t msg = DHT_MSG__INIT; msg.code = KAD_JOIN; @@ -1871,18 +1891,13 @@ static int dht_del(struct dht * dht, { 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; } @@ -1924,14 +1939,14 @@ static buffer_t dht_retrieve(struct dht * dht, fail: pthread_rwlock_unlock(&dht->lock); - buf.len = 0; - + buf.len = 0; + buf.data = NULL; return buf; } static ssize_t dht_get_contacts(struct dht * dht, const uint8_t * key, - kad_contact_msg_t *** msgs) + dht_contact_msg_t *** msgs) { struct list_head l; struct list_head * p; @@ -1946,6 +1961,7 @@ static ssize_t dht_get_contacts(struct dht * dht, len = dht_contact_list(dht, &l, key); if (len == 0) { pthread_rwlock_unlock(&dht->lock); + *msgs = NULL; return 0; } @@ -1963,10 +1979,11 @@ static ssize_t dht_get_contacts(struct dht * dht, while (i > 0) free(*msgs[--i]); free(*msgs); + *msgs = NULL; return 0; } - kad_contact_msg__init((*msgs)[i]); + dht_contact_msg__init((*msgs)[i]); (*msgs)[i]->id.data = c->id; (*msgs)[i]->id.len = dht->b; @@ -2103,7 +2120,7 @@ static void * work(void * o) static int kad_handle_join_resp(struct dht * dht, struct kad_req * req, - kad_msg_t * msg) + dht_msg_t * msg) { assert(dht); assert(req); @@ -2163,7 +2180,7 @@ static int kad_handle_join_resp(struct dht * dht, static int kad_handle_find_resp(struct dht * dht, struct kad_req * req, - kad_msg_t * msg) + dht_msg_t * msg) { struct lookup * lu; @@ -2187,7 +2204,7 @@ static int kad_handle_find_resp(struct dht * dht, } static void kad_handle_response(struct dht * dht, - kad_msg_t * msg) + dht_msg_t * msg) { struct kad_req * req; @@ -2225,15 +2242,23 @@ static void kad_handle_response(struct dht * dht, kad_req_destroy(req); } -int dht_bootstrap(struct dht * dht, - size_t b, - time_t t_expire) +int dht_bootstrap(void * dir) { + struct dht * dht; + + dht = (struct dht *) dir; + assert(dht); pthread_rwlock_wrlock(&dht->lock); - dht->id = create_id(b); +#ifndef __DHT_TEST__ + dht->b = hash_len(ipcpi.dir_hash_algo); +#else + dht->b = DHT_TEST_KEY_LEN; +#endif + + dht->id = create_id(dht->b); if (dht->id == NULL) goto fail_id; @@ -2244,9 +2269,8 @@ int dht_bootstrap(struct dht * dht, 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->t_expire = 86400; /* 1 day */ + dht->t_repub = dht->t_expire - 10; dht->k = KAD_K; if (pthread_create(&dht->worker, NULL, work, dht)) @@ -2285,13 +2309,16 @@ static struct ref_entry * ref_entry_get(struct dht * dht, return NULL; } -int dht_reg(struct dht * dht, +int dht_reg(void * dir, const uint8_t * key) { + struct dht * dht; struct ref_entry * e; uint64_t addr; time_t t_expire; + dht = (struct dht *) dir; + assert(dht); assert(key); assert(dht->addr != 0); @@ -2325,12 +2352,15 @@ int dht_reg(struct dht * dht, return 0; } -int dht_unreg(struct dht * dht, +int dht_unreg(void * dir, const uint8_t * key) { + struct dht * dht; struct list_head * p; struct list_head * h; + dht = (struct dht *) dir; + assert(dht); assert(key); @@ -2354,14 +2384,19 @@ int dht_unreg(struct dht * dht, return 0; } -uint64_t dht_query(struct dht * dht, +uint64_t dht_query(void * dir, const uint8_t * key) { + struct dht * dht; struct dht_entry * e; struct lookup * lu; uint64_t addrs[KAD_K]; size_t n; + dht = (struct dht *) dir; + + assert(dht); + addrs[0] = 0; if (dht_wait_running(dht)) @@ -2407,9 +2442,9 @@ static void * dht_handle_packet(void * o) assert(dht); while (true) { - kad_msg_t * msg; - kad_contact_msg_t ** cmsgs; - kad_msg_t resp_msg = KAD_MSG__INIT; + dht_msg_t * msg; + dht_contact_msg_t ** cmsgs; + dht_msg_t resp_msg = DHT_MSG__INIT; uint64_t addr; buffer_t buf; size_t i; @@ -2419,8 +2454,7 @@ static void * dht_handle_packet(void * o) pthread_mutex_lock(&dht->mtx); - pthread_cleanup_push((void *)(void *) pthread_mutex_unlock, - &dht->mtx); + pthread_cleanup_push(__cleanup_mutex_unlock, &dht->mtx); while (list_is_empty(&dht->cmds)) pthread_cond_wait(&dht->cond, &dht->mtx); @@ -2430,9 +2464,9 @@ static void * dht_handle_packet(void * o) pthread_cleanup_pop(true); - i = shm_du_buff_tail(cmd->sdb) - shm_du_buff_head(cmd->sdb); + i = shm_du_buff_len(cmd->sdb); - msg = kad_msg__unpack(NULL, i, shm_du_buff_head(cmd->sdb)); + msg = dht_msg__unpack(NULL, i, shm_du_buff_head(cmd->sdb)); #ifndef __DHT_TEST__ ipcp_sdb_release(cmd->sdb); #endif @@ -2444,7 +2478,7 @@ static void * dht_handle_packet(void * o) } if (msg->code != KAD_RESPONSE && dht_wait_running(dht)) { - kad_msg__free_unpacked(msg, NULL); + dht_msg__free_unpacked(msg, NULL); log_dbg("Got a request message when not running."); continue; } @@ -2457,13 +2491,13 @@ static void * dht_handle_packet(void * o) pthread_rwlock_unlock(&dht->lock); if (msg->has_key && msg->key.len != b) { - kad_msg__free_unpacked(msg, NULL); + dht_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); + dht_msg__free_unpacked(msg, NULL); log_warn("Bad source ID in message of type %d.", msg->code); continue; @@ -2552,7 +2586,7 @@ static void * dht_handle_packet(void * o) if (dht_get_state(dht) == DHT_JOINING && dht->buckets == NULL) { pthread_rwlock_unlock(&dht->lock); - break; + goto finish; } if (dht_update_bucket(dht, msg->s_id.data, addr)) @@ -2563,7 +2597,8 @@ static void * dht_handle_packet(void * o) if (msg->code < KAD_STORE && send_msg(dht, &resp_msg, addr) < 0) log_warn("Failed to send response."); - kad_msg__free_unpacked(msg, NULL); + finish: + dht_msg__free_unpacked(msg, NULL); if (resp_msg.n_addrs > 0) free(resp_msg.addrs); @@ -2574,7 +2609,7 @@ static void * dht_handle_packet(void * o) } for (i = 0; i < resp_msg.n_contacts; ++i) - kad_contact_msg__free_unpacked(resp_msg.contacts[i], + dht_contact_msg__free_unpacked(resp_msg.contacts[i], NULL); free(resp_msg.contacts); @@ -2614,11 +2649,13 @@ static void dht_post_packet(void * comp, pthread_mutex_unlock(&dht->mtx); } -void dht_destroy(struct dht * dht) +void dht_destroy(void * dir) { + struct dht * dht; struct list_head * p; struct list_head * h; + dht = (struct dht *) dir; if (dht == NULL) return; @@ -2729,7 +2766,7 @@ static void handle_event(void * self, pthread_t thr; struct join_info * inf; struct conn * c = (struct conn *) o; - struct timespec slack = {0, DHT_ENROLL_SLACK * MILLION}; + struct timespec slack = TIMESPEC_INIT_MS(DHT_ENROLL_SLACK); /* Give the pff some time to update for the new link. */ nanosleep(&slack, NULL); @@ -2771,7 +2808,7 @@ static void handle_event(void * self, } } -struct dht * dht_create(uint64_t addr) +void * dht_create(void) { struct dht * dht; @@ -2801,9 +2838,9 @@ struct dht * dht_create(uint64_t addr) goto fail_bmp; dht->b = 0; - dht->addr = addr; dht->id = NULL; #ifndef __DHT_TEST__ + dht->addr = ipcpi.dt_addr; dht->tpm = tpm_create(2, 1, dht_handle_packet, dht); if (dht->tpm == NULL) goto fail_tpm_create; @@ -2811,8 +2848,12 @@ struct dht * dht_create(uint64_t addr) if (tpm_start(dht->tpm)) goto fail_tpm_start; - dht->fd = dt_reg_comp(dht, &dht_post_packet, DHT); - notifier_reg(handle_event, dht); + dht->eid = dt_reg_comp(dht, &dht_post_packet, DHT); + if ((int) dht->eid < 0) + goto fail_tpm_start; + + if (notifier_reg(handle_event, dht)) + goto fail_notifier_reg; #else (void) handle_event; (void) dht_handle_packet; @@ -2820,8 +2861,10 @@ struct dht * dht_create(uint64_t addr) #endif dht->state = DHT_INIT; - return dht; + return (void *) dht; #ifndef __DHT_TEST__ + fail_notifier_reg: + tpm_stop(dht->tpm); fail_tpm_start: tpm_destroy(dht->tpm); fail_tpm_create: diff --git a/src/ipcpd/unicast/dir/dht.h b/src/ipcpd/unicast/dir/dht.h new file mode 100644 index 00000000..311c6b23 --- /dev/null +++ b/src/ipcpd/unicast/dir/dht.h @@ -0,0 +1,52 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Distributed Hash Table based on Kademlia + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * 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_UNICAST_DIR_DHT_H +#define OUROBOROS_IPCPD_UNICAST_DIR_DHT_H + +#include <ouroboros/ipcp-dev.h> + +#include "ops.h" + +#include <stdint.h> +#include <sys/types.h> + +void * dht_create(void); + +void dht_destroy(void * dir); + +int dht_bootstrap(void * dir); + +int dht_reg(void * dir, + const uint8_t * key); + +int dht_unreg(void * dir, + const uint8_t * key); + +uint64_t dht_query(void * dir, + const uint8_t * key); + +int dht_wait_running(void * dir); + +extern struct dir_ops dht_dir_ops; + +#endif /* OUROBOROS_IPCPD_UNICAST_DIR_DHT_H */ diff --git a/src/ipcpd/unicast/kademlia.proto b/src/ipcpd/unicast/dir/dht.proto index 4f807fd3..4c5b06db 100644 --- a/src/ipcpd/unicast/kademlia.proto +++ b/src/ipcpd/unicast/dir/dht.proto @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * - * KAD protocol + * DHT protocol, based on Kademlia * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -22,19 +22,19 @@ syntax = "proto2"; -message kad_contact_msg { +message dht_contact_msg { required bytes id = 1; required uint64 addr = 2; -}; +} -message kad_msg { +message dht_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; + repeated dht_contact_msg contacts = 7; // enrolment parameters optional uint32 alpha = 8; optional uint32 b = 9; @@ -42,4 +42,4 @@ message kad_msg { 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/unicast/dir/ops.h b/src/ipcpd/unicast/dir/ops.h new file mode 100644 index 00000000..6ff61ce6 --- /dev/null +++ b/src/ipcpd/unicast/dir/ops.h @@ -0,0 +1,46 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Directory policy ops + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * 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_UNICAST_DIR_OPS_H +#define OUROBOROS_IPCPD_UNICAST_DIR_OPS_H + + +struct dir_ops { + void * (* create)(void); + + void (* destroy)(void * dir); + + int (* bootstrap)(void * dir); + + int (* reg)(void * dir, + const uint8_t * hash); + + int (* unreg)(void * dir, + const uint8_t * hash); + + uint64_t (* query)(void * dir, + const uint8_t * hash); + + int (* wait_running)(void * dir); +}; + +#endif /* OUROBOROS_IPCPD_UNICAST_DIR_OPS_H */ diff --git a/src/ipcpd/unicast/dir/pol.h b/src/ipcpd/unicast/dir/pol.h new file mode 100644 index 00000000..eae4b2e7 --- /dev/null +++ b/src/ipcpd/unicast/dir/pol.h @@ -0,0 +1,23 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Directory policies + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * 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/. + */ + +#include "dht.h" diff --git a/src/ipcpd/unicast/dir/tests/CMakeLists.txt b/src/ipcpd/unicast/dir/tests/CMakeLists.txt new file mode 100644 index 00000000..f62ed993 --- /dev/null +++ b/src/ipcpd/unicast/dir/tests/CMakeLists.txt @@ -0,0 +1,40 @@ +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(DHT_PROTO_SRCS KAD_PROTO_HDRS ../dht.proto) +add_executable(${PARENT_DIR}_test EXCLUDE_FROM_ALL ${${PARENT_DIR}_tests} + ${DHT_PROTO_SRCS}) +target_link_libraries(${PARENT_DIR}_test ouroboros-common) + +add_dependencies(check ${PARENT_DIR}_test) + +set(tests_to_run ${${PARENT_DIR}_tests}) +if(CMAKE_VERSION VERSION_LESS "3.29.0") + remove(tests_to_run test_suite.c) +else () + list(POP_FRONT tests_to_run) +endif() + +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/unicast/tests/dht_test.c b/src/ipcpd/unicast/dir/tests/dht_test.c index 21ecd564..bea2c3e7 100644 --- a/src/ipcpd/unicast/tests/dht_test.c +++ b/src/ipcpd/unicast/dir/tests/dht_test.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Unit tests of the DHT * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -21,6 +21,7 @@ */ #define __DHT_TEST__ +#define DHT_TEST_KEY_LEN 32 #include "dht.c" @@ -29,23 +30,19 @@ #include <stdlib.h> #include <stdio.h> -#define KEY_LEN 32 - -#define EXP 86400 -#define CONTACTS 1000 +#define CONTACTS 1000 int dht_test(int argc, char ** argv) { struct dht * dht; - uint64_t addr = 0x0D1F; - uint8_t key[KEY_LEN]; + uint8_t key[DHT_TEST_KEY_LEN]; size_t i; (void) argc; (void) argv; - dht = dht_create(addr); + dht = dht_create(); if (dht == NULL) { printf("Failed to create dht.\n"); return -1; @@ -53,13 +50,13 @@ int dht_test(int argc, dht_destroy(dht); - dht = dht_create(addr); + dht = dht_create(); if (dht == NULL) { printf("Failed to re-create dht.\n"); return -1; } - if (dht_bootstrap(dht, KEY_LEN, EXP)) { + if (dht_bootstrap(dht)) { printf("Failed to bootstrap dht.\n"); dht_destroy(dht); return -1; @@ -67,13 +64,13 @@ int dht_test(int argc, dht_destroy(dht); - dht = dht_create(addr); + dht = dht_create(); if (dht == NULL) { printf("Failed to re-create dht.\n"); return -1; } - if (dht_bootstrap(dht, KEY_LEN, EXP)) { + if (dht_bootstrap(dht)) { printf("Failed to bootstrap dht.\n"); dht_destroy(dht); return -1; @@ -82,7 +79,7 @@ int dht_test(int argc, for (i = 0; i < CONTACTS; ++i) { uint64_t addr; random_buffer(&addr, sizeof(addr)); - random_buffer(key, KEY_LEN); + random_buffer(key, DHT_TEST_KEY_LEN); pthread_rwlock_wrlock(&dht->lock); if (dht_update_bucket(dht, key, addr)) { pthread_rwlock_unlock(&dht->lock); diff --git a/src/ipcpd/unicast/dt.c b/src/ipcpd/unicast/dt.c index d6a3ddc9..2bb5ed2f 100644 --- a/src/ipcpd/unicast/dt.c +++ b/src/ipcpd/unicast/dt.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Data Transfer Component * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -41,13 +41,14 @@ #include <ouroboros/fccntl.h> #endif -#include "connmgr.h" +#include "common/comp.h" +#include "common/connmgr.h" +#include "ca.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> @@ -57,8 +58,9 @@ #include <inttypes.h> #include <assert.h> -#define QOS_BLOCK_LEN 672 -#define STAT_FILE_LEN (189 + QOS_BLOCK_LEN * QOS_CUBE_MAX) +#define QOS_BLOCK_LEN 672 +#define RIB_FILE_STRLEN (189 + QOS_BLOCK_LEN * QOS_CUBE_MAX) +#define RIB_NAME_STRLEN 256 #ifndef CLOCK_REALTIME_COARSE #define CLOCK_REALTIME_COARSE CLOCK_REALTIME @@ -80,7 +82,7 @@ struct dt_pci { qoscube_t qc; uint8_t ttl; uint8_t ecn; - uint32_t eid; + uint64_t eid; }; struct { @@ -98,39 +100,29 @@ struct { uint8_t max_ttl; } dt_pci_info; -static int dt_pci_ser(struct shm_du_buff * sdb, - struct dt_pci * dt_pci) +static void dt_pci_ser(uint8_t * head, + struct dt_pci * dt_pci) { - uint8_t * head; - uint8_t ttl = dt_pci_info.max_ttl; + uint8_t ttl = dt_pci_info.max_ttl; - assert(sdb); + assert(head); 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.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) +static void dt_pci_des(uint8_t * head, + struct dt_pci * dt_pci) { - uint8_t * head; - - assert(sdb); + assert(head); assert(dt_pci); - head = shm_du_buff_head(sdb); - /* Decrease TTL */ --*(head + dt_pci_info.ttl_o); @@ -184,24 +176,28 @@ struct { pthread_t listener; } dt; -static int dt_stat_read(const char * path, - char * buf, - size_t len) +static int dt_rib_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 * entry; char tmstr[20]; size_t rxqlen = 0; size_t txqlen = 0; struct tm * tm; /* NOTE: we may need stronger checks. */ - fd = atoi(path); + entry = strstr(path, RIB_SEPARATOR) + 1; + assert(entry); + + fd = atoi(entry); - if (len < STAT_FILE_LEN) + if (len < RIB_FILE_STRLEN) return 0; buf[0] = '\0'; @@ -232,7 +228,6 @@ static int dt_stat_read(const char * path, "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" @@ -271,7 +266,7 @@ static int dt_stat_read(const char * path, pthread_mutex_unlock(&dt.stat[fd].lock); - return STAT_FILE_LEN; + return RIB_FILE_STRLEN; #else (void) path; (void) buf; @@ -280,7 +275,7 @@ static int dt_stat_read(const char * path, #endif } -static int dt_stat_readdir(char *** buf) +static int dt_rib_readdir(char *** buf) { #ifdef IPCP_FLOW_STATS char entry[RIB_PATH_LEN + 1]; @@ -317,7 +312,7 @@ static int dt_stat_readdir(char *** buf) if ((*buf)[idx] == NULL) { while (idx-- > 0) free((*buf)[idx]); - free(buf); + free(*buf); pthread_mutex_unlock(&dt.stat[i].lock); pthread_rwlock_unlock(&dt.lock); return -ENOMEM; @@ -327,11 +322,10 @@ static int dt_stat_readdir(char *** buf) pthread_mutex_unlock(&dt.stat[i].lock); } + assert((size_t) idx == dt.n_flows); pthread_rwlock_unlock(&dt.lock); - assert((size_t) idx == dt.n_flows); - return idx; #else (void) buf; @@ -339,45 +333,43 @@ static int dt_stat_readdir(char *** buf) #endif } -static int dt_stat_getattr(const char * path, - struct stat * st) +static int dt_rib_getattr(const char * path, + struct rib_attr * attr) { #ifdef IPCP_FLOW_STATS - int fd; + int fd; + char * entry; - fd = atoi(path); + entry = strstr(path, RIB_SEPARATOR) + 1; + assert(entry); - st->st_mode = S_IFREG | 0755; - st->st_nlink = 1; - st->st_uid = getuid(); - st->st_gid = getgid(); + fd = atoi(entry); 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; + attr->size = RIB_FILE_STRLEN; + attr->mtime = dt.stat[fd].stamp; } else { - st->st_size = 0; - st->st_mtime = 0; + attr->size = 0; + attr->mtime = 0; } pthread_mutex_unlock(&dt.stat[fd].lock); #else (void) path; - (void) st; + (void) attr; #endif return 0; } static struct rib_ops r_ops = { - .read = dt_stat_read, - .readdir = dt_stat_readdir, - .getattr = dt_stat_getattr + .read = dt_rib_read, + .readdir = dt_rib_readdir, + .getattr = dt_rib_getattr }; #ifdef IPCP_FLOW_STATS - static void stat_used(int fd, uint64_t addr) { @@ -407,6 +399,7 @@ static void handle_event(void * self, const void * o) { struct conn * c; + int fd; (void) self; @@ -414,19 +407,20 @@ static void handle_event(void * self, switch (event) { case NOTIFY_DT_CONN_ADD: + fd = c->flow_info.fd; #ifdef IPCP_FLOW_STATS - stat_used(c->flow_info.fd, c->conn_info.addr); + stat_used(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); + psched_add(dt.psched, fd); + log_dbg("Added fd %d to packet scheduler.", fd); break; case NOTIFY_DT_CONN_DEL: + fd = c->flow_info.fd; #ifdef IPCP_FLOW_STATS - stat_used(c->flow_info.fd, INVALID_ADDR); + stat_used(fd, INVALID_ADDR); #endif - psched_del(dt.psched, c->flow_info.fd); - log_dbg("Removed fd %d from " - "packet scheduler.", c->flow_info.fd); + psched_del(dt.psched, fd); + log_dbg("Removed fd %d from packet scheduler.", fd); break; default: break; @@ -440,17 +434,26 @@ static void packet_handler(int fd, struct dt_pci dt_pci; int ret; int ofd; -#ifdef IPCP_FLOW_STATS + uint8_t * head; size_t len; -#else + + len = shm_du_buff_len(sdb); + +#ifndef IPCP_FLOW_STATS (void) fd; -#endif +#else + pthread_mutex_lock(&dt.stat[fd].lock); -#ifdef IPCP_FLOW_STATS - len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb); + ++dt.stat[fd].rcv_pkt[qc]; + dt.stat[fd].rcv_bytes[qc] += len; + + pthread_mutex_unlock(&dt.stat[fd].lock); #endif memset(&dt_pci, 0, sizeof(dt_pci)); - dt_pci_des(sdb, &dt_pci); + + head = shm_du_buff_head(sdb); + + dt_pci_des(head, &dt_pci); if (dt_pci.dst_addr != ipcpi.dt_addr) { if (dt_pci.ttl == 0) { log_dbg("TTL was zero."); @@ -458,8 +461,6 @@ static void packet_handler(int fd, #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; @@ -471,13 +472,12 @@ static void packet_handler(int fd, /* 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); + 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; @@ -486,6 +486,8 @@ static void packet_handler(int fd, return; } + (void) ca_calc_ecn(ofd, head + dt_pci_info.ecn_o, qc, len); + ret = ipcp_flow_write(ofd, sdb); if (ret < 0) { log_dbg("Failed to write packet to fd %d.", ofd); @@ -493,12 +495,6 @@ static void packet_handler(int fd, 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]; @@ -509,12 +505,6 @@ static void packet_handler(int fd, 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]; @@ -525,65 +515,20 @@ static void packet_handler(int fd, } 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 + uint8_t ecn = *(head + dt_pci_info.ecn_o); + fa_np1_rcv(dt_pci.eid, ecn, sdb); return; } if (dt.comps[dt_pci.eid].post_packet == NULL) { - log_err("No registered component on eid %d.", + log_err("No registered component on eid %" PRIu64 ".", 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; @@ -620,14 +565,11 @@ static void * dt_conn_handle(void * o) return 0; } -int dt_init(enum pol_routing pr, - uint8_t addr_size, - uint8_t eid_size, - uint8_t max_ttl) +int dt_init(struct dt_config cfg) { int i; int j; - char dtstr[256]; + char dtstr[RIB_NAME_STRLEN + 1]; int pp; struct conn_info info; @@ -639,9 +581,14 @@ int dt_init(enum pol_routing pr, 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; + if (cfg.eid_size != 8) { /* only support 64 bits from now */ + log_warn("Invalid EID size. Only 64 bit is supported."); + cfg.eid_size = 8; + } + + dt_pci_info.addr_size = cfg.addr_size; + dt_pci_info.eid_size = cfg.eid_size; + dt_pci_info.max_ttl = cfg.max_ttl; dt_pci_info.qc_o = dt_pci_info.addr_size; dt_pci_info.ttl_o = dt_pci_info.qc_o + QOS_LEN; @@ -649,17 +596,12 @@ int dt_init(enum pol_routing pr, 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; } - pp = routing_init(pr); + pp = routing_init(cfg.routing_type); if (pp < 0) { log_err("Failed to init routing."); goto fail_routing; @@ -697,6 +639,7 @@ int dt_init(enum pol_routing pr, for (i = 0; i < PROG_MAX_FLOWS; ++i) if (pthread_mutex_init(&dt.stat[i].lock, NULL)) { + log_err("Failed to init mutex for flow %d.", i); for (j = 0; j < i; ++j) pthread_mutex_destroy(&dt.stat[j].lock); goto fail_stat_lock; @@ -705,8 +648,10 @@ int dt_init(enum pol_routing pr, dt.n_flows = 0; #endif sprintf(dtstr, "%s.%" PRIu64, DT, ipcpi.dt_addr); - if (rib_reg(dtstr, &r_ops)) + if (rib_reg(dtstr, &r_ops)) { + log_err("Failed to register RIB."); goto fail_rib_reg; + } return 0; @@ -730,16 +675,16 @@ int dt_init(enum pol_routing pr, fail_routing: connmgr_comp_fini(COMPID_DT); fail_connmgr_comp_init: - notifier_unreg(&handle_event); - fail_notifier_reg: return -1; } void dt_fini(void) { + char dtstr[RIB_NAME_STRLEN + 1]; int i; - rib_unreg(DT); + sprintf(dtstr, "%s.%" PRIu64, DT, ipcpi.dt_addr); + rib_unreg(dtstr); #ifdef IPCP_FLOW_STATS for (i = 0; i < PROG_MAX_FLOWS; ++i) pthread_mutex_destroy(&dt.stat[i].lock); @@ -757,16 +702,19 @@ void dt_fini(void) routing_fini(); connmgr_comp_fini(COMPID_DT); - - notifier_unreg(&handle_event); } int dt_start(void) { - dt.psched = psched_create(packet_handler); + dt.psched = psched_create(packet_handler, ipcp_flow_read); if (dt.psched == NULL) { log_err("Failed to create N-1 packet scheduler."); - return -1; + goto fail_psched; + } + + if (notifier_reg(handle_event, NULL)) { + log_err("Failed to register with notifier."); + goto fail_notifier_reg; } if (pthread_create(&dt.listener, NULL, dt_conn_handle, NULL)) { @@ -776,12 +724,21 @@ int dt_start(void) } return 0; + + fail_notifier_reg: + psched_destroy(dt.psched); + fail_psched: + return -1; + } void dt_stop(void) { pthread_cancel(dt.listener); pthread_join(dt.listener, NULL); + + notifier_unreg(&handle_event); + psched_destroy(dt.psched); } @@ -789,81 +746,93 @@ int dt_reg_comp(void * comp, void (* func)(void * func, struct shm_du_buff *), char * name) { - int res_fd; + int eid; 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."); + eid = bmp_allocate(dt.res_fds); + if (!bmp_is_id_valid(dt.res_fds, eid)) { + log_err("Cannot allocate EID."); 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); + assert(dt.comps[eid].post_packet == NULL); + assert(dt.comps[eid].comp == NULL); + assert(dt.comps[eid].name == NULL); - dt.comps[res_fd].post_packet = func; - dt.comps[res_fd].comp = comp; - dt.comps[res_fd].name = name; + dt.comps[eid].post_packet = func; + dt.comps[eid].comp = comp; + dt.comps[eid].name = name; pthread_rwlock_unlock(&dt.lock); #ifdef IPCP_FLOW_STATS - stat_used(res_fd, ipcpi.dt_addr); + stat_used(eid, ipcpi.dt_addr); #endif - return res_fd; + return eid; } int dt_write_packet(uint64_t dst_addr, qoscube_t qc, - int np1_fd, + uint64_t eid, struct shm_du_buff * sdb) { - int fd; struct dt_pci dt_pci; + int fd; int ret; -#ifdef IPCP_FLOW_STATS + uint8_t * head; size_t len; -#endif + assert(sdb); assert(dst_addr != ipcpi.dt_addr); + len = shm_du_buff_len(sdb); + +#ifdef IPCP_FLOW_STATS + if (eid < PROG_RES_FDS) { + pthread_mutex_lock(&dt.stat[eid].lock); + + ++dt.stat[eid].lcl_r_pkt[qc]; + dt.stat[eid].lcl_r_bytes[qc] += len; + + pthread_mutex_unlock(&dt.stat[eid].lock); + } +#endif 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); + if (eid < PROG_RES_FDS) { + pthread_mutex_lock(&dt.stat[eid].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; + ++dt.stat[eid].lcl_r_pkt[qc]; + dt.stat[eid].lcl_r_bytes[qc] += len; - pthread_mutex_unlock(&dt.stat[np1_fd].lock); + pthread_mutex_unlock(&dt.stat[eid].lock); + } #endif - return -1; + return -EPERM; + } + + head = shm_du_buff_head_alloc(sdb, dt_pci_info.head_size); + if (head == NULL) { + log_dbg("Failed to allocate DT header."); + goto fail_write; } + len = shm_du_buff_len(sdb); + dt_pci.dst_addr = dst_addr; dt_pci.qc = qc; - dt_pci.eid = np1_fd; + dt_pci.eid = eid; 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 + (void) ca_calc_ecn(fd, &dt_pci.ecn, qc, len); + + dt_pci_ser(head, &dt_pci); + ret = ipcp_flow_write(fd, sdb); if (ret < 0) { log_dbg("Failed to write packet to fd %d.", fd); @@ -872,12 +841,6 @@ int dt_write_packet(uint64_t dst_addr, 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) { @@ -893,15 +856,9 @@ int dt_write_packet(uint64_t dst_addr, 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) { + if (eid < PROG_RES_FDS) { ++dt.stat[fd].lcl_w_pkt[qc]; dt.stat[fd].lcl_w_bytes[qc] += len; } diff --git a/src/ipcpd/unicast/dt.h b/src/ipcpd/unicast/dt.h index 73b71a92..7198a013 100644 --- a/src/ipcpd/unicast/dt.h +++ b/src/ipcpd/unicast/dt.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Data Transfer component * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -31,11 +31,7 @@ #define DT_PROTO "dtp" #define INVALID_ADDR 0 -int dt_init(enum pol_routing pr, - uint8_t addr_size, - uint8_t eid_size, - uint8_t max_ttl -); +int dt_init(struct dt_config cfg); void dt_fini(void); @@ -49,7 +45,7 @@ int dt_reg_comp(void * comp, int dt_write_packet(uint64_t dst_addr, qoscube_t qc, - int res_fd, + uint64_t eid, struct shm_du_buff * sdb); #endif /* OUROBOROS_IPCPD_UNICAST_DT_H */ diff --git a/src/ipcpd/unicast/enroll.c b/src/ipcpd/unicast/enroll.c deleted file mode 100644 index 3b4a5a89..00000000 --- a/src/ipcpd/unicast/enroll.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2020 - * - * Enrollment Task - * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> - * - * 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) < 0) { - 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.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.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) < 0) { - 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) < 0) { - 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/unicast/fa.c b/src/ipcpd/unicast/fa.c index e0727e85..3631fd7b 100644 --- a/src/ipcpd/unicast/fa.c +++ b/src/ipcpd/unicast/fa.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Flow allocator of the IPC Process * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -31,43 +31,57 @@ #define FA "flow-allocator" #define OUROBOROS_PREFIX FA +#include <ouroboros/endian.h> #include <ouroboros/logs.h> #include <ouroboros/fqueue.h> #include <ouroboros/errno.h> #include <ouroboros/dev.h> #include <ouroboros/ipcp-dev.h> +#include <ouroboros/rib.h> +#include <ouroboros/random.h> +#include <ouroboros/pthread.h> #include "dir.h" #include "fa.h" #include "psched.h" #include "ipcp.h" #include "dt.h" +#include "ca.h" -#include <pthread.h> +#include <inttypes.h> #include <stdlib.h> #include <string.h> -#define TIMEOUT 10000 /* nanoseconds */ +#if defined (IPCP_FLOW_STATS) && !defined(CLOCK_REALTIME_COARSE) +#define CLOCK_REALTIME_COARSE CLOCK_REALTIME +#endif + +#define TIMEOUT 10 * MILLION /* nanoseconds */ + +#define FLOW_REQ 0 +#define FLOW_REPLY 1 +#define FLOW_UPDATE 2 +#define MSGBUFSZ 2048 -#define FLOW_REQ 0 -#define FLOW_REPLY 1 -#define MSGBUFSZ 2048 +#define STAT_FILE_LEN 0 struct fa_msg { uint64_t s_addr; - uint32_t r_eid; - uint32_t s_eid; + uint64_t r_eid; + uint64_t s_eid; uint8_t code; int8_t response; + uint16_t ece; /* 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; + uint32_t timeout; uint16_t cypher_s; + uint8_t availability; + uint8_t in_order; } __attribute__((packed)); struct cmd { @@ -75,11 +89,33 @@ struct cmd { struct shm_du_buff * sdb; }; +struct fa_flow { +#ifdef IPCP_FLOW_STATS + time_t stamp; /* Flow creation */ + size_t p_snd; /* Packets sent */ + size_t p_snd_f; /* Packets sent fail */ + size_t b_snd; /* Bytes sent */ + size_t b_snd_f; /* Bytes sent fail */ + size_t p_rcv; /* Packets received */ + size_t p_rcv_f; /* Packets received fail */ + size_t b_rcv; /* Bytes received */ + size_t b_rcv_f; /* Bytes received fail */ + size_t u_snd; /* Flow updates sent */ + size_t u_rcv; /* Flow updates received */ +#endif + uint64_t s_eid; /* Local endpoint id */ + uint64_t r_eid; /* Remote endpoint id */ + uint64_t r_addr; /* Remote address */ + void * ctx; /* Congestion avoidance context */ +}; + struct { pthread_rwlock_t flows_lock; - int r_eid[PROG_MAX_FLOWS]; - uint64_t r_addr[PROG_MAX_FLOWS]; - int fd; + struct fa_flow flows[PROG_MAX_FLOWS]; +#ifdef IPCP_FLOW_STATS + size_t n_flows; +#endif + uint32_t eid; struct list_head cmds; pthread_cond_t cond; @@ -89,26 +125,289 @@ struct { struct psched * psched; } fa; +static int fa_rib_read(const char * path, + char * buf, + size_t len) +{ +#ifdef IPCP_FLOW_STATS + struct fa_flow * flow; + int fd; + char r_addrstr[21]; + char s_eidstr[21]; + char r_eidstr[21]; + char tmstr[20]; + char castr[1024]; + char * entry; + struct tm * tm; + + entry = strstr(path, RIB_SEPARATOR) + 1; + assert(entry); + + fd = atoi(entry); + + if (fd < 0 || fd >= PROG_MAX_FLOWS) + return -1; + + if (len < 1536) + return 0; + + flow = &fa.flows[fd]; + + buf[0] = '\0'; + + pthread_rwlock_rdlock(&fa.flows_lock); + + if (flow->stamp ==0) { + pthread_rwlock_unlock(&fa.flows_lock); + return 0; + } + + sprintf(r_addrstr, "%" PRIu64, flow->r_addr); + sprintf(s_eidstr, "%" PRIu64, flow->s_eid); + sprintf(r_eidstr, "%" PRIu64, flow->r_eid); + + tm = localtime(&flow->stamp); + strftime(tmstr, sizeof(tmstr), "%F %T", tm); + + ca_print_stats(flow->ctx, castr, 1024); + + sprintf(buf, + "Flow established at: %20s\n" + "Remote address: %20s\n" + "Local endpoint ID: %20s\n" + "Remote endpoint ID: %20s\n" + "Sent (packets): %20zu\n" + "Sent (bytes): %20zu\n" + "Send failed (packets): %20zu\n" + "Send failed (bytes): %20zu\n" + "Received (packets): %20zu\n" + "Received (bytes): %20zu\n" + "Receive failed (packets): %20zu\n" + "Receive failed (bytes): %20zu\n" + "Sent flow updates (packets): %20zu\n" + "Received flow updates (packets): %20zu\n" + "%s", + tmstr, r_addrstr, + s_eidstr, r_eidstr, + flow->p_snd, flow->b_snd, + flow->p_snd_f, flow->b_snd_f, + flow->p_rcv, flow->b_rcv, + flow->b_rcv_f, flow->b_rcv_f, + flow->u_snd, flow->u_rcv, + castr); + + pthread_rwlock_unlock(&fa.flows_lock); + + return strlen(buf); +#else + (void) path; + (void) buf; + (void) len; + return 0; +#endif +} + +static int fa_rib_readdir(char *** buf) +{ +#ifdef IPCP_FLOW_STATS + char entry[RIB_PATH_LEN + 1]; + size_t i; + int idx = 0; + + pthread_rwlock_rdlock(&fa.flows_lock); + + if (fa.n_flows < 1) { + pthread_rwlock_unlock(&fa.flows_lock); + return 0; + } + + *buf = malloc(sizeof(**buf) * fa.n_flows); + if (*buf == NULL) { + pthread_rwlock_unlock(&fa.flows_lock); + return -ENOMEM; + } + + for (i = 0; i < PROG_MAX_FLOWS; ++i) { + struct fa_flow * flow; + + flow = &fa.flows[i]; + if (flow->stamp == 0) + continue; + + sprintf(entry, "%zu", i); + + (*buf)[idx] = malloc(strlen(entry) + 1); + if ((*buf)[idx] == NULL) { + while (idx-- > 0) + free((*buf)[idx]); + free(*buf); + pthread_rwlock_unlock(&fa.flows_lock); + return -ENOMEM; + } + + strcpy((*buf)[idx++], entry); + } + + assert((size_t) idx == fa.n_flows); + + pthread_rwlock_unlock(&fa.flows_lock); + + return idx; +#else + (void) buf; + return 0; +#endif +} + +static int fa_rib_getattr(const char * path, + struct rib_attr * attr) +{ +#ifdef IPCP_FLOW_STATS + int fd; + char * entry; + struct fa_flow * flow; + + entry = strstr(path, RIB_SEPARATOR) + 1; + assert(entry); + + fd = atoi(entry); + + flow = &fa.flows[fd]; + + pthread_rwlock_rdlock(&fa.flows_lock); + + if (flow->stamp != 0) { + attr->size = 1536; + attr->mtime = flow->stamp; + } else { + attr->size = 0; + attr->mtime = 0; + } + + pthread_rwlock_unlock(&fa.flows_lock); +#else + (void) path; + (void) attr; +#endif + return 0; +} + +static struct rib_ops r_ops = { + .read = fa_rib_read, + .readdir = fa_rib_readdir, + .getattr = fa_rib_getattr +}; + +static int eid_to_fd(uint64_t eid) +{ + struct fa_flow * flow; + int fd; + + fd = eid & 0xFFFFFFFF; + + if (fd < 0 || fd >= PROG_MAX_FLOWS) + return -1; + + flow = &fa.flows[fd]; + + if (flow->s_eid == eid) + return fd; + + return -1; +} + +static uint64_t gen_eid(int fd) +{ + uint32_t rnd; + + if (random_buffer(&rnd, sizeof(rnd)) < 0) + return fa.eid; /* INVALID */ + + fd &= 0xFFFFFFFF; + + return ((uint64_t) rnd << 32) + fd; +} + static void packet_handler(int fd, qoscube_t qc, struct shm_du_buff * sdb) { - pthread_rwlock_rdlock(&fa.flows_lock); + struct fa_flow * flow; + uint64_t r_addr; + uint64_t r_eid; + ca_wnd_t wnd; + size_t len; - if (dt_write_packet(fa.r_addr[fd], qc, fa.r_eid[fd], sdb)) { - pthread_rwlock_unlock(&fa.flows_lock); + flow = &fa.flows[fd]; + + pthread_rwlock_wrlock(&fa.flows_lock); + + len = shm_du_buff_len(sdb); + +#ifdef IPCP_FLOW_STATS + ++flow->p_snd; + flow->b_snd += len; +#endif + wnd = ca_ctx_update_snd(flow->ctx, len); + + r_addr = flow->r_addr; + r_eid = flow->r_eid; + + pthread_rwlock_unlock(&fa.flows_lock); + + ca_wnd_wait(wnd); + + if (dt_write_packet(r_addr, qc, r_eid, sdb)) { ipcp_sdb_release(sdb); - log_warn("Failed to forward packet."); + log_dbg("Failed to forward packet."); +#ifdef IPCP_FLOW_STATS + pthread_rwlock_wrlock(&fa.flows_lock); + ++flow->p_snd_f; + flow->b_snd_f += len; + pthread_rwlock_unlock(&fa.flows_lock); +#endif return; } +} - pthread_rwlock_unlock(&fa.flows_lock); +static int fa_flow_init(struct fa_flow * flow) +{ +#ifdef IPCP_FLOW_STATS + struct timespec now; +#endif + memset(flow, 0, sizeof(*flow)); + + flow->r_eid = -1; + flow->s_eid = -1; + flow->r_addr = INVALID_ADDR; + + flow->ctx = ca_ctx_create(); + if (flow->ctx == NULL) + return -1; + +#ifdef IPCP_FLOW_STATS + clock_gettime(CLOCK_REALTIME_COARSE, &now); + + flow->stamp = now.tv_sec; + + ++fa.n_flows; +#endif + return 0; } -static void destroy_conn(int fd) +static void fa_flow_fini(struct fa_flow * flow) { - fa.r_eid[fd] = -1; - fa.r_addr[fd] = INVALID_ADDR; + ca_ctx_destroy(flow->ctx); + + memset(flow, 0, sizeof(*flow)); + + flow->r_eid = -1; + flow->s_eid = -1; + flow->r_addr = INVALID_ADDR; + +#ifdef IPCP_FLOW_STATS + --fa.n_flows; +#endif } static void fa_post_packet(void * comp, @@ -138,146 +437,200 @@ static void fa_post_packet(void * comp, pthread_mutex_unlock(&fa.mtx); } -static void * fa_handle_packet(void * o) +static size_t fa_wait_for_fa_msg(struct fa_msg * msg) { - struct timespec ts = {0, TIMEOUT * 1000}; + struct cmd * cmd; + size_t len; - (void) o; + pthread_mutex_lock(&fa.mtx); - while (true) { - struct timespec abstime; - int fd; - uint8_t buf[MSGBUFSZ]; - struct fa_msg * msg; - qosspec_t qs; - struct cmd * cmd; - size_t len; - size_t msg_len; + pthread_cleanup_push(__cleanup_mutex_unlock, &fa.mtx); - pthread_mutex_lock(&fa.mtx); + while (list_is_empty(&fa.cmds)) + pthread_cond_wait(&fa.cond, &fa.mtx); - pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, - &fa.mtx); + cmd = list_last_entry(&fa.cmds, struct cmd, next); + list_del(&cmd->next); - while (list_is_empty(&fa.cmds)) - pthread_cond_wait(&fa.cond, &fa.mtx); + pthread_cleanup_pop(true); - cmd = list_last_entry(&fa.cmds, struct cmd, next); - list_del(&cmd->next); + len = shm_du_buff_len(cmd->sdb); + if (len > MSGBUFSZ || len < sizeof(*msg)) { + log_warn("Invalid flow allocation message (len: %zd).", len); + free(cmd); + return 0; /* No valid message */ + } - pthread_cleanup_pop(true); + memcpy(msg, shm_du_buff_head(cmd->sdb), len); - len = shm_du_buff_tail(cmd->sdb) - shm_du_buff_head(cmd->sdb); + ipcp_sdb_release(cmd->sdb); - if (len > MSGBUFSZ) { - log_err("Message over buffer size."); - free(cmd); - continue; - } + free(cmd); - msg = (struct fa_msg *) buf; + return len; +} - /* Depending on the message call the function in ipcp-dev.h */ +static int fa_handle_flow_req(struct fa_msg * msg, + size_t len) +{ + size_t msg_len; + int fd; + qosspec_t qs; + struct fa_flow * flow; + uint8_t * dst; + buffer_t data; /* Piggbacked data on flow alloc request. */ + + msg_len = sizeof(*msg) + ipcp_dir_hash_len(); + if (len < msg_len) { + log_err("Invalid flow allocation request"); + return -EPERM; + } - memcpy(msg, shm_du_buff_head(cmd->sdb), len); + dst = (uint8_t *)(msg + 1); + data.data = (uint8_t *) msg + msg_len; + data.len = len - msg_len; - ipcp_sdb_release(cmd->sdb); + 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); + qs.cypher_s = ntoh16(msg->cypher_s); + qs.timeout = ntoh32(msg->timeout); - free(cmd); + fd = ipcp_wait_flow_req_arr(dst, qs, IPCP_UNICAST_MPL, &data); + if (fd < 0) + return fd; - switch (msg->code) { - case FLOW_REQ: - msg_len = sizeof(*msg) + ipcp_dir_hash_len(); - - assert(len >= msg_len); - - 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."); - 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); - qs.cypher_s = ntoh16(msg->cypher_s); - - fd = ipcp_flow_req_arr((uint8_t *) (msg + 1), - ipcp_dir_hash_len(), - qs, - buf + msg_len, - len - msg_len); - if (fd < 0) { - pthread_mutex_unlock(&ipcpi.alloc_lock); - log_err("Failed to get fd for flow."); - continue; - } - - pthread_rwlock_wrlock(&fa.flows_lock); - - fa.r_eid[fd] = ntoh32(msg->s_eid); - fa.r_addr[fd] = ntoh64(msg->s_addr); + flow = &fa.flows[fd]; - pthread_rwlock_unlock(&fa.flows_lock); + pthread_rwlock_wrlock(&fa.flows_lock); - ipcpi.alloc_id = fd; - pthread_cond_broadcast(&ipcpi.alloc_cond); + fa_flow_init(flow); - pthread_mutex_unlock(&ipcpi.alloc_lock); + flow->s_eid = gen_eid(fd); + flow->r_eid = ntoh64(msg->s_eid); + flow->r_addr = ntoh64(msg->s_addr); - break; - case FLOW_REPLY: - assert(len >= sizeof(*msg)); + pthread_rwlock_unlock(&fa.flows_lock); - pthread_rwlock_wrlock(&fa.flows_lock); + return fd; +} - fa.r_eid[ntoh32(msg->r_eid)] = ntoh32(msg->s_eid); +static int fa_handle_flow_reply(struct fa_msg * msg, + size_t len) +{ + int fd; + struct fa_flow * flow; + buffer_t data; /* Piggbacked data on flow alloc request. */ + time_t mpl = IPCP_UNICAST_MPL; - ipcp_flow_alloc_reply(ntoh32(msg->r_eid), - msg->response, - buf + sizeof(*msg), - len - sizeof(*msg)); + assert(len >= sizeof(*msg)); - if (msg->response < 0) - destroy_conn(ntoh32(msg->r_eid)); - else - psched_add(fa.psched, ntoh32(msg->r_eid)); + data.data = (uint8_t *) msg + sizeof(*msg); + data.len = len - sizeof(*msg); - pthread_rwlock_unlock(&fa.flows_lock); + pthread_rwlock_wrlock(&fa.flows_lock); + + fd = eid_to_fd(ntoh64(msg->r_eid)); + if (fd < 0) { + pthread_rwlock_unlock(&fa.flows_lock); + log_err("Flow reply for unknown EID %" PRIu64 ".", + ntoh64(msg->r_eid)); + return -ENOTALLOC; + } + + flow = &fa.flows[fd]; + + flow->r_eid = ntoh64(msg->s_eid); + + if (msg->response < 0) + fa_flow_fini(flow); + else + psched_add(fa.psched, fd); + + pthread_rwlock_unlock(&fa.flows_lock); + + if (ipcp_flow_alloc_reply(fd, msg->response, mpl, &data) < 0) { + log_err("Failed to reply for flow allocation on fd %d.", fd); + return -EIRMD; + } + + return 0; +} + +static int fa_handle_flow_update(struct fa_msg * msg, + size_t len) +{ + struct fa_flow * flow; + int fd; + + (void) len; + assert(len >= sizeof(*msg)); + + pthread_rwlock_wrlock(&fa.flows_lock); + + fd = eid_to_fd(ntoh64(msg->r_eid)); + if (fd < 0) { + pthread_rwlock_unlock(&fa.flows_lock); + log_err("Flow update for unknown EID %" PRIu64 ".", + ntoh64(msg->r_eid)); + return -EPERM; + } + + flow = &fa.flows[fd]; +#ifdef IPCP_FLOW_STATS + flow->u_rcv++; +#endif + ca_ctx_update_ece(flow->ctx, ntoh16(msg->ece)); + + pthread_rwlock_unlock(&fa.flows_lock); + + return 0; +} + +static void * fa_handle_packet(void * o) +{ + (void) o; + + while (true) { + uint8_t buf[MSGBUFSZ]; + struct fa_msg * msg; + size_t len; + + msg = (struct fa_msg *) buf; + + len = fa_wait_for_fa_msg(msg); + if (len == 0) + continue; + switch (msg->code) { + case FLOW_REQ: + if (fa_handle_flow_req(msg, len) < 0) + log_err("Error handling flow alloc request."); + break; + case FLOW_REPLY: + if (fa_handle_flow_reply(msg, len) < 0) + log_err("Error handling flow reply."); + break; + case FLOW_UPDATE: + if (fa_handle_flow_update(msg, len) < 0) + log_err("Error handling flow update."); break; default: - log_err("Got an unknown flow allocation message."); + log_warn("Recieved unknown flow allocation message."); break; } } + + return (void *) 0; } int fa_init(void) { - int i; - - for (i = 0; i < PROG_MAX_FLOWS; ++i) - destroy_conn(i); + pthread_condattr_t cattr; if (pthread_rwlock_init(&fa.flows_lock, NULL)) goto fail_rwlock; @@ -285,26 +638,45 @@ int fa_init(void) if (pthread_mutex_init(&fa.mtx, NULL)) goto fail_mtx; - if (pthread_cond_init(&fa.cond, NULL)) + if (pthread_condattr_init(&cattr)) + goto fail_cattr; + +#ifndef __APPLE__ + pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK); +#endif + if (pthread_cond_init(&fa.cond, &cattr)) goto fail_cond; + pthread_condattr_destroy(&cattr); + list_head_init(&fa.cmds); - fa.fd = dt_reg_comp(&fa, &fa_post_packet, FA); + if (rib_reg(FA, &r_ops)) + goto fail_rib_reg; + + fa.eid = dt_reg_comp(&fa, &fa_post_packet, FA); + if ((int) fa.eid < 0) + goto fail_rib_reg; return 0; + fail_rib_reg: + pthread_cond_destroy(&fa.cond); fail_cond: + pthread_condattr_destroy(&cattr); + fail_cattr: 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) { + rib_unreg(FA); + pthread_cond_destroy(&fa.cond);; pthread_mutex_destroy(&fa.mtx); pthread_rwlock_destroy(&fa.flows_lock); @@ -316,7 +688,7 @@ int fa_start(void) int pol; int max; - fa.psched = psched_create(packet_handler); + fa.psched = psched_create(packet_handler, np1_flow_read); if (fa.psched == NULL) { log_err("Failed to start packet scheduler."); goto fail_psched; @@ -353,7 +725,6 @@ int fa_start(void) fail_thread: psched_destroy(fa.psched); fail_psched: - log_err("Failed to start flow allocator."); return -1; } @@ -365,17 +736,18 @@ void fa_stop(void) psched_destroy(fa.psched); } -int fa_alloc(int fd, - const uint8_t * dst, - qosspec_t qs, - const void * data, - size_t dlen) +int fa_alloc(int fd, + const uint8_t * dst, + qosspec_t qs, + const buffer_t * data) { struct fa_msg * msg; - uint64_t addr; struct shm_du_buff * sdb; - qoscube_t qc; + struct fa_flow * flow; + uint64_t addr; + qoscube_t qc = QOS_CUBE_BE; size_t len; + uint64_t eid; addr = dir_query(dst); if (addr == 0) @@ -383,12 +755,16 @@ int fa_alloc(int fd, len = sizeof(*msg) + ipcp_dir_hash_len(); - if (ipcp_sdb_reserve(&sdb, len + dlen)) + if (ipcp_sdb_reserve(&sdb, len + data->len)) return -1; - msg = (struct fa_msg *) shm_du_buff_head(sdb); + msg = (struct fa_msg *) shm_du_buff_head(sdb); + memset(msg, 0, sizeof(*msg)); + + eid = gen_eid(fd); + msg->code = FLOW_REQ; - msg->s_eid = hton32(fd); + msg->s_eid = hton64(eid); msg->s_addr = hton64(ipcpi.dt_addr); msg->delay = hton32(qs.delay); msg->bandwidth = hton64(qs.bandwidth); @@ -398,111 +774,196 @@ int fa_alloc(int fd, msg->in_order = qs.in_order; msg->max_gap = hton32(qs.max_gap); msg->cypher_s = hton16(qs.cypher_s); + msg->timeout = hton32(qs.timeout); memcpy(msg + 1, dst, ipcp_dir_hash_len()); - memcpy(shm_du_buff_head(sdb) + len, data, dlen); - - qc = qos_spec_to_cube(qs); + if (data->len > 0) + memcpy(shm_du_buff_head(sdb) + len, data->data, data->len); - if (dt_write_packet(addr, qc, fa.fd, sdb)) { + if (dt_write_packet(addr, qc, fa.eid, sdb)) { + log_err("Failed to send flow allocation request packet."); ipcp_sdb_release(sdb); return -1; } + flow = &fa.flows[fd]; + pthread_rwlock_wrlock(&fa.flows_lock); - assert(fa.r_eid[fd] == -1); - fa.r_addr[fd] = addr; + fa_flow_init(flow); + flow->r_addr = addr; + flow->s_eid = eid; pthread_rwlock_unlock(&fa.flows_lock); return 0; } -int fa_alloc_resp(int fd, - int response, - const void * data, - size_t len) +int fa_alloc_resp(int fd, + int response, + const buffer_t * data) { - 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); + struct fa_flow * flow; + qoscube_t qc = QOS_CUBE_BE; - pthread_mutex_lock(&ipcpi.alloc_lock); + flow = &fa.flows[fd]; - 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_wait_flow_resp(fd) < 0) { + log_err("Failed to wait for flow response."); + goto fail_alloc_resp; } - if (ipcp_get_state() != IPCP_OPERATIONAL) { - pthread_mutex_unlock(&ipcpi.alloc_lock); - return -1; + if (ipcp_sdb_reserve(&sdb, sizeof(*msg) + data->len)) { + log_err("Failed to reserve sdb (%zu bytes).", + sizeof(*msg) + data->len); + goto fail_reserve; } - ipcpi.alloc_id = -1; - pthread_cond_broadcast(&ipcpi.alloc_cond); + msg = (struct fa_msg *) shm_du_buff_head(sdb); + memset(msg, 0, sizeof(*msg)); - pthread_mutex_unlock(&ipcpi.alloc_lock); + msg->code = FLOW_REPLY; + msg->response = response; + if (data->len > 0) + memcpy(msg + 1, data->data, data->len); - if (ipcp_sdb_reserve(&sdb, sizeof(*msg) + len)) { - destroy_conn(fd); - return -1; - } + pthread_rwlock_rdlock(&fa.flows_lock); - pthread_rwlock_wrlock(&fa.flows_lock); + msg->r_eid = hton64(flow->r_eid); + msg->s_eid = hton64(flow->s_eid); - 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; + pthread_rwlock_unlock(&fa.flows_lock); - memcpy(msg + 1, data, len); + if (dt_write_packet(flow->r_addr, qc, fa.eid, sdb)) { + log_err("Failed to send flow allocation response packet."); + goto fail_packet; + } if (response < 0) { - destroy_conn(fd); - ipcp_sdb_release(sdb); + pthread_rwlock_rdlock(&fa.flows_lock); + fa_flow_fini(flow); + pthread_rwlock_unlock(&fa.flows_lock); } else { psched_add(fa.psched, fd); } - ipcp_flow_get_qoscube(fd, &qc); + return 0; + + fail_packet: + ipcp_sdb_release(sdb); + fail_reserve: + pthread_rwlock_wrlock(&fa.flows_lock); + fa_flow_fini(flow); + pthread_rwlock_unlock(&fa.flows_lock); + fail_alloc_resp: + return -1; +} + +int fa_dealloc(int fd) +{ + if (ipcp_flow_fini(fd) < 0) + return 0; + + psched_del(fa.psched, fd); - assert(qc >= 0 && qc < QOS_CUBE_MAX); + pthread_rwlock_wrlock(&fa.flows_lock); - 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); + fa_flow_fini(&fa.flows[fd]); + + pthread_rwlock_unlock(&fa.flows_lock); + + ipcp_flow_dealloc(fd); + + return 0; +} + +static int fa_update_remote(int fd, + uint16_t ece) +{ + struct fa_msg * msg; + struct shm_du_buff * sdb; + qoscube_t qc = QOS_CUBE_BE; + struct fa_flow * flow; + uint64_t r_addr; + + if (ipcp_sdb_reserve(&sdb, sizeof(*msg))) { + log_err("Failed to reserve sdb (%zu bytes).", sizeof(*msg)); return -1; } + msg = (struct fa_msg *) shm_du_buff_head(sdb); + + memset(msg, 0, sizeof(*msg)); + + flow = &fa.flows[fd]; + + pthread_rwlock_wrlock(&fa.flows_lock); + + msg->code = FLOW_UPDATE; + msg->r_eid = hton64(flow->r_eid); + msg->ece = hton16(ece); + + r_addr = flow->r_addr; +#ifdef IPCP_FLOW_STATS + flow->u_snd++; +#endif pthread_rwlock_unlock(&fa.flows_lock); + + if (dt_write_packet(r_addr, qc, fa.eid, sdb)) { + log_err("Failed to send flow update packet."); + ipcp_sdb_release(sdb); + return -1; + } + return 0; } -int fa_dealloc(int fd) +void fa_np1_rcv(uint64_t eid, + uint8_t ecn, + struct shm_du_buff * sdb) { - if (ipcp_flow_fini(fd) < 0) - return 0; + struct fa_flow * flow; + bool update; + uint16_t ece; + int fd; + size_t len; + + len = shm_du_buff_len(sdb); pthread_rwlock_wrlock(&fa.flows_lock); - psched_del(fa.psched, fd); + fd = eid_to_fd(eid); + if (fd < 0) { + pthread_rwlock_unlock(&fa.flows_lock); + log_dbg("Received packet for unknown EID %" PRIu64 ".", eid); + ipcp_sdb_release(sdb); + return; + } + + flow = &fa.flows[fd]; - destroy_conn(fd); +#ifdef IPCP_FLOW_STATS + ++flow->p_rcv; + flow->b_rcv += len; +#endif + update = ca_ctx_update_rcv(flow->ctx, len, ecn, &ece); pthread_rwlock_unlock(&fa.flows_lock); - flow_dealloc(fd); + if (ipcp_flow_write(fd, sdb) < 0) { + log_dbg("Failed to write to flow %d.", fd); + ipcp_sdb_release(sdb); +#ifdef IPCP_FLOW_STATS + pthread_rwlock_wrlock(&fa.flows_lock); + ++flow->p_rcv_f; + flow->b_rcv_f += len; + pthread_rwlock_unlock(&fa.flows_lock); +#endif + } - return 0; + if (update) + fa_update_remote(eid, ece); } diff --git a/src/ipcpd/unicast/fa.h b/src/ipcpd/unicast/fa.h index 12a10a0c..1e716966 100644 --- a/src/ipcpd/unicast/fa.h +++ b/src/ipcpd/unicast/fa.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Flow allocator of the IPC Process * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -34,17 +34,19 @@ int fa_start(void); void fa_stop(void); -int fa_alloc(int fd, - const uint8_t * dst, - qosspec_t qs, - const void * data, - size_t len); +int fa_alloc(int fd, + const uint8_t * dst, + qosspec_t qs, + const buffer_t * data); -int fa_alloc_resp(int fd, - int response, - const void * data, - size_t len); +int fa_alloc_resp(int fd, + int response, + const buffer_t * data); int fa_dealloc(int fd); +void fa_np1_rcv(uint64_t eid, + uint8_t ecn, + struct shm_du_buff * sdb); + #endif /* OUROBOROS_IPCPD_UNICAST_FA_H */ diff --git a/src/ipcpd/unicast/main.c b/src/ipcpd/unicast/main.c index 43052209..e6cb2994 100644 --- a/src/ipcpd/unicast/main.c +++ b/src/ipcpd/unicast/main.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Unicast IPC Process * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -29,20 +29,22 @@ #include "config.h" #define OUROBOROS_PREFIX "unicast-ipcp" +#define THIS_TYPE IPCP_UNICAST #include <ouroboros/errno.h> -#include <ouroboros/hash.h> #include <ouroboros/ipcp-dev.h> #include <ouroboros/logs.h> #include <ouroboros/notifier.h> +#include <ouroboros/random.h> #include <ouroboros/rib.h> -#include <ouroboros/time_utils.h> +#include <ouroboros/time.h> -#include "addr_auth.h" -#include "connmgr.h" +#include "common/connmgr.h" +#include "common/enroll.h" +#include "addr-auth.h" +#include "ca.h" #include "dir.h" #include "dt.h" -#include "enroll.h" #include "fa.h" #include "ipcp.h" @@ -53,22 +55,17 @@ #include <assert.h> #include <inttypes.h> -#define THIS_TYPE IPCP_UNICAST +struct ipcp ipcpi; 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; + strcpy(ipcpi.layer_name, conf->layer_info.name); + ipcpi.dir_hash_algo = (enum 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)) { + if (addr_auth_init(conf->unicast.addr_auth_type, + &conf->unicast.dt.addr_size)) { log_err("Failed to init address authority."); goto fail_addr_auth; } @@ -79,12 +76,14 @@ static int initialize_components(const struct ipcp_config * conf) goto fail_addr_auth; } - log_dbg("IPCP got address %" PRIu64 ".", ipcpi.dt_addr); + log_info("IPCP got address %" PRIu64 ".", ipcpi.dt_addr); + + if (ca_init(conf->unicast.cong_avoid)) { + log_err("Failed to initialize congestion avoidance."); + goto fail_ca; + } - if (dt_init(conf->routing_type, - conf->addr_size, - conf->eid_size, - conf->max_ttl)) { + if (dt_init(conf->unicast.dt)) { log_err("Failed to initialize data transfer component."); goto fail_dt; } @@ -108,10 +107,10 @@ static int initialize_components(const struct ipcp_config * conf) fail_fa: dt_fini(); fail_dt: + ca_fini(); + fail_ca: addr_auth_fini(); fail_addr_auth: - free(ipcpi.layer_name); - fail_layer_name: return -1; } @@ -123,28 +122,29 @@ static void finalize_components(void) dt_fini(); - addr_auth_fini(); + ca_fini(); - free(ipcpi.layer_name); + addr_auth_fini(); } static int start_components(void) { - assert(ipcp_get_state() == IPCP_INIT); - - ipcp_set_state(IPCP_OPERATIONAL); + if (dt_start() < 0) { + log_err("Failed to start data transfer."); + goto fail_dt_start; + } - if (fa_start()) { + if (fa_start() < 0) { log_err("Failed to start flow allocator."); goto fail_fa_start; } - if (enroll_start()) { + if (enroll_start() < 0) { log_err("Failed to start enrollment."); goto fail_enroll_start; } - if (connmgr_start()) { + if (connmgr_start() < 0) { log_err("Failed to start AP connection manager."); goto fail_connmgr_start; } @@ -156,21 +156,22 @@ static int start_components(void) fail_enroll_start: fa_stop(); fail_fa_start: + dt_stop(); + fail_dt_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(); + dt_stop(); + ipcp_set_state(IPCP_INIT); } @@ -178,7 +179,6 @@ static int bootstrap_components(void) { if (dir_bootstrap()) { log_err("Failed to bootstrap directory."); - dt_stop(); return -1; } @@ -189,53 +189,54 @@ static int unicast_ipcp_enroll(const char * dst, struct layer_info * info) { struct conn conn; + uint8_t id[ENROLL_ID_LEN]; - if (connmgr_alloc(COMPID_ENROLL, dst, NULL, &conn)) { - log_err("Failed to get connection."); - goto fail_er_flow; + if (random_buffer(id, ENROLL_ID_LEN) < 0) { + log_err("Failed to generate enrollment ID."); + goto fail_id; } - /* Get boot state from peer. */ - if (enroll_boot(&conn)) { - log_err("Failed to get boot information."); - goto fail_enroll_boot; + log_info_id(id, "Requesting enrollment."); + + if (connmgr_alloc(COMPID_ENROLL, dst, NULL, &conn) < 0) { + log_err_id(id, "Failed to get connection."); + goto fail_id; } - if (initialize_components(enroll_get_conf())) { - log_err("Failed to initialize IPCP components."); + /* Get boot state from peer. */ + if (enroll_boot(&conn, id) < 0) { + log_err_id(id, "Failed to get boot information."); goto fail_enroll_boot; } - if (dt_start()) { - log_err("Failed to initialize IPCP components."); - goto fail_dt_start; + if (initialize_components(enroll_get_conf()) < 0) { + log_err_id(id, "Failed to initialize components."); + goto fail_enroll_boot; } - if (start_components()) { - log_err("Failed to start components."); + if (start_components() < 0) { + log_err_id(id, "Failed to start components."); goto fail_start_comp; } - if (enroll_done(&conn, 0)) - log_warn("Failed to confirm enrollment with peer."); + if (enroll_ack(&conn, id, 0) < 0) + log_err_id(id, "Failed to confirm enrollment."); - if (connmgr_dealloc(COMPID_ENROLL, &conn)) - log_warn("Failed to deallocate enrollment flow."); + if (connmgr_dealloc(COMPID_ENROLL, &conn) < 0) + log_warn_id(id, "Failed to dealloc enrollment flow."); - log_info("Enrolled with %s.", dst); + log_info_id(id, "Enrolled with %s.", dst); - info->dir_hash_algo = ipcpi.dir_hash_algo; - strcpy(info->layer_name, ipcpi.layer_name); + info->dir_hash_algo = (enum pol_dir_hash) ipcpi.dir_hash_algo; + strcpy(info->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: + fail_id: return -1; } @@ -246,35 +247,26 @@ static int unicast_ipcp_bootstrap(const struct ipcp_config * conf) enroll_bootstrap(conf); - if (initialize_components(conf)) { + if (initialize_components(conf) < 0) { 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()) { + if (start_components() < 0) { log_err("Failed to init IPCP components."); goto fail_start; } - if (bootstrap_components()) { + if (bootstrap_components() < 0) { 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; @@ -302,76 +294,58 @@ static struct ipcp_ops unicast_ops = { int main(int argc, char * argv[]) { - if (ipcp_init(argc, argv, &unicast_ops) < 0) { + if (ipcp_init(argc, argv, &unicast_ops, THIS_TYPE) < 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()) { + if (notifier_init() < 0) { log_err("Failed to initialize notifier component."); goto fail_notifier_init; } - if (connmgr_init()) { + if (connmgr_init() < 0) { log_err("Failed to initialize connection manager."); goto fail_connmgr_init; } - if (enroll_init()) { + if (enroll_init() < 0) { 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; + if (ipcp_start() < 0) { + log_err("Failed to start IPCP."); + goto fail_start; } - ipcp_shutdown(); + ipcp_sigwait(); if (ipcp_get_state() == IPCP_SHUTDOWN) { - dt_stop(); stop_components(); finalize_components(); } + ipcp_stop(); + enroll_fini(); connmgr_fini(); notifier_fini(); - rib_fini(); - ipcp_fini(); exit(EXIT_SUCCESS); - fail_create_r: - ipcp_shutdown(); - fail_boot: + fail_start: enroll_fini(); fail_enroll_init: connmgr_fini(); fail_connmgr_init: notifier_fini(); fail_notifier_init: - rib_fini(); - fail_rib_init: - ipcp_fini(); + ipcp_fini(); fail_init: - ipcp_create_r(-1); exit(EXIT_FAILURE); } diff --git a/src/ipcpd/unicast/pff.c b/src/ipcpd/unicast/pff.c index 19432972..9b2aa2b4 100644 --- a/src/ipcpd/unicast/pff.c +++ b/src/ipcpd/unicast/pff.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * PDU Forwarding Function * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -26,14 +26,11 @@ #include <ouroboros/logs.h> #include "pff.h" -#include "pol-pff-ops.h" -#include "pol/alternate_pff.h" -#include "pol/multipath_pff.h" -#include "pol/simple_pff.h" +#include "pff/pol.h" struct pff { - struct pol_pff_ops * ops; - struct pff_i * pff_i; + struct pff_ops * ops; + struct pff_i * pff_i; }; struct pff * pff_create(enum pol_pff pol) @@ -62,8 +59,10 @@ struct pff * pff_create(enum pol_pff pol) } pff->pff_i = pff->ops->create(); - if (pff->pff_i == NULL) + if (pff->pff_i == NULL) { + log_err("Failed to create PFF instance."); goto err; + } return pff; err: diff --git a/src/ipcpd/unicast/pff.h b/src/ipcpd/unicast/pff.h index 962ae594..f44e5531 100644 --- a/src/ipcpd/unicast/pff.h +++ b/src/ipcpd/unicast/pff.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * PDU Forwarding Function * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 diff --git a/src/ipcpd/unicast/pol/alternate_pff.c b/src/ipcpd/unicast/pff/alternate.c index f26bb047..85e85914 100644 --- a/src/ipcpd/unicast/pol/alternate_pff.c +++ b/src/ipcpd/unicast/pff/alternate.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Policy for PFF with alternate next hops * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -28,7 +28,7 @@ #include <ouroboros/list.h> #include "pft.h" -#include "alternate_pff.h" +#include "alternate.h" #include <string.h> #include <assert.h> @@ -54,7 +54,7 @@ struct pff_i { pthread_rwlock_t lock; }; -struct pol_pff_ops alternate_pff_ops = { +struct pff_ops alternate_pff_ops = { .create = alternate_pff_create, .destroy = alternate_pff_destroy, .lock = alternate_pff_lock, diff --git a/src/ipcpd/unicast/pol/alternate_pff.h b/src/ipcpd/unicast/pff/alternate.h index 5e5fca3d..96207e74 100644 --- a/src/ipcpd/unicast/pol/alternate_pff.h +++ b/src/ipcpd/unicast/pff/alternate.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Policy for PFF with alternate next hops * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -23,7 +23,7 @@ #ifndef OUROBOROS_IPCPD_UNICAST_ALTERNATE_PFF_H #define OUROBOROS_IPCPD_UNICAST_ALTERNATE_PFF_H -#include "pol-pff-ops.h" +#include "ops.h" struct pff_i * alternate_pff_create(void); @@ -56,6 +56,6 @@ int alternate_flow_state_change(struct pff_i * pff_i, int fd, bool up); -struct pol_pff_ops alternate_pff_ops; +extern struct pff_ops alternate_pff_ops; #endif /* OUROBOROS_IPCPD_UNICAST_ALTERNATE_PFF_H */ diff --git a/src/ipcpd/unicast/pol/multipath_pff.c b/src/ipcpd/unicast/pff/multipath.c index 0fe101bc..cbab0f5f 100644 --- a/src/ipcpd/unicast/pol/multipath_pff.c +++ b/src/ipcpd/unicast/pff/multipath.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Policy for PFF supporting multipath routing * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * Nick Aerts <nick.aerts@ugent.be> * * This program is free software; you can redistribute it and/or modify @@ -28,7 +28,7 @@ #include <ouroboros/errno.h> #include "pft.h" -#include "multipath_pff.h" +#include "multipath.h" #include <string.h> #include <assert.h> @@ -39,7 +39,7 @@ struct pff_i { pthread_rwlock_t lock; }; -struct pol_pff_ops multipath_pff_ops = { +struct pff_ops multipath_pff_ops = { .create = multipath_pff_create, .destroy = multipath_pff_destroy, .lock = multipath_pff_lock, @@ -58,21 +58,23 @@ struct pff_i * multipath_pff_create(void) tmp = malloc(sizeof(*tmp)); if (tmp == NULL) - return NULL; + goto fail_malloc; - if (pthread_rwlock_init(&tmp->lock, NULL)) { - free(tmp); - return NULL; - } + if (pthread_rwlock_init(&tmp->lock, NULL)) + goto fail_rwlock; tmp->pft = pft_create(PFT_SIZE, false); - if (tmp->pft == NULL) { - pthread_rwlock_destroy(&tmp->lock); - free(tmp); - return NULL; - } + if (tmp->pft == NULL) + goto fail_pft; return tmp; + + fail_pft: + pthread_rwlock_destroy(&tmp->lock); + fail_rwlock: + free(tmp); + fail_malloc: + return NULL; } void multipath_pff_destroy(struct pff_i * pff_i) @@ -80,8 +82,8 @@ void multipath_pff_destroy(struct pff_i * pff_i) assert(pff_i); pft_destroy(pff_i->pft); - pthread_rwlock_destroy(&pff_i->lock); + free(pff_i); } @@ -177,7 +179,7 @@ int multipath_pff_nhop(struct pff_i * pff_i, assert(pff_i); - pthread_rwlock_rdlock(&pff_i->lock); + pthread_rwlock_wrlock(&pff_i->lock); if (pft_lookup(pff_i->pft, addr, &fds, &len)) { pthread_rwlock_unlock(&pff_i->lock); @@ -189,7 +191,7 @@ int multipath_pff_nhop(struct pff_i * pff_i, assert(len > 0); /* Rotate fds left. */ - memcpy(fds, fds + 1, (len - 1) * sizeof(*fds)); + memmove(fds, fds + 1, (len - 1) * sizeof(*fds)); fds[len - 1] = fd; pthread_rwlock_unlock(&pff_i->lock); diff --git a/src/ipcpd/unicast/pol/multipath_pff.h b/src/ipcpd/unicast/pff/multipath.h index a8ee088f..0eb03476 100644 --- a/src/ipcpd/unicast/pol/multipath_pff.h +++ b/src/ipcpd/unicast/pff/multipath.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Policy for PFF supporting multipath routing * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * Nick Aerts <nick.aerts@ugent.be> * * This program is free software; you can redistribute it and/or modify @@ -24,7 +24,7 @@ #ifndef OUROBOROS_IPCPD_UNICAST_MULTIPATH_PFF_H #define OUROBOROS_IPCPD_UNICAST_MULTIPATH_PFF_H -#include "pol-pff-ops.h" +#include "ops.h" struct pff_i * multipath_pff_create(void); @@ -53,6 +53,6 @@ void multipath_pff_flush(struct pff_i * pff_i); int multipath_pff_nhop(struct pff_i * pff_i, uint64_t addr); -struct pol_pff_ops multipath_pff_ops; +extern struct pff_ops multipath_pff_ops; #endif /* OUROBOROS_IPCPD_UNICAST_MULTIPATH_PFF_H */ diff --git a/src/ipcpd/unicast/pol-pff-ops.h b/src/ipcpd/unicast/pff/ops.h index 9e126cb5..16a31273 100644 --- a/src/ipcpd/unicast/pol-pff-ops.h +++ b/src/ipcpd/unicast/pff/ops.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Pff policy ops * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -20,14 +20,14 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#ifndef OUROBOROS_IPCPD_UNICAST_POL_PFF_OPS_H -#define OUROBOROS_IPCPD_UNICAST_POL_PFF_OPS_H +#ifndef OUROBOROS_IPCPD_UNICAST_PFF_OPS_H +#define OUROBOROS_IPCPD_UNICAST_PFF_OPS_H #include <stdbool.h> struct pff_i; -struct pol_pff_ops { +struct pff_ops { struct pff_i * (* create)(void); void (* destroy)(struct pff_i * pff_i); @@ -60,4 +60,4 @@ struct pol_pff_ops { bool up); }; -#endif /* OUROBOROS_IPCPD_UNICAST_POL_PFF_OPS_H */ +#endif /* OUROBOROS_IPCPD_UNICAST_PFF_OPS_H */ diff --git a/src/ipcpd/unicast/pol/pft.c b/src/ipcpd/unicast/pff/pft.c index 53acc08e..8c436113 100644 --- a/src/ipcpd/unicast/pol/pft.c +++ b/src/ipcpd/unicast/pff/pft.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Packet forwarding table (PFT) with chaining on collisions * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -115,19 +115,11 @@ void pft_flush(struct pft * pft) static uint64_t hash(uint64_t key) { - void * res; - uint64_t ret; - uint8_t keys[4]; + uint64_t res[2]; - memcpy(keys, &key, 4); + mem_hash(HASH_MD5, res, (uint8_t *) &key, sizeof(key)); - mem_hash(HASH_MD5, &res, keys, 4); - - ret = (* (uint64_t *) res); - - free(res); - - return ret; + return res[0]; } static uint64_t calc_key(struct pft * pft, diff --git a/src/ipcpd/unicast/pol/pft.h b/src/ipcpd/unicast/pff/pft.h index aed4dba8..711dabcb 100644 --- a/src/ipcpd/unicast/pol/pft.h +++ b/src/ipcpd/unicast/pff/pft.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Packet forwarding table (PFT) with chaining on collisions * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 diff --git a/src/ipcpd/unicast/pff/pol.h b/src/ipcpd/unicast/pff/pol.h new file mode 100644 index 00000000..245b03c4 --- /dev/null +++ b/src/ipcpd/unicast/pff/pol.h @@ -0,0 +1,25 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * PDU Forwarding Function policies + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * 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/. + */ + +#include "alternate.h" +#include "multipath.h" +#include "simple.h" diff --git a/src/ipcpd/unicast/pol/simple_pff.c b/src/ipcpd/unicast/pff/simple.c index 5bd73d8a..5f95e3ce 100644 --- a/src/ipcpd/unicast/pol/simple_pff.c +++ b/src/ipcpd/unicast/pff/simple.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Simple PDU Forwarding Function * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -27,7 +27,7 @@ #include <ouroboros/errno.h> #include "pft.h" -#include "simple_pff.h" +#include "simple.h" #include <assert.h> #include <pthread.h> @@ -37,7 +37,7 @@ struct pff_i { pthread_rwlock_t lock; }; -struct pol_pff_ops simple_pff_ops = { +struct pff_ops simple_pff_ops = { .create = simple_pff_create, .destroy = simple_pff_destroy, .lock = simple_pff_lock, diff --git a/src/ipcpd/unicast/pol/simple_pff.h b/src/ipcpd/unicast/pff/simple.h index 2dfce45c..0966a186 100644 --- a/src/ipcpd/unicast/pol/simple_pff.h +++ b/src/ipcpd/unicast/pff/simple.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Simple policy for PFF * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -23,7 +23,7 @@ #ifndef OUROBOROS_IPCPD_UNICAST_SIMPLE_PFF_H #define OUROBOROS_IPCPD_UNICAST_SIMPLE_PFF_H -#include "pol-pff-ops.h" +#include "ops.h" struct pff_i * simple_pff_create(void); @@ -52,6 +52,6 @@ void simple_pff_flush(struct pff_i * pff_i); int simple_pff_nhop(struct pff_i * pff_i, uint64_t addr); -struct pol_pff_ops simple_pff_ops; +extern struct pff_ops simple_pff_ops; #endif /* OUROBOROS_IPCPD_UNICAST_SIMPLE_PFF_H */ diff --git a/src/ipcpd/unicast/tests/CMakeLists.txt b/src/ipcpd/unicast/pff/tests/CMakeLists.txt index 482711d5..65705714 100644 --- a/src/ipcpd/unicast/tests/CMakeLists.txt +++ b/src/ipcpd/unicast/pff/tests/CMakeLists.txt @@ -17,19 +17,20 @@ get_filename_component(PARENT_DIR ${PARENT_PATH} NAME) create_test_sourcelist(${PARENT_DIR}_tests test_suite.c # Add new tests here - dht_test.c + pft_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}) +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) +if(CMAKE_VERSION VERSION_LESS "3.29.0") + remove(tests_to_run test_suite.c) +else () + list(POP_FRONT tests_to_run) +endif() foreach (test ${tests_to_run}) get_filename_component(test_name ${test} NAME_WE) diff --git a/src/ipcpd/unicast/pol/tests/pft_test.c b/src/ipcpd/unicast/pff/tests/pft_test.c index 4e23898b..18287fb8 100644 --- a/src/ipcpd/unicast/pol/tests/pft_test.c +++ b/src/ipcpd/unicast/pff/tests/pft_test.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Test of the hash table * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 diff --git a/src/ipcpd/unicast/psched.c b/src/ipcpd/unicast/psched.c index 1ac3fc12..7e12148b 100644 --- a/src/ipcpd/unicast/psched.c +++ b/src/ipcpd/unicast/psched.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Packet scheduler component * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -31,9 +31,9 @@ #include <ouroboros/errno.h> #include <ouroboros/notifier.h> +#include "common/connmgr.h" #include "ipcp.h" #include "psched.h" -#include "connmgr.h" #include <assert.h> #include <sched.h> @@ -50,6 +50,7 @@ static int qos_prio [] = { struct psched { fset_t * set[QOS_CUBE_MAX]; next_packet_fn_t callback; + read_fn_t read; pthread_t readers[QOS_CUBE_MAX * IPCP_SCHED_THR_MUL]; }; @@ -101,7 +102,7 @@ static void * packet_reader(void * o) notifier_event(NOTIFY_DT_FLOW_UP, &fd); break; case FLOW_PKT: - if (ipcp_flow_read(fd, &sdb)) + if (sched->read(fd, &sdb) < 0) continue; sched->callback(fd, qc, sdb); @@ -117,7 +118,8 @@ static void * packet_reader(void * o) return (void *) 0; } -struct psched * psched_create(next_packet_fn_t callback) +struct psched * psched_create(next_packet_fn_t callback, + read_fn_t read) { struct psched * psched; struct sched_info * infos[QOS_CUBE_MAX * IPCP_SCHED_THR_MUL]; @@ -131,6 +133,7 @@ struct psched * psched_create(next_packet_fn_t callback) goto fail_malloc; psched->callback = callback; + psched->read = read; for (i = 0; i < QOS_CUBE_MAX; ++i) { psched->set[i] = fset_create(); @@ -160,7 +163,7 @@ struct psched * psched_create(next_packet_fn_t callback) 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]); + free(infos[j]); goto fail_infos; } } diff --git a/src/ipcpd/unicast/psched.h b/src/ipcpd/unicast/psched.h index 85f32b9a..831f8084 100644 --- a/src/ipcpd/unicast/psched.h +++ b/src/ipcpd/unicast/psched.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Packet scheduler component * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -30,7 +30,11 @@ 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); +typedef int (* read_fn_t)(int fd, + struct shm_du_buff ** sdb); + +struct psched * psched_create(next_packet_fn_t callback, + read_fn_t read); void psched_destroy(struct psched * psched); diff --git a/src/ipcpd/unicast/routing.c b/src/ipcpd/unicast/routing.c index 0ac43f9f..f5417c24 100644 --- a/src/ipcpd/unicast/routing.c +++ b/src/ipcpd/unicast/routing.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Routing component of the IPCP * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -26,9 +26,9 @@ #include "pff.h" #include "routing.h" -#include "pol/link_state.h" +#include "routing/pol.h" -struct pol_routing_ops * r_ops; +struct routing_ops * r_ops; int routing_init(enum pol_routing pr) { diff --git a/src/ipcpd/unicast/routing.h b/src/ipcpd/unicast/routing.h index 38e875e7..d5d833ae 100644 --- a/src/ipcpd/unicast/routing.h +++ b/src/ipcpd/unicast/routing.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Routing component of the IPCP * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 diff --git a/src/ipcpd/unicast/pol/graph.c b/src/ipcpd/unicast/routing/graph.c index ba2ce553..32f3e6fb 100644 --- a/src/ipcpd/unicast/pol/graph.c +++ b/src/ipcpd/unicast/routing/graph.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Undirected graph structure * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * Nick Aerts <nick.aerts@ugent.be> * * This program is free software; you can redistribute it and/or modify @@ -834,7 +834,7 @@ int graph_routing_table(struct graph * graph, break; default: log_err("Unsupported algorithm."); - goto fail_algo; + goto fail_table; } pthread_mutex_unlock(&graph->lock); @@ -843,8 +843,6 @@ int graph_routing_table(struct graph * graph, return 0; - fail_algo: - free(s_dist); fail_table: pthread_mutex_unlock(&graph->lock); return -1; diff --git a/src/ipcpd/unicast/pol/graph.h b/src/ipcpd/unicast/routing/graph.h index 473a5163..8190cc6c 100644 --- a/src/ipcpd/unicast/pol/graph.h +++ b/src/ipcpd/unicast/routing/graph.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Undirected graph structure * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 diff --git a/src/ipcpd/unicast/pol/link_state.c b/src/ipcpd/unicast/routing/link-state.c index d9482876..57c0c7cb 100644 --- a/src/ipcpd/unicast/pol/link_state.c +++ b/src/ipcpd/unicast/routing/link-state.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Link state routing policy * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -38,21 +38,21 @@ #include <ouroboros/list.h> #include <ouroboros/logs.h> #include <ouroboros/notifier.h> +#include <ouroboros/pthread.h> #include <ouroboros/rib.h> #include <ouroboros/utils.h> -#include "comp.h" -#include "connmgr.h" +#include "common/comp.h" +#include "common/connmgr.h" #include "graph.h" #include "ipcp.h" -#include "link_state.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 @@ -127,7 +127,7 @@ struct { enum routing_algo routing_algo; } ls; -struct pol_routing_ops link_state_ops = { +struct routing_ops link_state_ops = { .init = link_state_init, .fini = link_state_fini, .routing_i_create = link_state_routing_i_create, @@ -179,53 +179,56 @@ static struct adjacency * get_adj(const char * path) return NULL; } -static int lsdb_getattr(const char * path, - struct stat * st) +static int lsdb_rib_getattr(const char * path, + struct rib_attr * attr) { struct adjacency * adj; struct timespec now; + char * entry; assert(path); - assert(st); + assert(attr); + + entry = strstr(path, RIB_SEPARATOR) + 1; + assert(entry); clock_gettime(CLOCK_REALTIME_COARSE, &now); pthread_rwlock_rdlock(&ls.db_lock); - adj = get_adj(path); + adj = get_adj(entry); if (adj != NULL) { - st->st_mtime = adj->stamp; - st->st_size = LS_ENTRY_SIZE; + attr->mtime = adj->stamp; + attr->size = LS_ENTRY_SIZE; } else { - st->st_mtime = now.tv_sec; - st->st_size = 0; + attr->mtime = now.tv_sec; + attr->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) +static int lsdb_rib_read(const char * path, + char * buf, + size_t len) { struct adjacency * a; + char * entry; int size; assert(path); + entry = strstr(path, RIB_SEPARATOR) + 1; + assert(entry); + pthread_rwlock_rdlock(&ls.db_lock); if (ls.db_len + ls.nbs_len == 0) goto fail; - a = get_adj(path); + a = get_adj(entry); if (a == NULL) goto fail; @@ -241,7 +244,7 @@ static int lsdb_read(const char * path, return -1; } -static int lsdb_readdir(char *** buf) +static int lsdb_rib_readdir(char *** buf) { struct list_head * p; char entry[RIB_PATH_LEN + 1]; @@ -270,7 +273,7 @@ static int lsdb_readdir(char *** buf) if ((*buf)[idx] == NULL) { while (idx-- > 0) free((*buf)[idx]); - free(buf); + free(*buf); pthread_rwlock_unlock(&ls.db_lock); return -ENOMEM; } @@ -304,9 +307,9 @@ static int lsdb_readdir(char *** buf) } static struct rib_ops r_ops = { - .read = lsdb_read, - .readdir = lsdb_readdir, - .getattr = lsdb_getattr + .read = lsdb_rib_read, + .readdir = lsdb_rib_readdir, + .getattr = lsdb_rib_getattr }; static int lsdb_add_nb(uint64_t addr, @@ -648,8 +651,7 @@ static void * lsupdate(void * o) pthread_rwlock_wrlock(&ls.db_lock); - pthread_cleanup_push((void (*) (void *)) pthread_rwlock_unlock, - (void *) &ls.db_lock); + pthread_cleanup_push(__cleanup_rwlock_unlock, &ls.db_lock); list_for_each_safe(p, h, &ls.db) { struct adjacency * adj; @@ -709,8 +711,7 @@ static void forward_lsm(uint8_t * buf, pthread_rwlock_rdlock(&ls.db_lock); - pthread_cleanup_push((void (*))(void *) pthread_rwlock_unlock, - &ls.db_lock); + pthread_cleanup_push(__cleanup_rwlock_unlock, &ls.db_lock); list_for_each(p, &ls.nbs) { struct nb * nb = list_entry(p, struct nb, next); @@ -721,6 +722,11 @@ static void forward_lsm(uint8_t * buf, pthread_cleanup_pop(true); } +static void cleanup_fqueue(void * fq) +{ + fqueue_destroy((fqueue_t *) fq); +} + static void * lsreader(void * o) { fqueue_t * fq; @@ -739,8 +745,7 @@ static void * lsreader(void * o) if (fq == NULL) return (void *) -1; - pthread_cleanup_push((void (*) (void *)) fqueue_destroy, - (void *) fq); + pthread_cleanup_push(cleanup_fqueue, fq); while (true) { ret = fevent(ls.mgmt_set, fq, NULL); @@ -812,8 +817,11 @@ static void handle_event(void * self, switch (event) { case NOTIFY_DT_CONN_ADD: pthread_rwlock_rdlock(&ls.db_lock); + + pthread_cleanup_push(__cleanup_rwlock_unlock, &ls.db_lock); + send_lsm(ipcpi.dt_addr, c->conn_info.addr, 0); - pthread_rwlock_unlock(&ls.db_lock); + pthread_cleanup_pop(true); if (lsdb_add_nb(c->conn_info.addr, c->flow_info.fd, NB_DT)) log_dbg("Failed to add neighbor to LSDB."); diff --git a/src/ipcpd/unicast/pol/link_state.h b/src/ipcpd/unicast/routing/link-state.h index 9d4858e1..d77d72df 100644 --- a/src/ipcpd/unicast/pol/link_state.h +++ b/src/ipcpd/unicast/routing/link-state.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Link state routing policy * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -26,7 +26,7 @@ #define LS_COMP "Management" #define LS_PROTO "LSP" -#include "pol-routing-ops.h" +#include "ops.h" int link_state_init(enum pol_routing pr); @@ -36,6 +36,6 @@ 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; +extern struct routing_ops link_state_ops; #endif /* OUROBOROS_IPCPD_UNICAST_POL_LINK_STATE_H */ diff --git a/src/ipcpd/unicast/pol-routing-ops.h b/src/ipcpd/unicast/routing/ops.h index 3fa1d573..8a79b7ec 100644 --- a/src/ipcpd/unicast/pol-routing-ops.h +++ b/src/ipcpd/unicast/routing/ops.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Routing policy ops * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 @@ -20,12 +20,12 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#ifndef OUROBOROS_IPCPD_UNICAST_POL_ROUTING_OPS_H -#define OUROBOROS_IPCPD_UNICAST_POL_ROUTING_OPS_H +#ifndef OUROBOROS_IPCPD_UNICAST_ROUTING_OPS_H +#define OUROBOROS_IPCPD_UNICAST_ROUTING_OPS_H #include "pff.h" -struct pol_routing_ops { +struct routing_ops { int (* init)(enum pol_routing pr); void (* fini)(void); @@ -35,4 +35,4 @@ struct pol_routing_ops { void (* routing_i_destroy)(struct routing_i * instance); }; -#endif /* OUROBOROS_IPCPD_UNICAST_POL_ROUTING_OPS_H */ +#endif /* OUROBOROS_IPCPD_UNICAST_ROUTING_OPS_H */ diff --git a/src/ipcpd/unicast/routing/pol.h b/src/ipcpd/unicast/routing/pol.h new file mode 100644 index 00000000..b6a6f150 --- /dev/null +++ b/src/ipcpd/unicast/routing/pol.h @@ -0,0 +1,23 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Routing policies + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * 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/. + */ + +#include "link-state.h" diff --git a/src/ipcpd/unicast/pol/tests/CMakeLists.txt b/src/ipcpd/unicast/routing/tests/CMakeLists.txt index 34d80e8d..9d24bf03 100644 --- a/src/ipcpd/unicast/pol/tests/CMakeLists.txt +++ b/src/ipcpd/unicast/routing/tests/CMakeLists.txt @@ -18,7 +18,6 @@ get_filename_component(PARENT_DIR ${PARENT_PATH} NAME) create_test_sourcelist(${PARENT_DIR}_tests test_suite.c # Add new tests here graph_test.c - pft_test.c ) add_executable(${PARENT_DIR}_test EXCLUDE_FROM_ALL ${${PARENT_DIR}_tests}) @@ -27,7 +26,11 @@ 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) +if(CMAKE_VERSION VERSION_LESS "3.29.0") + remove(tests_to_run test_suite.c) +else () + list(POP_FRONT tests_to_run) +endif() foreach (test ${tests_to_run}) get_filename_component(test_name ${test} NAME_WE) diff --git a/src/ipcpd/unicast/pol/tests/graph_test.c b/src/ipcpd/unicast/routing/tests/graph_test.c index ea4c0e59..d805640c 100644 --- a/src/ipcpd/unicast/pol/tests/graph_test.c +++ b/src/ipcpd/unicast/routing/tests/graph_test.c @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2024 * * Test of the graph structure * - * Dimitri Staessens <dimitri.staessens@ugent.be> - * Sander Vrijders <sander.vrijders@ugent.be> + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> * * 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 |