From a6309410ffb6b4531044c3b52cb6a79cfdcde231 Mon Sep 17 00:00:00 2001 From: dimitri staessens Date: Fri, 10 Feb 2017 20:54:38 +0100 Subject: include: Add header for endianness This adds a header for dealing with endianness in ouroboros. It is extracted from the byte_order header in the library (which now includes this header). It also exposes the functions ntohl, ntohll, htonl and htonll, necessary for converting 32 and 64 bit values for storage and retrieval from the RIB (which should store multi-byte values in network byte order). --- include/ouroboros/CMakeLists.txt | 1 + include/ouroboros/endian.h | 154 +++++++++++++++++++++++++++++++++++++++ src/lib/byte_order.h | 89 +--------------------- 3 files changed, 156 insertions(+), 88 deletions(-) create mode 100644 include/ouroboros/endian.h diff --git a/include/ouroboros/CMakeLists.txt b/include/ouroboros/CMakeLists.txt index 41feb65e..d1a3166c 100644 --- a/include/ouroboros/CMakeLists.txt +++ b/include/ouroboros/CMakeLists.txt @@ -5,6 +5,7 @@ configure_file( set(HEADER_FILES cdap.h dev.h + endian.h errno.h fcntl.h fqueue.h diff --git a/include/ouroboros/endian.h b/include/ouroboros/endian.h new file mode 100644 index 00000000..c6b0d80a --- /dev/null +++ b/include/ouroboros/endian.h @@ -0,0 +1,154 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2017 + * + * Endianness + * + * Dimitri Staessens + * + * This implementation is adapted and redistributed from the RHASH + * project + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +/* + * byte_order.h - byte order related platform dependent routines, + * + * Copyright: 2008-2012 Aleksey Kravchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so. + * + * 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. Use this program at your own risk! + */ + +#ifndef OUROBOROS_ENDIAN_H +#define OUROBOROS_ENDIAN_H + +#include +#include +#include + +#ifdef __GLIBC__ +#include +#elif defined(__FreeBSD__) +#include +#endif + +/* if x86 compatible cpu */ +#if defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(__pentium__) || \ + defined(__pentiumpro__) || defined(__pentium4__) || \ + defined(__nocona__) || defined(prescott) || defined(__core2__) || \ + defined(__k6__) || defined(__k8__) || defined(__athlon__) || \ + defined(__amd64) || defined(__amd64__) || \ + defined(__x86_64) || defined(__x86_64__) || defined(_M_IX86) || \ + defined(_M_AMD64) || defined(_M_IA64) || defined(_M_X64) +/* detect if x86-64 instruction set is supported */ +# if defined(_LP64) || defined(__LP64__) || defined(__x86_64) || \ + defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64) +# define CPU_X64 +# else +# define CPU_IA32 +# endif +#endif + +/* detect CPU endianness */ +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ + __BYTE_ORDER == __LITTLE_ENDIAN) || \ + defined(CPU_IA32) || defined(CPU_X64) || \ + defined(__ia64) || defined(__ia64__) || defined(__alpha__) || \ + defined(_M_ALPHA) || defined(vax) || defined(MIPSEL) || \ + defined(_ARM_) || defined(__arm__) +#define CPU_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 0 +#define IS_LITTLE_ENDIAN 1 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ + __BYTE_ORDER == __BIG_ENDIAN) || \ + defined(__sparc) || defined(__sparc__) || defined(sparc) || \ + defined(_ARCH_PPC) || defined(_ARCH_PPC64) || defined(_POWER) || \ + defined(__POWERPC__) || defined(POWERPC) || defined(__powerpc) || \ + defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || \ + defined(__hpux) || defined(_MIPSEB) || defined(mc68000) || \ + defined(__s390__) || defined(__s390x__) || defined(sel) +#define CPU_BIG_ENDIAN +#define IS_BIG_ENDIAN 1 +#define IS_LITTLE_ENDIAN 0 +#else +# error "Can't detect CPU architecture." +#endif + +#if defined(__GNUC__) && (__GNUC__ >= 4) && \ + (__GNUC__ > 4 || __GNUC_MINOR__ >= 3) +/* for GCC >= 4.3 */ +#define bswap_32(x) __builtin_bswap32(x) +#elif !defined(__STRICT_ANSI__) +/* general bswap_32 definition */ +static inline uint32_t bswap_32(uint32_t x) { + x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0x00FF00FF); + return (x >> 16) | (x << 16); +} +#else +#define bswap_32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) +#endif /* bswap_32 */ + +#if defined(__GNUC__) && (__GNUC__ >= 4) && \ + (__GNUC__ > 4 || __GNUC_MINOR__ >= 3) +#define bswap_64(x) __builtin_bswap64(x) +#elif !defined (bswap64) +#if !defined(__STRICT_ANSI__) +static inline uint64_t bswap_64(uint64_t x) { + union { + uint64_t ll; + uint32_t l[2]; + } w, r; + w.ll = x; + r.l[0] = bswap_32(w.l[1]); + r.l[1] = bswap_32(w.l[0]); + return r.ll; +} +#else +#error "bswap_64 unsupported" +#endif +#endif + +#ifdef CPU_LITTLE_ENDIAN +#define htonll(x) bswap_64(x) +#ifndef htonl +#define htonl(x) bswap_32(x) +#endif +#define ntohll(x) bswap_64(x) +#ifndef ntohl +#define ntohl(x) bswap_32(x) +#endif +#else /* CPU_LITTLE_ENDIAN */ +#define htonll(x) (x) +#ifndef htonl +#define htonl(x) (x) +#endif +#define ntohll(x) (x) +#ifndef ntohl +#define nothl(x) (x) +#endif +#endif /* CPU_LITTLE_ENDIAN */ + +#endif /* OUROBOROS_ENDIAN_H */ diff --git a/src/lib/byte_order.h b/src/lib/byte_order.h index 364b06cc..a0c72cf5 100644 --- a/src/lib/byte_order.h +++ b/src/lib/byte_order.h @@ -40,62 +40,10 @@ * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! */ -/* byte_order.h */ #ifndef OUROBOROS_BYTE_ORDER_H #define OUROBOROS_BYTE_ORDER_H -#include -#include -#include - -#ifdef __GLIBC__ -#include -#elif defined(__FreeBSD__) -#include -#endif - -/* if x86 compatible cpu */ -#if defined(i386) || defined(__i386__) || defined(__i486__) || \ - defined(__i586__) || defined(__i686__) || defined(__pentium__) || \ - defined(__pentiumpro__) || defined(__pentium4__) || \ - defined(__nocona__) || defined(prescott) || defined(__core2__) || \ - defined(__k6__) || defined(__k8__) || defined(__athlon__) || \ - defined(__amd64) || defined(__amd64__) || \ - defined(__x86_64) || defined(__x86_64__) || defined(_M_IX86) || \ - defined(_M_AMD64) || defined(_M_IA64) || defined(_M_X64) -/* detect if x86-64 instruction set is supported */ -# if defined(_LP64) || defined(__LP64__) || defined(__x86_64) || \ - defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64) -# define CPU_X64 -# else -# define CPU_IA32 -# endif -#endif - -/* detect CPU endianness */ -#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ - __BYTE_ORDER == __LITTLE_ENDIAN) || \ - defined(CPU_IA32) || defined(CPU_X64) || \ - defined(__ia64) || defined(__ia64__) || defined(__alpha__) || \ - defined(_M_ALPHA) || defined(vax) || defined(MIPSEL) || \ - defined(_ARM_) || defined(__arm__) -#define CPU_LITTLE_ENDIAN -#define IS_BIG_ENDIAN 0 -#define IS_LITTLE_ENDIAN 1 -#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ - __BYTE_ORDER == __BIG_ENDIAN) || \ - defined(__sparc) || defined(__sparc__) || defined(sparc) || \ - defined(_ARCH_PPC) || defined(_ARCH_PPC64) || defined(_POWER) || \ - defined(__POWERPC__) || defined(POWERPC) || defined(__powerpc) || \ - defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || \ - defined(__hpux) || defined(_MIPSEB) || defined(mc68000) || \ - defined(__s390__) || defined(__s390x__) || defined(sel) -#define CPU_BIG_ENDIAN -#define IS_BIG_ENDIAN 1 -#define IS_LITTLE_ENDIAN 0 -#else -# error "Can't detect CPU architecture." -#endif +#include #define IS_ALIGNED_32(p) (0 == (3 & ((const char*)(p) - (const char*)0))) #define IS_ALIGNED_64(p) (0 == (7 & ((const char*)(p) - (const char*)0))) @@ -115,41 +63,6 @@ unsigned rhash_ctz(unsigned); /* define as function */ #endif -#if defined(__GNUC__) && (__GNUC__ >= 4) && \ - (__GNUC__ > 4 || __GNUC_MINOR__ >= 3) -/* for GCC >= 4.3 */ -#define bswap_32(x) __builtin_bswap32(x) -#elif !defined(__STRICT_ANSI__) -/* general bswap_32 definition */ -static inline uint32_t bswap_32(uint32_t x) { - x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0x00FF00FF); - return (x >> 16) | (x << 16); -} -#else -#define bswap_32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ - (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) -#endif /* bswap_32 */ - -#if defined(__GNUC__) && (__GNUC__ >= 4) && \ - (__GNUC__ > 4 || __GNUC_MINOR__ >= 3) -#define bswap_64(x) __builtin_bswap64(x) -#elif !defined (bswap64) -#if !defined(__STRICT_ANSI__) -static inline uint64_t bswap_64(uint64_t x) { - union { - uint64_t ll; - uint32_t l[2]; - } w, r; - w.ll = x; - r.l[0] = bswap_32(w.l[1]); - r.l[1] = bswap_32(w.l[0]); - return r.ll; -} -#else -#error "bswap_64 unsupported" -#endif -#endif - #ifdef CPU_BIG_ENDIAN #define be2me_32(x) (x) #define be2me_64(x) (x) -- cgit v1.2.3 From f87a2bc5199104d87ccc48dcc2b0e18d345a9bb4 Mon Sep 17 00:00:00 2001 From: dimitri staessens Date: Fri, 10 Feb 2017 23:40:34 +0100 Subject: ipcpd: Silent shutdown of normal The acceptor will not log disconnects with IRMd. Unexpected disconnects will be reported and handled by management components. --- src/ipcpd/normal/main.c | 5 +++-- src/irmd/main.c | 2 +- src/lib/dev.c | 5 +++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/ipcpd/normal/main.c b/src/ipcpd/normal/main.c index 81912614..11ec0938 100644 --- a/src/ipcpd/normal/main.c +++ b/src/ipcpd/normal/main.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "addr_auth.h" #include "ae.h" @@ -45,7 +46,6 @@ #include #include #include -#include #include #include @@ -108,7 +108,8 @@ static void * flow_acceptor(void * o) fd = flow_accept(&ae_name, &qs); if (fd < 0) { - log_warn("Flow accept failed."); + if (fd != -EIRMD) + log_warn("Flow accept failed: %d", fd); continue; } diff --git a/src/irmd/main.c b/src/irmd/main.c index 74cb8359..2454a9ca 100644 --- a/src/irmd/main.c +++ b/src/irmd/main.c @@ -1888,7 +1888,7 @@ void * mainloop(void * o) (qoscube_t *) &ret_msg.qoscube); if (e == NULL) { ret_msg.has_result = true; - ret_msg.result = -1; + ret_msg.result = -EIRMD; break; } ret_msg.has_port_id = true; diff --git a/src/lib/dev.c b/src/lib/dev.c index 38f7cddf..4d85a5d9 100644 --- a/src/lib/dev.c +++ b/src/lib/dev.c @@ -402,6 +402,11 @@ int flow_accept(char ** ae_name, if (recv_msg == NULL) return -EIRMD; + if (recv_msg->has_result) { + irm_msg__free_unpacked(recv_msg, NULL); + return -EIRMD; + } + if (!recv_msg->has_api || !recv_msg->has_port_id) { irm_msg__free_unpacked(recv_msg, NULL); return -1; -- cgit v1.2.3 From 2da76c5db47aeabb91669d6ca9c4da92911fbec9 Mon Sep 17 00:00:00 2001 From: dimitri staessens Date: Fri, 10 Feb 2017 23:56:10 +0100 Subject: cdap: Take void * for send operations This facilitates sending arbitrary variables over CDAP. --- include/ouroboros/cdap.h | 6 +++--- src/lib/cdap.c | 26 +++++++++++++++----------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/include/ouroboros/cdap.h b/include/ouroboros/cdap.h index 23a8a3d6..9f6e2654 100644 --- a/include/ouroboros/cdap.h +++ b/include/ouroboros/cdap.h @@ -52,8 +52,8 @@ int cdap_destroy(struct cdap * instance); cdap_key_t cdap_request_send(struct cdap * instance, enum cdap_opcode code, - char * name, - uint8_t * data, + const char * name, + const void * data, size_t len, uint32_t flags); @@ -72,7 +72,7 @@ cdap_key_t cdap_request_wait(struct cdap * instance, int cdap_reply_send(struct cdap * instance, cdap_key_t key, int result, - uint8_t * data, + const void * data, size_t len); #endif /* OUROBOROS_CDAP_H */ diff --git a/src/lib/cdap.c b/src/lib/cdap.c index 956486d1..6c46775c 100644 --- a/src/lib/cdap.c +++ b/src/lib/cdap.c @@ -67,7 +67,7 @@ struct cdap_rcvd { enum cdap_opcode opcode; char * name; - uint8_t * data; + void * data; size_t len; uint32_t flags; }; @@ -89,7 +89,8 @@ static int next_invoke_id(struct cdap * instance) return ret; } -static int release_invoke_id(struct cdap * instance, int id) +static int release_invoke_id(struct cdap * instance, + int id) { int ret; @@ -130,7 +131,8 @@ static struct cdap_req * cdap_sent_get_by_key(struct cdap * instance, return NULL; } -static struct cdap_req * cdap_sent_add(struct cdap * instance, cdap_key_t key) +static struct cdap_req * cdap_sent_add(struct cdap * instance, + cdap_key_t key) { struct cdap_req * req; @@ -151,7 +153,8 @@ static struct cdap_req * cdap_sent_add(struct cdap * instance, cdap_key_t key) return req; } -static void cdap_sent_del(struct cdap * instance, struct cdap_req * req) +static void cdap_sent_del(struct cdap * instance, + struct cdap_req * req) { assert(instance); assert(req); @@ -405,7 +408,8 @@ int cdap_destroy(struct cdap * instance) return 0; } -static int write_msg(struct cdap * instance, cdap_t * msg) +static int write_msg(struct cdap * instance, + cdap_t * msg) { int ret; uint8_t * data; @@ -449,8 +453,8 @@ static invoke_id_t key_to_invoke_id(cdap_key_t key) cdap_key_t cdap_request_send(struct cdap * instance, enum cdap_opcode code, - char * name, - uint8_t * data, + const char * name, + const void * data, size_t len, uint32_t flags) { @@ -491,13 +495,13 @@ cdap_key_t cdap_request_send(struct cdap * instance, return -EINVAL; } - msg.name = name; + msg.name = (char *) name; msg.has_flags = true; msg.flags = flags; msg.invoke_id = iid; if (data != NULL) { msg.has_value = true; - msg.value.data = data; + msg.value.data = (uint8_t *) data; msg.value.len = len; } @@ -599,7 +603,7 @@ cdap_key_t cdap_request_wait(struct cdap * instance, int cdap_reply_send(struct cdap * instance, cdap_key_t key, int result, - uint8_t * data, + const void * data, size_t len) { cdap_t msg = CDAP__INIT; @@ -615,7 +619,7 @@ int cdap_reply_send(struct cdap * instance, if (data != NULL) { msg.has_value = true; - msg.value.data = data; + msg.value.data = (uint8_t *) data; msg.value.len = len; } -- cgit v1.2.3 From f0ef4bdbf66ed12e52ff33da90d79af0cbc00436 Mon Sep 17 00:00:00 2001 From: dimitri staessens Date: Sat, 11 Feb 2017 00:00:38 +0100 Subject: ipcpd: Compare timestamp upon enrollment The enrollment procedure will ask for a timestamp of the IPCP it is enrolling with. It will (taking into account the RTT of the request) issue a warning if the offset is larger than RIB_WARN_TIME_OFFSET ms. --- include/ouroboros/config.h.in | 10 ++++---- src/ipcpd/normal/enroll.c | 53 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/include/ouroboros/config.h.in b/include/ouroboros/config.h.in index b95fe927..c1b6bd02 100644 --- a/include/ouroboros/config.h.in +++ b/include/ouroboros/config.h.in @@ -50,11 +50,9 @@ #define IRMD_THREADPOOL_SIZE 16 #define IPCPD_THREADPOOL_SIZE 3 #define IPCPD_MAX_CONNS IRMD_MAX_FLOWS -#define LOG_DIR "/@LOG_DIR@/" #define PTHREAD_COND_CLOCK CLOCK_MONOTONIC #define PFT_SIZE 1 << 12 /* Timeout values */ -#define SHM_DU_TIMEOUT_MICROS 15000 #define IRMD_ACCEPT_TIMEOUT 100 #define IRMD_FLOW_TIMEOUT 5000 #define IPCP_ACCEPT_TIMEOUT 100 @@ -63,9 +61,9 @@ #define ENROLL_TIMEOUT 2000 /* RIB configuration for normal */ #define RIB_MAX_PATH_LEN 256 -#define BOOT_NAME "boot" -#define MEMBERS_NAME "members" -#define DIF_NAME "dif_name" -#define DIR_NAME "directory" +#define BOOT_NAME "boot" +#define MEMBERS_NAME "members" +#define DIF_NAME "dif_name" +#define DIR_NAME "directory" #endif /* OUROBOROS_CONFIG */ diff --git a/src/ipcpd/normal/enroll.c b/src/ipcpd/normal/enroll.c index 16bfc592..cea33bf2 100644 --- a/src/ipcpd/normal/enroll.c +++ b/src/ipcpd/normal/enroll.c @@ -21,10 +21,12 @@ #define OUROBOROS_PREFIX "enrollment" #include +#include #include #include #include #include +#include #include "ae.h" @@ -32,10 +34,15 @@ #include #include +/* Symbolic, will return current time */ +#define TIME_NAME "localtime" +#define ENROLL_WARN_TIME_OFFSET 20 + #define DLR "/" #define DIF_PATH DLR DIF_NAME #define BOOT_PATH DLR BOOT_NAME #define MEMBERS_PATH DLR MEMBERS_NAME +#define TIME_PATH DLR TIME_NAME int enroll_handle(int fd) { @@ -72,7 +79,6 @@ int enroll_handle(int fd) while (!(boot_r && members_r && dif_name_r)) { key = cdap_request_wait(ci, &oc, &name, &data, (size_t *) &len , &flags); - assert(key >= 0); assert(name); @@ -96,6 +102,15 @@ int enroll_handle(int fd) members_r = true; } else if (strcmp(name, dif_ro) == 0) { dif_name_r = true; + } else if (strcmp(name, TIME_PATH) == 0) { + struct timespec t; + uint64_t buf[2]; + clock_gettime(CLOCK_REALTIME, &t); + buf[0] = htonll(t.tv_sec); + buf[1] = htonll(t.tv_nsec); + cdap_reply_send(ci, key, 0, buf, sizeof(buf)); + free(name); + continue; } else { log_warn("Illegal read: %s.", name); cdap_reply_send(ci, key, -1, NULL, 0); @@ -146,6 +161,11 @@ int enroll_boot(char * dst_name) size_t len; int fd; + struct timespec t0; + struct timespec rtt; + + ssize_t delta_t; + char * boot_ro = BOOT_PATH; char * members_ro = MEMBERS_PATH; char * dif_ro = DIF_PATH; @@ -171,6 +191,37 @@ int enroll_boot(char * dst_name) log_dbg("Getting boot information from %s.", dst_name); + clock_gettime(CLOCK_REALTIME, &t0); + + key = cdap_request_send(ci, CDAP_READ, TIME_PATH, NULL, 0, 0); + if (key < 0) { + log_err("Failed to send CDAP request."); + cdap_destroy(ci); + flow_dealloc(fd); + return -1; + } + + if (cdap_reply_wait(ci, key, &data, &len)) { + log_err("Failed to get CDAP reply."); + cdap_destroy(ci); + flow_dealloc(fd); + return -1; + } + + clock_gettime(CLOCK_REALTIME, &rtt); + + delta_t = ts_diff_ms(&t0, &rtt); + + assert (len == 2 * sizeof (uint64_t)); + + rtt.tv_sec = ntohll(((uint64_t *) data)[0]); + rtt.tv_nsec = ntohll(((uint64_t *) data)[1]); + + if (abs(ts_diff_ms(&t0, &rtt)) - delta_t > ENROLL_WARN_TIME_OFFSET) + log_warn("Clock offset above threshold."); + + free(data); + key = cdap_request_send(ci, CDAP_READ, boot_ro, NULL, 0, 0); if (key < 0) { log_err("Failed to send CDAP request."); -- cgit v1.2.3 From 2ee140ec27335ca50e813080ee0e85e4ab86af37 Mon Sep 17 00:00:00 2001 From: dimitri staessens Date: Sat, 11 Feb 2017 17:04:27 +0100 Subject: ipcpd: Prevent access to directory before init Doing a directory query before the IPCP is has bootstrapped or is enrolled will result in an assertion failure as the directory is not yet ready. This fixes flow allocation over the LLC shim (which triggers a directory query from the IRMd) with a normal IPCP present. --- src/ipcpd/normal/dir.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/ipcpd/normal/dir.c b/src/ipcpd/normal/dir.c index d30b9ec0..703f4e79 100644 --- a/src/ipcpd/normal/dir.c +++ b/src/ipcpd/normal/dir.c @@ -31,21 +31,22 @@ #include #include +#define DIR_PATH "/" DIR_NAME + static char dir_path[RIB_MAX_PATH_LEN + 1]; static void dir_path_reset(void) { - dir_path[strlen("/" DIR_NAME)]= '\0'; - assert(strcmp("/" DIR_NAME, dir_path) == 0); + dir_path[strlen(DIR_PATH)]= '\0'; + assert(strcmp(DIR_PATH, dir_path) == 0); } int dir_init(void) { /*FIXME: set ribmgr dissemination here */ - if (rib_add(RIB_ROOT, DIR_NAME)) return -1; - strcpy(dir_path, "/" DIR_NAME); + strcpy(dir_path, DIR_PATH); return 0; } @@ -66,6 +67,9 @@ int dir_name_reg(char * name) assert(name); + if (ipcp_get_state() != IPCP_OPERATIONAL) + return -EPERM; + dir_path_reset(); ret = rib_add(dir_path, name); @@ -91,6 +95,9 @@ int dir_name_unreg(char * name) assert(name); + if (ipcp_get_state() != IPCP_OPERATIONAL) + return -EPERM; + dir_path_reset(); rib_path_append(dir_path, name); @@ -116,6 +123,9 @@ int dir_name_query(char * name) { size_t len; + if (ipcp_get_state() != IPCP_OPERATIONAL) + return -EPERM; + dir_path_reset(); rib_path_append(dir_path, name); -- cgit v1.2.3 From 98a15feabb6a14e52a54a09dfed58d55e0f99884 Mon Sep 17 00:00:00 2001 From: dimitri staessens Date: Sun, 12 Feb 2017 16:15:46 +0100 Subject: irmd: Allow time for AP to call flow_accept() When there is a burst of successive flow allocations for a certain name, each such request will block a thread in the IRMD for IRMD_REQ_ARR_TIMEOUT ms to allow the application some time to respond. This refactors some parts of the IRMd. --- include/ouroboros/config.h.in | 1 + src/irmd/api_table.c | 15 +++-- src/irmd/main.c | 45 +++++++++------ src/irmd/registry.c | 129 +++++++++++++++++++++++++++++++++++------- src/irmd/registry.h | 11 +++- 5 files changed, 154 insertions(+), 47 deletions(-) diff --git a/include/ouroboros/config.h.in b/include/ouroboros/config.h.in index c1b6bd02..10d78cd0 100644 --- a/include/ouroboros/config.h.in +++ b/include/ouroboros/config.h.in @@ -54,6 +54,7 @@ #define PFT_SIZE 1 << 12 /* Timeout values */ #define IRMD_ACCEPT_TIMEOUT 100 +#define IRMD_REQ_ARR_TIMEOUT 200 #define IRMD_FLOW_TIMEOUT 5000 #define IPCP_ACCEPT_TIMEOUT 100 #define SOCKET_TIMEOUT 4000 diff --git a/src/irmd/api_table.c b/src/irmd/api_table.c index 7619fcf6..df300cea 100644 --- a/src/irmd/api_table.c +++ b/src/irmd/api_table.c @@ -159,16 +159,15 @@ int api_entry_sleep(struct api_entry * e) e->state = API_SLEEP; - while (e->state == API_SLEEP) { - if ((ret = -pthread_cond_timedwait(&e->state_cond, - &e->state_lock, - &dl)) == -ETIMEDOUT) { - break; - } - } + while (e->state == API_SLEEP && ret != -ETIMEDOUT) + ret = -pthread_cond_timedwait(&e->state_cond, + &e->state_lock, + &dl); - if (e->state == API_DESTROY) + if (e->state == API_DESTROY) { + reg_entry_del_api(e->re, e->api); ret = -1; + } e->state = API_INIT; pthread_cond_broadcast(&e->state_cond); diff --git a/src/irmd/main.c b/src/irmd/main.c index 2454a9ca..aa4614c1 100644 --- a/src/irmd/main.c +++ b/src/irmd/main.c @@ -970,7 +970,6 @@ static struct irm_flow * flow_accept(pid_t api, log_err("Unknown instance %d calling accept.", api); return NULL; } - log_dbg("New instance (%d) of %s added.", api, e->apn); log_dbg("This instance accepts flows for:"); list_for_each(p, &e->names) { @@ -996,6 +995,7 @@ static struct irm_flow * flow_accept(pid_t api, pthread_rwlock_rdlock(&irmd->state_lock); if (irmd->state != IRMD_RUNNING) { + reg_entry_set_state(re, REG_NAME_NULL); pthread_rwlock_unlock(&irmd->state_lock); return NULL; } @@ -1331,11 +1331,14 @@ static struct irm_flow * flow_req_arr(pid_t api, pid_t h_api = -1; int port_id = -1; + struct timespec wt = {IRMD_REQ_ARR_TIMEOUT % 1000, + (IRMD_REQ_ARR_TIMEOUT % 1000) * MILLION}; + log_dbg("Flow req arrived from IPCP %d for %s on AE %s.", api, dst_name, ae_name); pthread_rwlock_rdlock(&irmd->state_lock); - pthread_rwlock_wrlock(&irmd->reg_lock); + pthread_rwlock_rdlock(&irmd->reg_lock); re = registry_get_entry(&irmd->registry, dst_name); if (re == NULL) { @@ -1345,6 +1348,18 @@ static struct irm_flow * flow_req_arr(pid_t api, return NULL; } + pthread_rwlock_unlock(&irmd->reg_lock); + pthread_rwlock_unlock(&irmd->state_lock); + + /* Give the AP a bit of slop time to call accept */ + if (reg_entry_leave_state(re, REG_NAME_IDLE, &wt) == -1) { + log_err("No APs for %s.", dst_name); + return NULL; + } + + pthread_rwlock_rdlock(&irmd->state_lock); + pthread_rwlock_wrlock(&irmd->reg_lock); + switch (reg_entry_get_state(re)) { case REG_NAME_IDLE: pthread_rwlock_unlock(&irmd->reg_lock); @@ -1378,17 +1393,12 @@ static struct irm_flow * flow_req_arr(pid_t api, pthread_rwlock_unlock(&irmd->reg_lock); pthread_rwlock_unlock(&irmd->state_lock); - reg_entry_leave_state(re, REG_NAME_AUTO_EXEC); - - pthread_rwlock_rdlock(&irmd->state_lock); - pthread_rwlock_rdlock(&irmd->reg_lock); - - if (reg_entry_get_state(re) == REG_NAME_DESTROY) { - reg_entry_set_state(re, REG_NAME_NULL); + if (reg_entry_leave_state(re, REG_NAME_AUTO_EXEC, NULL)) { pthread_rwlock_unlock(&irmd->reg_lock); pthread_rwlock_unlock(&irmd->state_lock); return NULL; } + case REG_NAME_FLOW_ACCEPT: h_api = reg_entry_get_api(re); if (h_api == -1) { @@ -1453,7 +1463,7 @@ static struct irm_flow * flow_req_arr(pid_t api, pthread_rwlock_unlock(&irmd->reg_lock); pthread_rwlock_unlock(&irmd->state_lock); - reg_entry_leave_state(re, REG_NAME_FLOW_ARRIVED); + reg_entry_leave_state(re, REG_NAME_FLOW_ARRIVED, NULL); return f; } @@ -1518,10 +1528,16 @@ static void irm_destroy(void) list_del(&e->next); ipcp_destroy(e->api); clear_spawned_api(e->api); + registry_del_api(&irmd->registry, e->api); ipcp_entry_destroy(e); } - registry_destroy(&irmd->registry); + list_for_each_safe(p, h, &irmd->api_table) { + struct api_entry * e = list_entry(p, struct api_entry, next); + list_del(&e->next); + registry_del_api(&irmd->registry, e->api); + api_entry_destroy(e); + } list_for_each_safe(p, h, &irmd->spawned_apis) { struct pid_el * e = list_entry(p, struct pid_el, next); @@ -1531,6 +1547,7 @@ static void irm_destroy(void) else if (waitpid(e->pid, &status, 0) < 0) log_dbg("Error waiting for %d to exit.", e->pid); list_del(&e->next); + registry_del_api(&irmd->registry, e->pid); free(e); } @@ -1540,11 +1557,7 @@ static void irm_destroy(void) apn_entry_destroy(e); } - list_for_each_safe(p, h, &irmd->api_table) { - struct api_entry * e = list_entry(p, struct api_entry, next); - list_del(&e->next); - api_entry_destroy(e); - } + registry_destroy(&irmd->registry); pthread_rwlock_unlock(&irmd->reg_lock); diff --git a/src/irmd/registry.c b/src/irmd/registry.c index d22c1be3..985ecda0 100644 --- a/src/irmd/registry.c +++ b/src/irmd/registry.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "registry.h" #include "utils.h" @@ -60,6 +61,8 @@ static struct reg_entry * reg_entry_create(void) static struct reg_entry * reg_entry_init(struct reg_entry * e, char * name) { + pthread_condattr_t cattr; + if (e == NULL || name == NULL) return NULL; @@ -70,7 +73,13 @@ static struct reg_entry * reg_entry_init(struct reg_entry * e, e->name = name; - if (pthread_cond_init(&e->state_cond, NULL)) + if (pthread_condattr_init(&cattr)) + return NULL; + +#ifdef __APPLE__ + pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK); +#endif + if (pthread_cond_init(&e->state_cond, &cattr)) return NULL; if (pthread_mutex_init(&e->state_lock, NULL)) @@ -91,9 +100,21 @@ static void reg_entry_destroy(struct reg_entry * e) pthread_mutex_lock(&e->state_lock); - e->state = REG_NAME_DESTROY; + if (e->state == REG_NAME_DESTROY) { + pthread_mutex_unlock(&e->state_lock); + return; + } + + if (e->state != REG_NAME_FLOW_ACCEPT) + e->state = REG_NAME_NULL; + else + e->state = REG_NAME_DESTROY; pthread_cond_broadcast(&e->state_cond); + + while (e->state != REG_NAME_NULL) + pthread_cond_wait(&e->state_cond, &e->state_lock); + pthread_mutex_unlock(&e->state_lock); pthread_cond_destroy(&e->state_cond); @@ -102,12 +123,6 @@ static void reg_entry_destroy(struct reg_entry * e) if (e->name != NULL) free(e->name); - list_for_each_safe(p, h, &e->reg_apis) { - struct pid_el * i = list_entry(p, struct pid_el, next); - list_del(&i->next); - free(i); - } - list_for_each_safe(p, h, &e->reg_apns) { struct str_el * a = list_entry(p, struct str_el, next); list_del(&a->next); @@ -171,7 +186,8 @@ static void reg_entry_del_local_from_dif(struct reg_entry * e, } } -static bool reg_entry_has_apn(struct reg_entry * e, char * apn) +static bool reg_entry_has_apn(struct reg_entry * e, + char * apn) { struct list_head * p; @@ -184,7 +200,8 @@ static bool reg_entry_has_apn(struct reg_entry * e, char * apn) return false; } -int reg_entry_add_apn(struct reg_entry * e, struct apn_entry * a) +int reg_entry_add_apn(struct reg_entry * e, + struct apn_entry * a) { struct str_el * n; @@ -215,7 +232,8 @@ int reg_entry_add_apn(struct reg_entry * e, struct apn_entry * a) return 0; } -void reg_entry_del_apn(struct reg_entry * e, char * apn) +void reg_entry_del_apn(struct reg_entry * e, + char * apn) { struct list_head * p = NULL; struct list_head * h = NULL; @@ -244,7 +262,8 @@ char * reg_entry_get_apn(struct reg_entry * e) return list_first_entry(&e->reg_apns, struct str_el, next)->str; } -static bool reg_entry_has_api(struct reg_entry * e, pid_t api) +static bool reg_entry_has_api(struct reg_entry * e, + pid_t api) { struct list_head * p; @@ -257,7 +276,8 @@ static bool reg_entry_has_api(struct reg_entry * e, pid_t api) return false; } -int reg_entry_add_api(struct reg_entry * e, pid_t api) +int reg_entry_add_api(struct reg_entry * e, + pid_t api) { struct pid_el * i; @@ -288,7 +308,7 @@ int reg_entry_add_api(struct reg_entry * e, pid_t api) e->state == REG_NAME_AUTO_ACCEPT || e->state == REG_NAME_AUTO_EXEC) { e->state = REG_NAME_FLOW_ACCEPT; - pthread_cond_signal(&e->state_cond); + pthread_cond_broadcast(&e->state_cond); } pthread_mutex_unlock(&e->state_lock); @@ -298,6 +318,12 @@ int reg_entry_add_api(struct reg_entry * e, pid_t api) static void reg_entry_check_state(struct reg_entry * e) { + if (e->state == REG_NAME_DESTROY) { + e->state = REG_NAME_NULL; + pthread_cond_broadcast(&e->state_cond); + return; + } + if (list_is_empty(&e->reg_apis)) { if (!list_is_empty(&e->reg_apns)) e->state = REG_NAME_AUTO_ACCEPT; @@ -319,7 +345,8 @@ void reg_entry_del_pid_el(struct reg_entry * e, reg_entry_check_state(e); } -void reg_entry_del_api(struct reg_entry * e, pid_t api) +void reg_entry_del_api(struct reg_entry * e, + pid_t api) { struct list_head * p; struct list_head * h; @@ -365,7 +392,8 @@ enum reg_name_state reg_entry_get_state(struct reg_entry * e) return state; } -int reg_entry_set_state(struct reg_entry * e, enum reg_name_state state) +int reg_entry_set_state(struct reg_entry * e, + enum reg_name_state state) { if (state == REG_NAME_DESTROY) return -EPERM; @@ -380,19 +408,80 @@ int reg_entry_set_state(struct reg_entry * e, enum reg_name_state state) return 0; } -int reg_entry_leave_state(struct reg_entry * e, enum reg_name_state state) +int reg_entry_leave_state(struct reg_entry * e, + enum reg_name_state state, + struct timespec * timeout) { + struct timespec abstime; + int ret = 0; + if (e == NULL || state == REG_NAME_DESTROY) return -EINVAL; + if (timeout != NULL) { + clock_gettime(PTHREAD_COND_CLOCK, &abstime); + ts_add(&abstime, timeout, &abstime); + } + pthread_mutex_lock(&e->state_lock); - while (e->state == state) - pthread_cond_wait(&e->state_cond, &e->state_lock); + while (e->state == state && ret != -ETIMEDOUT) + if (timeout) + ret = -pthread_cond_timedwait(&e->state_cond, + &e->state_lock, + timeout); + else + ret = -pthread_cond_wait(&e->state_cond, + &e->state_lock); + + if (e->state == REG_NAME_DESTROY) { + ret = -1; + e->state = REG_NAME_NULL; + pthread_cond_broadcast(&e->state_cond); + } pthread_mutex_unlock(&e->state_lock); - return 0; + return ret; +} + +int reg_entry_wait_state(struct reg_entry * e, + enum reg_name_state state, + struct timespec * timeout) +{ + struct timespec abstime; + int ret = 0; + + if (e == NULL || state == REG_NAME_DESTROY) + return -EINVAL; + + if (timeout != NULL) { + clock_gettime(PTHREAD_COND_CLOCK, &abstime); + ts_add(&abstime, timeout, &abstime); + } + + pthread_mutex_lock(&e->state_lock); + + while (e->state != state && + e->state != REG_NAME_DESTROY && + ret != -ETIMEDOUT) + if (timeout) + ret = -pthread_cond_timedwait(&e->state_cond, + &e->state_lock, + timeout); + else + ret = -pthread_cond_wait(&e->state_cond, + &e->state_lock); + + if (e->state == REG_NAME_DESTROY) { + ret = -1; + e->state = REG_NAME_NULL; + pthread_cond_broadcast(&e->state_cond); + } + + pthread_mutex_unlock(&e->state_lock); + + return ret; } struct reg_entry * registry_get_entry(struct list_head * registry, diff --git a/src/irmd/registry.h b/src/irmd/registry.h index 7713e278..67e4da40 100644 --- a/src/irmd/registry.h +++ b/src/irmd/registry.h @@ -91,11 +91,16 @@ pid_t reg_entry_get_api(struct reg_entry * e); enum reg_name_state reg_entry_get_state(struct reg_entry * e); -int reg_entry_set_state(struct reg_entry * e, +int reg_entry_set_state(struct reg_entry * e, enum reg_name_state state); -int reg_entry_leave_state(struct reg_entry * e, - enum reg_name_state state); +int reg_entry_leave_state(struct reg_entry * e, + enum reg_name_state state, + struct timespec * timeout); + +int reg_entry_wait_state(struct reg_entry * e, + enum reg_name_state state, + struct timespec * timeout); struct reg_entry * registry_add_name(struct list_head * registry, char * name); -- cgit v1.2.3 From cf5087a8397e379d059998b27ef86a1bb68d70ff Mon Sep 17 00:00:00 2001 From: dimitri staessens Date: Sun, 12 Feb 2017 16:40:38 +0100 Subject: include: Use width in endian naming convention ntohll and ntohl have been renamed ntoh64 and ntoh32, htonll and htonl have been renamed hton64 and hton32. --- include/ouroboros/endian.h | 24 ++++++++---------------- src/ipcpd/normal/enroll.c | 8 ++++---- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/include/ouroboros/endian.h b/include/ouroboros/endian.h index c6b0d80a..745f0c57 100644 --- a/include/ouroboros/endian.h +++ b/include/ouroboros/endian.h @@ -132,23 +132,15 @@ static inline uint64_t bswap_64(uint64_t x) { #endif #ifdef CPU_LITTLE_ENDIAN -#define htonll(x) bswap_64(x) -#ifndef htonl -#define htonl(x) bswap_32(x) -#endif -#define ntohll(x) bswap_64(x) -#ifndef ntohl -#define ntohl(x) bswap_32(x) -#endif +#define hton64(x) bswap_64(x) +#define hton32(x) bswap_32(x) +#define ntoh64(x) bswap_64(x) +#define ntoh32(x) bswap_32(x) #else /* CPU_LITTLE_ENDIAN */ -#define htonll(x) (x) -#ifndef htonl -#define htonl(x) (x) -#endif -#define ntohll(x) (x) -#ifndef ntohl -#define nothl(x) (x) -#endif +#define hton64(x) (x) +#define hton32(x) (x) +#define ntoh64(x) (x) +#define noth32(x) (x) #endif /* CPU_LITTLE_ENDIAN */ #endif /* OUROBOROS_ENDIAN_H */ diff --git a/src/ipcpd/normal/enroll.c b/src/ipcpd/normal/enroll.c index cea33bf2..94e171c0 100644 --- a/src/ipcpd/normal/enroll.c +++ b/src/ipcpd/normal/enroll.c @@ -106,8 +106,8 @@ int enroll_handle(int fd) struct timespec t; uint64_t buf[2]; clock_gettime(CLOCK_REALTIME, &t); - buf[0] = htonll(t.tv_sec); - buf[1] = htonll(t.tv_nsec); + buf[0] = hton64(t.tv_sec); + buf[1] = hton64(t.tv_nsec); cdap_reply_send(ci, key, 0, buf, sizeof(buf)); free(name); continue; @@ -214,8 +214,8 @@ int enroll_boot(char * dst_name) assert (len == 2 * sizeof (uint64_t)); - rtt.tv_sec = ntohll(((uint64_t *) data)[0]); - rtt.tv_nsec = ntohll(((uint64_t *) data)[1]); + rtt.tv_sec = ntoh64(((uint64_t *) data)[0]); + rtt.tv_nsec = ntoh64(((uint64_t *) data)[1]); if (abs(ts_diff_ms(&t0, &rtt)) - delta_t > ENROLL_WARN_TIME_OFFSET) log_warn("Clock offset above threshold."); -- cgit v1.2.3 From 5cc79cfeb7a33c93ae9ef5781f9b0ecd4a958bee Mon Sep 17 00:00:00 2001 From: dimitri staessens Date: Sun, 12 Feb 2017 20:22:56 +0100 Subject: ipcpd: Fix timeout in ipcp_wait_state --- src/ipcpd/ipcp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ipcpd/ipcp.c b/src/ipcpd/ipcp.c index 24d8da46..19b3a721 100644 --- a/src/ipcpd/ipcp.c +++ b/src/ipcpd/ipcp.c @@ -145,7 +145,6 @@ static void * ipcp_main_loop(void * o) } ret_msg.has_result = true; ret_msg.result = ipcpi.ops->ipcp_enroll(msg->dif_name); - break; case IPCP_MSG_CODE__IPCP_NAME_REG: if (ipcpi.ops->ipcp_name_reg == NULL) { @@ -459,7 +458,8 @@ int ipcp_wait_state(enum ipcp_state state, while (ipcpi.state != state && ipcpi.state != IPCP_SHUTDOWN - && ipcpi.state != IPCP_NULL) { + && ipcpi.state != IPCP_NULL + && ret != -ETIMEDOUT) { if (timeout == NULL) ret = -pthread_cond_wait(&ipcpi.state_cond, &ipcpi.state_mtx); -- cgit v1.2.3