summaryrefslogtreecommitdiff
path: root/src/irmd
diff options
context:
space:
mode:
authorDimitri Staessens <dimitri@ouroboros.rocks>2023-03-04 03:48:48 +0100
committerSander Vrijders <sander@ouroboros.rocks>2023-03-08 15:59:37 +0100
commit89b58eaa2706c54aeb0a48252d1cfbd2b5ae01b7 (patch)
tree891c4a2de37e06fdb8879741911a6b7ff2f1b4b8 /src/irmd
parentf16b4a1954ab4fbca0ec403f6a04c80375328921 (diff)
downloadouroboros-89b58eaa2706c54aeb0a48252d1cfbd2b5ae01b7.tar.gz
ouroboros-89b58eaa2706c54aeb0a48252d1cfbd2b5ae01b7.zip
irmd: Add configuration file support
This adds initial support for configuration files using the C99 TOML parser (to be installed separately from https://github.com/cktan/tomlc99). The default location for the IRMd configuration file is /etc/ouroboros/irmd.conf. This is configurable at build time. An example file will be installed in the configuration directory with the name irmd.conf.example. Config file support can be disabled using the DISABLE_CONFIGFILE build option. There were some refactors and changes to the configuration messages and protobuf files. This works towards consolidation of protobuf C as an option for more generic handling of serialization/deserialization of various messages. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
Diffstat (limited to 'src/irmd')
-rw-r--r--src/irmd/CMakeLists.txt37
-rw-r--r--src/irmd/config.h.in6
-rw-r--r--src/irmd/configfile.c837
-rw-r--r--src/irmd/configfile.h29
-rw-r--r--src/irmd/ipcp.c21
-rw-r--r--src/irmd/ipcp.h7
-rw-r--r--src/irmd/irmd.h61
-rw-r--r--src/irmd/main.c150
-rw-r--r--src/irmd/registry.c1
-rw-r--r--src/irmd/utils.h2
10 files changed, 1081 insertions, 70 deletions
diff --git a/src/irmd/CMakeLists.txt b/src/irmd/CMakeLists.txt
index 59d0d103..fb1e6ca2 100644
--- a/src/irmd/CMakeLists.txt
+++ b/src/irmd/CMakeLists.txt
@@ -4,6 +4,39 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_BINARY_DIR}/include)
+find_library(TOML_LIBRARIES toml QUIET)
+if (TOML_LIBRARIES)
+ set(DISABLE_CONFIGFILE FALSE CACHE BOOL
+ "Disable configuration file support")
+ if (NOT DISABLE_CONFIGFILE)
+ set(OUROBOROS_CONFIG_DIR /etc/ouroboros/ CACHE STRING
+ "Configuration directory")
+ set(OUROBOROS_CONFIG_FILE irmd.conf CACHE STRING
+ "Name of the IRMd configuration file")
+ set(HAVE_TOML TRUE)
+ message(STATUS "Found TOML C99 library: " ${TOML_LIBRARIES})
+ message(STATUS "Configuration file support enabled")
+ message(STATUS "Configuration directory: ${OUROBOROS_CONFIG_DIR}")
+ set(INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
+ configure_file("${CMAKE_SOURCE_DIR}/irmd.conf.in"
+ "${CMAKE_BINARY_DIR}/irmd.conf.example" @ONLY)
+ install(FILES "${CMAKE_BINARY_DIR}/irmd.conf.example"
+ DESTINATION "${OUROBOROS_CONFIG_DIR}")
+ unset(INSTALL_DIR)
+ mark_as_advanced(TOML_LIBRARIES)
+ else ()
+ message(STATUS "Configuration file support disabled by user")
+ unset(OUROBOROS_CONFIG_FILE CACHE)
+ unset(OUROBOROS_CONFIG_DIR CACHE)
+ set(HAVE_TOML FALSE)
+ endif ()
+else ()
+ message(STATUS "Install tomlc99 for config file support")
+ message(STATUS " https://github.com/cktan/tomlc99")
+ unset(DISABLE_CONFIGFILE CACHE)
+ unset(HAVE_TOML)
+endif ()
+
set(IRMD_REQ_ARR_TIMEOUT 500 CACHE STRING
"Timeout for an application to respond to a new flow (ms)")
set(IRMD_FLOW_TIMEOUT 5000 CACHE STRING
@@ -31,6 +64,7 @@ set(SOURCE_FILES
proc_table.c
prog_table.c
ipcp.c
+ configfile.c
irm_flow.c
main.c
registry.c
@@ -39,7 +73,8 @@ set(SOURCE_FILES
add_executable (irmd ${SOURCE_FILES})
-target_link_libraries (irmd LINK_PUBLIC ouroboros-common)
+target_link_libraries (irmd LINK_PUBLIC ouroboros-common
+ ${TOML_LIBRARIES} ${CONFINI_LIBRARIES})
include(AddCompileFlags)
if (CMAKE_BUILD_TYPE MATCHES "Debug*")
diff --git a/src/irmd/config.h.in b/src/irmd/config.h.in
index a6979504..10ccaa52 100644
--- a/src/irmd/config.h.in
+++ b/src/irmd/config.h.in
@@ -47,9 +47,15 @@
#define IRMD_MIN_THREADS @IRMD_MIN_THREADS@
#define IRMD_ADD_THREADS @IRMD_ADD_THREADS@
+#define OUROBOROS_CONFIG_DIR "@OUROBOROS_CONFIG_DIR@"
+#define OUROBOROS_CONFIG_FILE "@OUROBOROS_CONFIG_FILE@"
+
#cmakedefine HAVE_FUSE
#ifdef HAVE_FUSE
#define FUSE_PREFIX "@FUSE_PREFIX@"
#endif
+#cmakedefine HAVE_TOML
+#cmakedefine HAVE_CONFINI
+#cmakedefine OUROBOROS_CONFIG_INI
#cmakedefine HAVE_LIBGCRYPT
diff --git a/src/irmd/configfile.c b/src/irmd/configfile.c
new file mode 100644
index 00000000..787edb49
--- /dev/null
+++ b/src/irmd/configfile.c
@@ -0,0 +1,837 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2023
+ *
+ * The IPC Resource Manager / Configuration from file
+ *
+ * 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 "config.h"
+
+#if defined (HAVE_TOML)
+
+#define _XOPEN_SOURCE 500
+
+#define OUROBOROS_PREFIX "irmd/configuration"
+
+#include <toml.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include <ouroboros/errno.h>
+#include <ouroboros/ipcp.h>
+#include <ouroboros/logs.h>
+
+#include "irmd.h"
+#include "configfile.h"
+#include "utils.h"
+
+#define ERRBUFSZ 200
+
+static int toml_hash(toml_table_t * table,
+ struct layer_info * info)
+{
+ toml_datum_t hash;
+
+ hash = toml_string_in(table, "hash");
+ if (!hash.ok) {
+ log_dbg("No hash specified, using default.");
+ return 0;
+ }
+
+ if (strcmp(hash.u.s, "SHA3_224") == 0) {
+ info->dir_hash_algo = DIR_HASH_SHA3_224;
+ } else if (strcmp(hash.u.s, "SHA3_256") == 0) {
+ info->dir_hash_algo = DIR_HASH_SHA3_256;
+ } else if (strcmp(hash.u.s, "SHA3_384") == 0) {
+ info->dir_hash_algo = DIR_HASH_SHA3_384;
+ } else if (strcmp(hash.u.s, "SHA3_512") == 0) {
+ info->dir_hash_algo = DIR_HASH_SHA3_512;
+ } else {
+ log_err("Unknown hash algorithm: %s.", hash.u.s);
+ free(hash.u.s);
+ return -1;
+ }
+
+ free(hash.u.s);
+
+ return 0;
+}
+
+static int toml_local(toml_table_t * table,
+ struct ipcp_config * conf)
+{
+ *conf = local_default_conf;
+
+ return toml_hash(table, &conf->layer_info);
+}
+
+static int toml_eth_dev(toml_table_t * table,
+ struct eth_config * conf)
+{
+ toml_datum_t dev;
+
+ dev = toml_string_in(table, "dev");
+ if (!dev.ok) {
+ log_err("Missing device.");
+ return -1;
+ }
+
+ if (strlen(dev.u.s) > DEV_NAME_SIZE) {
+ log_err("Device name too long: %s", dev.u.s);
+ free(dev.u.s);
+ return -1;
+ }
+
+ strcpy(conf->dev, dev.u.s);
+ free(dev.u.s);
+
+ return 0;
+}
+
+static int toml_eth_llc(toml_table_t * table,
+ struct ipcp_config * conf)
+{
+ *conf = eth_llc_default_conf;
+
+ if (toml_hash(table, &conf->layer_info) < 0)
+ return -1;
+
+ return toml_eth_dev(table, &conf->eth);
+}
+
+
+static int toml_ethertype(toml_table_t * table,
+ struct eth_config * conf)
+{
+ toml_datum_t ethertype;
+
+ ethertype = toml_int_in(table, "ethertype");
+ if (ethertype.ok)
+ conf->ethertype = ethertype.u.i;
+
+ if (conf->ethertype < 0x0600 || conf->ethertype == 0xFFFF)
+ return -1;
+
+ return 0;
+}
+
+static int toml_eth_dix(toml_table_t * table,
+ struct ipcp_config * conf)
+{
+ *conf = eth_dix_default_conf;
+
+ if (toml_hash(table, &conf->layer_info) < 0)
+ return -1;
+
+ if (toml_eth_dev(table, &conf->eth) < 0)
+ return -1;
+
+ if (toml_ethertype(table, &conf->eth) < 0) {
+ log_err("Ethertype not in valid range.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int toml_udp(toml_table_t * table,
+ struct ipcp_config * conf)
+{
+ toml_datum_t ip;
+ toml_datum_t port;
+ toml_datum_t dns;
+
+ *conf = udp_default_conf;
+
+ ip = toml_string_in(table, "ip");
+ if (!ip.ok) {
+ log_err("No IP address specified!");
+ goto fail_ip;
+ }
+
+ if (inet_pton (AF_INET, ip.u.s, &conf->udp.ip_addr) != 1) {
+ log_err("Failed to parse IPv4 address %s.", ip.u.s);
+ goto fail_addr;
+ }
+
+ port = toml_int_in(table, "port");
+ if (port.ok)
+ conf->udp.port = port.u.i;
+
+ dns = toml_string_in(table, "dns");
+ if (dns.ok) {
+ if (inet_pton(AF_INET, dns.u.s, &conf->udp.dns_addr) < 0) {
+ log_err("Failed to parse DNS address %s.", ip.u.s);
+ goto fail_dns;
+ }
+
+ free(dns.u.s);
+ }
+
+ free(ip.u.s);
+
+ return 0;
+
+ fail_dns:
+ free(dns.u.s);
+ fail_addr:
+ free(ip.u.s);
+ fail_ip:
+ return -1;
+}
+
+static int toml_broadcast(toml_table_t * table,
+ struct ipcp_config * conf)
+{
+ (void) table;
+ (void) conf;
+
+ /* Nothing to do here. */
+
+ return 0;
+}
+
+static int toml_routing(toml_table_t * table,
+ struct dt_config * conf)
+{
+ toml_datum_t routing;
+
+ routing = toml_string_in(table, "routing");
+ if (routing.ok) {
+ if (strcmp(routing.u.s, "link-state") == 0)
+ conf->routing_type = ROUTING_LINK_STATE;
+ else if (strcmp(routing.u.s, "lfa") == 0)
+ conf->routing_type = ROUTING_LINK_STATE_LFA;
+ else if (strcmp(routing.u.s, "ecmp") == 0)
+ conf->routing_type = ROUTING_LINK_STATE_ECMP;
+ else
+ conf->routing_type = ROUTING_INVALID;
+ free(routing.u.s);
+ }
+
+ if (conf->routing_type == ROUTING_INVALID)
+ return -1;
+
+ return 0;
+}
+
+static int toml_addr_auth(toml_table_t * table,
+ struct uni_config * conf)
+{
+ toml_datum_t addr_auth;
+
+ addr_auth = toml_string_in(table, "addr-auth");
+ if (addr_auth.ok) {
+ if (strcmp(addr_auth.u.s, "flat") == 0)
+ conf->addr_auth_type = ADDR_AUTH_FLAT_RANDOM;
+ else
+ conf->addr_auth_type = ADDR_AUTH_INVALID;
+ free(addr_auth.u.s);
+ }
+
+ if (conf->addr_auth_type == ADDR_AUTH_INVALID)
+ return -1;
+
+ return 0;
+}
+
+static int toml_congestion(toml_table_t * table,
+ struct uni_config * conf)
+{
+ toml_datum_t congestion;
+
+ congestion = toml_string_in(table, "congestion");
+ if (congestion.ok) {
+ if (strcmp(congestion.u.s, "none") == 0)
+ conf->cong_avoid = CA_NONE;
+ else if (strcmp(congestion.u.s, "lfa") == 0)
+ conf->cong_avoid = CA_MB_ECN;
+ else
+ conf->cong_avoid = CA_INVALID;
+ free(congestion.u.s);
+
+ }
+
+ if (conf->cong_avoid == CA_INVALID)
+ return -1;
+
+ return 0;
+}
+
+static int toml_dt(toml_table_t * table,
+ struct dt_config * conf)
+{
+ toml_datum_t addr;
+ toml_datum_t eid;
+ toml_datum_t ttl;
+
+ addr = toml_int_in(table, "addr_size");
+ if (addr.ok)
+ conf->addr_size = addr.u.i;
+
+ eid = toml_int_in(table, "eid_size");
+ if (eid.ok)
+ conf->eid_size = eid.u.i;
+
+ ttl = toml_int_in(table, "max_ttl");
+ if (ttl.ok)
+ conf->max_ttl = ttl.u.i;
+
+ if (toml_routing(table, conf) < 0) {
+ log_err("Invalid routing option.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int toml_unicast(toml_table_t * table,
+ struct ipcp_config * conf)
+{
+
+
+ *conf = uni_default_conf;
+
+ if (toml_hash(table, &conf->layer_info) < 0)
+ return -1;
+
+ if (toml_dt(table, &conf->unicast.dt) < 0) {
+ log_err("Invalid DT configuration.");
+ return -1;
+ }
+
+ if (toml_addr_auth(table, &conf->unicast) < 0) {
+ log_err("Invalid address authority");
+ return -1;
+ }
+
+ if (toml_congestion(table, &conf->unicast) < 0) {
+ log_err("Invalid congestion avoidance algorithm.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int toml_autobind(toml_table_t * table,
+ pid_t pid,
+ const char * name,
+ const char * layer)
+{
+ toml_datum_t autobind;
+
+ autobind = toml_bool_in(table, "autobind");
+ if (!autobind.ok)
+ return 0;
+
+ if (bind_process(pid, name) < 0) {
+ log_err("Failed to bind IPCP process %d to %s.", pid, name);
+ return -1;
+ }
+
+ if (layer != NULL && bind_process(pid, layer) < 0) {
+ log_err("Failed to bind IPCP process %d to %s.", pid, layer);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int toml_register(toml_table_t * table,
+ pid_t pid)
+{
+ toml_array_t * reg;
+ int i;
+ int ret = 0;
+
+ reg = toml_array_in(table, "reg");
+ if (reg == NULL)
+ return 0;
+
+ for (i = 0; ret == 0; i++) {
+ toml_datum_t name;
+
+ name = toml_string_at(reg, i);
+ if (!name.ok)
+ break;
+
+ log_dbg("Registering %s in %d", name.u.s, pid);
+
+ ret = name_create(name.u.s, LB_SPILL);
+ if (ret < 0 && ret != -ENAME) {
+ free(name.u.s);
+ break;
+ }
+
+ ret = name_reg(name.u.s, pid);
+ free(name.u.s);
+ }
+
+ return ret;
+}
+
+static int toml_connect(toml_table_t * table,
+ pid_t pid)
+{
+ toml_array_t * conn;
+ int i;
+ int ret = 0;
+
+ conn = toml_array_in(table, "conn");
+ if (conn == NULL)
+ return 0;
+
+ for (i=0; ret == 0; i++) {
+ toml_datum_t dst;
+ qosspec_t qs = qos_raw;
+
+ dst = toml_string_at(conn, i);
+ if (!dst.ok)
+ break;
+
+ log_dbg("Connecting %d to %s", pid, dst.u.s);
+
+ ret = connect_ipcp(pid, dst.u.s, MGMT_COMP, qs);
+ if (ret == 0)
+ ret = connect_ipcp(pid, dst.u.s, DT_COMP, qs);
+
+ free(dst.u.s);
+ }
+
+ return ret;
+}
+
+static int toml_ipcp(toml_table_t * table,
+ const char * name,
+ struct ipcp_config * conf)
+{
+ toml_datum_t bootstrap;
+ toml_datum_t enrol;
+ pid_t pid;
+ int ret;
+
+ log_dbg("Found IPCP %s in configuration file.", name);
+
+ pid = create_ipcp(name, conf->type);
+ if (pid < 0) {
+ log_err("Failed to create IPCP %s.", name);
+ return -1;
+ }
+
+ bootstrap = toml_string_in(table, "bootstrap");
+ enrol = toml_string_in(table, "enrol");
+
+ if (bootstrap.ok && enrol.ok) {
+ log_err("Ignoring bootstrap for IPCP %s.", name);
+ free(bootstrap.u.s);
+ bootstrap.ok = false;
+ }
+
+ if (!bootstrap.ok && !enrol.ok) {
+ log_dbg("Nothing more to do for %s.", name);
+ return 0;
+ }
+
+ if (enrol.ok) {
+ char layer[LAYER_NAME_SIZE + 1];
+ ret = enroll_ipcp(pid, enrol.u.s);
+ free(enrol.u.s);
+ if (ret < 0) {
+ log_err("Failed to enrol %s.", name);
+ return -1;
+ }
+
+ if (get_layer_for_ipcp(pid, layer) < 0)
+ return -1;
+
+ if (toml_autobind(table, pid, name, layer))
+ return -1;
+
+ if (toml_register(table, pid) < 0) {
+ log_err("Failed to register names.");
+ return -1;
+ }
+
+ if (toml_connect(table, pid) < 0) {
+ log_err("Failed to register names.");
+ return -1;
+ }
+
+ return 0;
+ }
+
+ assert(bootstrap.ok);
+
+ if (strlen(bootstrap.u.s) > LAYER_NAME_SIZE) {
+ log_err("Layer name too long: %s", bootstrap.u.s);
+ free(bootstrap.u.s);
+ return -1;
+ }
+
+ switch (conf->type) {
+ case IPCP_LOCAL:
+ ret = toml_local(table, conf);
+ break;
+ case IPCP_ETH_DIX:
+ ret = toml_eth_dix(table, conf);
+ break;
+ case IPCP_ETH_LLC:
+ ret = toml_eth_llc(table, conf);
+ break;
+ case IPCP_UDP:
+ ret = toml_udp(table, conf);
+ break;
+ case IPCP_BROADCAST:
+ ret = toml_broadcast(table, conf);
+ break;
+ case IPCP_UNICAST:
+ ret = toml_unicast(table, conf);
+ break;
+ default:
+ log_err("Invalid IPCP type");
+ ret = -1;
+ }
+
+ if (ret < 0)
+ return -1;
+
+ strcpy(conf->layer_info.layer_name, bootstrap.u.s);
+ free(bootstrap.u.s);
+
+ if (bootstrap_ipcp(pid, conf) < 0)
+ return -1;
+
+ if (toml_autobind(table, pid, name, conf->layer_info.layer_name) < 0)
+ return -1;
+
+ if (toml_register(table, pid) < 0) {
+ log_err("Failed to register names.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int toml_ipcp_list(toml_table_t * table,
+ enum ipcp_type type)
+{
+ int i = 0;
+ int ret = 0;
+
+ for (i = 0; ret == 0; i++) {
+ const char * key;
+ struct ipcp_config conf;
+
+ key = toml_key_in(table, i);
+ if (key == NULL)
+ break;
+
+ memset(&conf, 0, sizeof(conf));
+
+ conf.type = type;
+
+ ret = toml_ipcp(toml_table_in(table, key), key, &conf);
+ }
+
+ return ret;
+}
+
+static int args_to_argv(const char * args,
+ char *** argv)
+{
+ char * tok;
+ char * str;
+ int argc = 0;
+
+ str = (char *) args;
+
+ tok = strtok(str, " ");
+ while (tok != NULL) {
+ tok = strtok(NULL, " ");
+ argc++;
+ }
+
+ *argv = malloc((argc + 1) * sizeof(**argv));
+ if (*argv == NULL)
+ goto fail_malloc;
+
+ argc = 0;
+ tok = strtok(str, " ");
+ while (tok != NULL) {
+ (*argv)[argc] = malloc((strlen(tok) + 1) * sizeof(***argv));
+ if (*argv[argc] == NULL)
+ goto fail_malloc2;
+
+ strcpy((*argv)[argc++], tok);
+ tok = strtok(NULL, " ");
+ }
+
+ (*argv)[argc] = NULL;
+
+ return argc;
+
+ fail_malloc2:
+ argvfree(*argv);
+ fail_malloc:
+ return -1;
+
+}
+
+static int toml_prog(char * prog,
+ const char * args,
+ const char * name)
+{
+ uint16_t flags = 0;
+ int argc = 0;
+ char ** argv;
+ int ret;
+
+ if (args != NULL)
+ flags |= BIND_AUTO;
+
+ argc = args_to_argv(args, &argv);
+ if (argc < 0) {
+ log_err("Failed to parse arguments: %s", args);
+ return -1;
+ }
+
+ ret = bind_program(prog, name, flags, argc, argv);
+ if (ret < 0)
+ log_err("Failed to bind program %s %s for name %s.",
+ prog, args, name);
+
+ argvfree(argv);
+
+ return ret;
+}
+
+static int toml_prog_list(toml_array_t * progs,
+ toml_array_t * args,
+ const char * name)
+{
+ int ret = 0;
+ int i;
+
+ for (i = 0; ret == 0; i++) {
+ toml_datum_t prog;
+ toml_datum_t arg;
+
+ prog = toml_string_at(progs, i);
+ if (!prog.ok)
+ break;
+
+ if (args == NULL) {
+ ret = toml_prog(prog.u.s, NULL, name);
+ } else {
+ arg = toml_string_at(args, i);
+ if (!arg.ok) {
+ args = NULL; /* no more arguments in list. */
+ assert(arg.u.s == NULL);
+ }
+
+ ret = toml_prog(prog.u.s, arg.u.s, name);
+
+ if (arg.ok)
+ free(arg.u.s);
+ }
+
+ free(prog.u.s);
+ }
+
+ return ret;
+}
+
+static int toml_name(toml_table_t * table,
+ const char * name)
+{
+ toml_array_t * progs;
+ toml_array_t * args;
+ toml_datum_t lb;
+ enum pol_balance lb_pol = LB_SPILL;
+
+ log_dbg("Found service name %s in configuration file.", name);
+
+ lb = toml_string_in(table, "lb");
+ if (lb.ok) {
+ if (strcmp(lb.u.s, "spill") == 0)
+ lb_pol = LB_SPILL;
+ else if (strcmp(lb.u.s, "round-robin") == 0)
+ lb_pol = LB_RR;
+ else
+ lb_pol = LB_INVALID;
+ free(lb.u.s);
+ }
+
+ if (lb_pol == LB_INVALID) {
+ log_err("Invalid load-balancing policy for %s.", name);
+ return -1;
+ }
+
+ if (name_create(name, lb_pol) < 0) {
+ log_err("Failed to create name %s.", name);
+ return -1;
+ }
+
+ progs = toml_array_in(table, "prog");
+ if (progs == NULL)
+ return 0;
+
+ args = toml_array_in(table, "args");
+ if (toml_prog_list(progs, args, name) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int toml_name_list(toml_table_t * table)
+{
+ int i = 0;
+ int ret = 0;
+
+ for (i = 0; ret == 0; i++) {
+ const char * key;
+
+ key = toml_key_in(table, i);
+ if (key == NULL)
+ break;
+
+ ret = toml_name(toml_table_in(table, key), key);
+ }
+
+ return ret;
+ return 0;
+}
+
+static int toml_toplevel(toml_table_t * table,
+ const char * key)
+{
+ toml_table_t * subtable;
+
+ subtable = toml_table_in(table, key);
+
+ if (strcmp(key, "local") == 0)
+ return toml_ipcp_list(subtable, IPCP_LOCAL);
+ else if (strcmp(key, "eth-dix") == 0)
+ return toml_ipcp_list(subtable, IPCP_ETH_DIX);
+ else if (strcmp(key, "eth-llc") == 0)
+ return toml_ipcp_list(subtable, IPCP_ETH_LLC);
+ else if (strcmp(key, "udp") == 0)
+ return toml_ipcp_list(subtable, IPCP_UDP);
+ else if (strcmp(key, "broadcast") == 0)
+ return toml_ipcp_list(subtable, IPCP_BROADCAST);
+ else if (strcmp(key, "unicast") == 0)
+ return toml_ipcp_list(subtable, IPCP_UNICAST);
+ else if (strcmp(key, "name") == 0)
+ return toml_name_list(subtable);
+
+ log_err("Unkown toplevel key: %s.", key);
+ return -1;
+}
+
+static int toml_load(toml_table_t * table)
+{
+ int i = 0;
+ int ret = 0;
+
+ for (i = 0; ret == 0; i++) {
+ const char * key;
+
+ key = toml_key_in(table, i);
+ if (key == NULL)
+ break;
+
+ ret = toml_toplevel(table, key);
+ }
+
+ return ret;
+}
+
+static int toml_cfg(FILE * fp)
+{
+ toml_table_t * table;
+ char errbuf[ERRBUFSZ + 1];
+
+ assert(fp != NULL);
+
+ table = toml_parse_file(fp, errbuf, sizeof(errbuf));
+ if (table == NULL) {
+ log_err("Failed to parse config file: %s.", errbuf);
+ goto fail_parse;
+ }
+
+ if (toml_load(table) < 0) {
+ log_err("Failed to load configuration.");
+ goto fail_load;
+ }
+
+ toml_free(table);
+
+ return 0;
+
+ fail_load:
+ toml_free(table);
+ fail_parse:
+ return -1;
+}
+
+int irm_configure(const char * path)
+{
+ FILE * fp;
+ char * rp;
+
+ if (path == NULL)
+ return 0;
+
+ rp = realpath(path, NULL);
+ if (rp == NULL) {
+ log_warn("Failed to resolve path for %s", path);
+ return 0;
+ }
+
+ log_info("Reading configuration from file %s", rp);
+
+ fp = fopen(rp, "r");
+ if (fp == NULL) {
+ log_err("Failed to open config file: %s\n", strerror(errno));
+ goto fail_fopen;
+ }
+
+ if (toml_cfg(fp) < 0) {
+ log_err("Failed to load config file.");
+ goto fail_cfg;
+ }
+
+ fclose(fp);
+ free(rp);
+
+ return 0;
+
+ fail_cfg:
+ fclose(fp);
+ fail_fopen:
+ free(rp);
+ return -1;
+}
+
+#endif /* HAVE_TOML */
diff --git a/src/irmd/configfile.h b/src/irmd/configfile.h
new file mode 100644
index 00000000..586bff96
--- /dev/null
+++ b/src/irmd/configfile.h
@@ -0,0 +1,29 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2023
+ *
+ * The IPC Resource Manager / Configuration from file
+ *
+ * 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_IRMD_CONFIGURATION_H
+#define OUROBOROS_IRMD_CONFIGURATION_H
+
+int irm_configure(const char * path);
+
+#endif /* OUROBOROS_IRMD_CONFIGURATION_H */
diff --git a/src/irmd/ipcp.c b/src/irmd/ipcp.c
index 182fb087..c062809c 100644
--- a/src/irmd/ipcp.c
+++ b/src/irmd/ipcp.c
@@ -20,7 +20,7 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#define _POSIX_C_SOURCE 199309L
+#define _POSIX_C_SOURCE 200112L
#include "config.h"
@@ -194,9 +194,9 @@ int ipcp_destroy(pid_t pid)
return 0;
}
-int ipcp_bootstrap(pid_t pid,
- ipcp_config_msg_t * conf,
- struct layer_info * info)
+int ipcp_bootstrap(pid_t pid,
+ struct ipcp_config * conf,
+ struct layer_info * info)
{
ipcp_msg_t msg = IPCP_MSG__INIT;
ipcp_msg_t * recv_msg = NULL;
@@ -206,9 +206,10 @@ int ipcp_bootstrap(pid_t pid,
return -EINVAL;
msg.code = IPCP_MSG_CODE__IPCP_BOOTSTRAP;
- msg.conf = conf;
+ msg.conf = ipcp_config_s_to_msg(conf);
recv_msg = send_recv_ipcp_msg(pid, &msg);
+ ipcp_config_msg__free_unpacked(msg.conf, NULL);
if (recv_msg == NULL)
return -EIPCP;
@@ -285,7 +286,6 @@ int ipcp_connect(pid_t pid,
qosspec_t qs)
{
ipcp_msg_t msg = IPCP_MSG__INIT;
- qosspec_msg_t qs_msg = QOSSPEC_MSG__INIT;
int ret = -1;
ipcp_msg_t * recv_msg;
@@ -294,10 +294,10 @@ int ipcp_connect(pid_t pid,
msg.comp = (char *) component;
msg.has_pid = true;
msg.pid = pid;
- qs_msg = spec_to_msg(&qs);
- msg.qosspec = &qs_msg;
+ msg.qosspec = qos_spec_s_to_msg(&qs);
recv_msg = send_recv_ipcp_msg(pid, &msg);
+ free(msg.qosspec);
if (recv_msg == NULL)
return -EIPCP;
@@ -438,7 +438,6 @@ static int __ipcp_flow_alloc(pid_t pid,
size_t dlen)
{
ipcp_msg_t msg = IPCP_MSG__INIT;
- qosspec_msg_t qs_msg;
ipcp_msg_t * recv_msg = NULL;
int ret = -1;
@@ -453,13 +452,13 @@ static int __ipcp_flow_alloc(pid_t pid,
msg.has_hash = true;
msg.hash.len = len;
msg.hash.data = (uint8_t *) dst;
- qs_msg = spec_to_msg(&qs);
- msg.qosspec = &qs_msg;
+ msg.qosspec = qos_spec_s_to_msg(&qs);;
msg.has_pk = true;
msg.pk.data = (uint8_t *) data;
msg.pk.len = (uint32_t) dlen;
recv_msg = send_recv_ipcp_msg(pid, &msg);
+ free(msg.qosspec);
if (recv_msg == NULL)
return -EIPCP;
diff --git a/src/irmd/ipcp.h b/src/irmd/ipcp.h
index 40347e86..ad96ad1c 100644
--- a/src/irmd/ipcp.h
+++ b/src/irmd/ipcp.h
@@ -21,6 +21,7 @@
*/
#include <ouroboros/ipcp.h>
+#include <ouroboros/protobuf.h>
#include <ouroboros/sockets.h>
#include <sys/types.h>
@@ -37,9 +38,9 @@ int ipcp_enroll(pid_t pid,
const char * dst,
struct layer_info * info);
-int ipcp_bootstrap(pid_t pid,
- ipcp_config_msg_t * conf,
- struct layer_info * info);
+int ipcp_bootstrap(pid_t pid,
+ struct ipcp_config * conf,
+ struct layer_info * info);
int ipcp_connect(pid_t pid,
const char * dst,
diff --git a/src/irmd/irmd.h b/src/irmd/irmd.h
new file mode 100644
index 00000000..92c26818
--- /dev/null
+++ b/src/irmd/irmd.h
@@ -0,0 +1,61 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2023
+ *
+ * The IPC Resource Manager
+ *
+ * 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_IRMD_H
+#define OUROBOROS_IRMD_H
+
+#include <ouroboros/ipcp.h>
+#include <ouroboros/irm.h>
+
+int create_ipcp(const char * name,
+ enum ipcp_type type);
+
+int bootstrap_ipcp(pid_t pid,
+ struct ipcp_config * conf);
+
+int enroll_ipcp(pid_t pid,
+ const char * dst);
+
+int connect_ipcp(pid_t pid,
+ const char * dst,
+ const char * component,
+ qosspec_t qs);
+
+int get_layer_for_ipcp(pid_t pid,
+ char * buf);
+
+int name_create(const char * name,
+ enum pol_balance pol);
+
+int name_reg(const char * name,
+ pid_t pid);
+
+int bind_process(pid_t pid,
+ const char * name);
+
+int bind_program(char * prog,
+ const char * name,
+ uint16_t flags,
+ int argc,
+ char ** argv);
+
+#endif /* OUROBOROS_IRMD_H*/ \ No newline at end of file
diff --git a/src/irmd/main.c b/src/irmd/main.c
index 4277be3d..b2f83388 100644
--- a/src/irmd/main.c
+++ b/src/irmd/main.c
@@ -49,9 +49,11 @@
#include "utils.h"
#include "registry.h"
+#include "irmd.h"
#include "irm_flow.h"
#include "proc_table.h"
#include "ipcp.h"
+#include "configfile.h"
#include <sys/socket.h>
#include <sys/un.h>
@@ -123,7 +125,9 @@ struct {
struct bmp * flow_ids; /* flow_ids for flows */
struct list_head irm_flows; /* flow information */
pthread_rwlock_t flows_lock; /* lock for flows */
-
+#ifdef HAVE_TOML
+ char * cfg_file; /* configuration file path */
+#endif
struct lockfile * lf; /* single irmd per system */
struct shm_rdrbuff * rdrb; /* rdrbuff for packets */
@@ -363,7 +367,7 @@ static struct ipcp_entry * get_ipcp_by_dst_name(const char * name,
list_for_each_safe(p, h, &irmd.ipcps) {
struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
- if (e->layer == NULL || e->pid == src)
+ if (e->layer == NULL || e->pid == src || e->type == IPCP_BROADCAST)
continue;
len = IPCP_HASH_LEN(e);
@@ -395,8 +399,31 @@ static struct ipcp_entry * get_ipcp_by_dst_name(const char * name,
return NULL;
}
-static pid_t create_ipcp(const char * name,
- enum ipcp_type type)
+int get_layer_for_ipcp(pid_t pid,
+ char * buf)
+{
+ struct ipcp_entry * entry;
+
+ pthread_rwlock_rdlock(&irmd.reg_lock);
+
+ entry = get_ipcp_entry_by_pid(pid);
+ if (entry == NULL || entry->layer == NULL)
+ goto fail;
+
+ strcpy(buf, entry->layer);
+
+ pthread_rwlock_unlock(&irmd.reg_lock);
+
+ return 0;
+
+ fail:
+ pthread_rwlock_unlock(&irmd.reg_lock);
+ return -1;
+}
+
+
+pid_t create_ipcp(const char * name,
+ enum ipcp_type type)
{
struct pid_el * ppid;
struct ipcp_entry * entry;
@@ -524,8 +551,8 @@ static int destroy_ipcp(pid_t pid)
return 0;
}
-static int bootstrap_ipcp(pid_t pid,
- ipcp_config_msg_t * conf)
+int bootstrap_ipcp(pid_t pid,
+ struct ipcp_config * conf)
{
struct ipcp_entry * entry;
struct layer_info info;
@@ -539,7 +566,7 @@ static int bootstrap_ipcp(pid_t pid,
return -1;
}
- if (entry->type != (enum ipcp_type) conf->ipcp_type) {
+ if (entry->type != conf->type) {
pthread_rwlock_unlock(&irmd.reg_lock);
log_err("Configuration does not match IPCP type.");
return -1;
@@ -563,13 +590,13 @@ static int bootstrap_ipcp(pid_t pid,
pthread_rwlock_unlock(&irmd.reg_lock);
log_info("Bootstrapped IPCP %d in layer %s.",
- pid, conf->layer_info->layer_name);
+ pid, conf->layer_info.layer_name);
return 0;
}
-static int enroll_ipcp(pid_t pid,
- char * dst)
+int enroll_ipcp(pid_t pid,
+ const char * dst)
{
struct ipcp_entry * entry = NULL;
struct layer_info info;
@@ -622,10 +649,10 @@ static int enroll_ipcp(pid_t pid,
return 0;
}
-static int connect_ipcp(pid_t pid,
- const char * dst,
- const char * component,
- qosspec_t qs)
+int connect_ipcp(pid_t pid,
+ const char * dst,
+ const char * component,
+ qosspec_t qs)
{
struct ipcp_entry * entry = NULL;
@@ -693,11 +720,11 @@ static int disconnect_ipcp(pid_t pid,
return 0;
}
-static int bind_program(char * prog,
- char * name,
- uint16_t flags,
- int argc,
- char ** argv)
+int bind_program(char * prog,
+ const char * name,
+ uint16_t flags,
+ int argc,
+ char ** argv)
{
char * progs;
char ** argv_dup = NULL;
@@ -719,21 +746,21 @@ static int bind_program(char * prog,
return -ENOMEM;
}
- if ((flags & BIND_AUTO) && argc) {
+ if ((flags & BIND_AUTO) && argc > 0) {
/* We need to duplicate argv and set argv[0] to prog. */
argv_dup = malloc((argc + 2) * sizeof(*argv_dup));
argv_dup[0] = strdup(prog);
for (i = 1; i <= argc; ++i) {
argv_dup[i] = strdup(argv[i - 1]);
- if (argv_dup[i] == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- argvfree(argv_dup);
- log_err("Failed to bind program "
- "%s to %s.",
- prog, name);
- free(progs);
- return -ENOMEM;
- }
+ if (argv_dup[i] != NULL)
+ continue;
+
+ pthread_rwlock_unlock(&irmd.reg_lock);
+ log_err("Failed to bind program %s to %s.",
+ prog, name);
+ argvfree(argv_dup);
+ free(progs);
+ return -ENOMEM;
}
argv_dup[argc + 1] = NULL;
}
@@ -771,8 +798,8 @@ static int bind_program(char * prog,
return 0;
}
-static int bind_process(pid_t pid,
- char * name)
+int bind_process(pid_t pid,
+ const char * name)
{
char * name_dup = NULL;
struct proc_entry * e = NULL;
@@ -952,8 +979,8 @@ static ssize_t list_ipcps(ipcp_info_msg_t *** ipcps,
return -ENOMEM;
}
-static int name_create(const char * name,
- enum pol_balance pol)
+int name_create(const char * name,
+ enum pol_balance pol)
{
struct reg_entry * re;
struct list_head * p;
@@ -964,8 +991,8 @@ static int name_create(const char * name,
if (registry_has_name(&irmd.registry, name)) {
pthread_rwlock_unlock(&irmd.reg_lock);
- log_err("Registry entry for %s already exists.", name);
- return -ENAME;
+ log_warn("Registry entry for %s already exists.", name);
+ return 0;
}
re = registry_add_name(&irmd.registry, name);
@@ -1084,8 +1111,8 @@ static ssize_t list_names(name_info_msg_t *** names,
return -ENOMEM;
}
-static int name_reg(const char * name,
- pid_t pid)
+int name_reg(const char * name,
+ pid_t pid)
{
size_t len;
struct ipcp_entry * ipcp;
@@ -1403,8 +1430,7 @@ static int flow_alloc(pid_t pid,
int state;
uint8_t * hash;
- log_info("Allocating flow for %d to %s.\n",
- pid, dst);
+ log_info("Allocating flow for %d to %s.", pid, dst);
ipcp = join ? get_ipcp_entry_by_layer(dst)
: get_ipcp_by_dst_name(dst, pid);
@@ -1967,12 +1993,13 @@ static void * mainloop(void * o)
(void) o;
while (true) {
- irm_msg_t * ret_msg;
- struct irm_flow e;
- struct timespec * timeo = NULL;
- struct timespec ts = {0, 0};
- struct cmd * cmd;
- int result;
+ irm_msg_t * ret_msg;
+ struct irm_flow e;
+ struct ipcp_config conf;
+ struct timespec * timeo = NULL;
+ struct timespec ts = {0, 0};
+ struct cmd * cmd;
+ int result;
memset(&e, 0, sizeof(e));
@@ -2035,14 +2062,15 @@ static void * mainloop(void * o)
result = destroy_ipcp(msg->pid);
break;
case IRM_MSG_CODE__IRM_BOOTSTRAP_IPCP:
- result = bootstrap_ipcp(msg->pid, msg->conf);
+ conf = ipcp_config_msg_to_s(msg->conf);
+ result = bootstrap_ipcp(msg->pid, &conf);
break;
case IRM_MSG_CODE__IRM_ENROLL_IPCP:
result = enroll_ipcp(msg->pid, msg->dst);
break;
case IRM_MSG_CODE__IRM_CONNECT_IPCP:
result = connect_ipcp(msg->pid, msg->dst, msg->comp,
- msg_to_spec(msg->qosspec));
+ qos_spec_msg_to_s(msg->qosspec));
break;
case IRM_MSG_CODE__IRM_DISCONNECT_IPCP:
result = disconnect_ipcp(msg->pid, msg->dst, msg->comp);
@@ -2091,13 +2119,11 @@ static void * mainloop(void * o)
result = flow_accept(msg->pid, timeo, &e,
msg->pk.data, msg->pk.len);
if (result == 0) {
- qosspec_msg_t qs_msg;
ret_msg->has_flow_id = true;
ret_msg->flow_id = e.flow_id;
ret_msg->has_pid = true;
ret_msg->pid = e.n_1_pid;
- qs_msg = spec_to_msg(&e.qs);
- ret_msg->qosspec = &qs_msg;
+ ret_msg->qosspec = qos_spec_s_to_msg(&e.qs);
ret_msg->has_pk = true;
ret_msg->pk.data = e.data;
ret_msg->pk.len = e.len;
@@ -2109,7 +2135,7 @@ static void * mainloop(void * o)
assert(msg->pk.len > 0 ? msg->pk.data != NULL
: msg->pk.data == NULL);
result = flow_alloc(msg->pid, msg->dst,
- msg_to_spec(msg->qosspec),
+ qos_spec_msg_to_s(msg->qosspec),
timeo, &e, false, msg->pk.data,
msg->pk.len);
if (result == 0) {
@@ -2127,7 +2153,7 @@ static void * mainloop(void * o)
case IRM_MSG_CODE__IRM_FLOW_JOIN:
assert(msg->pk.len == 0 && msg->pk.data == NULL);
result = flow_alloc(msg->pid, msg->dst,
- msg_to_spec(msg->qosspec),
+ qos_spec_msg_to_s(msg->qosspec),
timeo, &e, true, NULL, 0);
if (result == 0) {
ret_msg->has_flow_id = true;
@@ -2150,7 +2176,7 @@ static void * mainloop(void * o)
&e,
msg->hash.data,
msg->mpl,
- msg_to_spec(msg->qosspec),
+ qos_spec_msg_to_s(msg->qosspec),
msg->pk.data,
msg->pk.len);
if (result == 0) {
@@ -2199,8 +2225,6 @@ static void * mainloop(void * o)
irm_msg__pack(ret_msg, buffer.data);
- /* Can't free the qosspec. */
- ret_msg->qosspec = NULL;
irm_msg__free_unpacked(ret_msg, NULL);
pthread_cleanup_push(__cleanup_close_ptr, &sfd);
@@ -2493,6 +2517,9 @@ static int irm_init(void)
static void usage(void)
{
printf("Usage: irmd \n"
+#ifdef OUROBOROS_CONFIG_INI
+ " [--config <path> (Path to configuration file)]\n"
+#endif
" [--stdout (Log to stdout instead of system log)]\n"
" [--version (Print version number and exit)]\n"
"\n");
@@ -2566,6 +2593,9 @@ static void irm_stop(void)
static void irm_argparse(int argc,
char ** argv)
{
+#ifdef HAVE_TOML
+ irmd.cfg_file = OUROBOROS_CONFIG_DIR OUROBOROS_CONFIG_FILE;
+#endif
argc--;
argv++;
while (argc > 0) {
@@ -2579,6 +2609,12 @@ static void irm_argparse(int argc,
OUROBOROS_VERSION_MINOR,
OUROBOROS_VERSION_PATCH);
exit(EXIT_SUCCESS);
+#ifdef HAVE_TOML
+ } else if (strcmp (*argv, "--config") == 0) {
+ irmd.cfg_file = *(argv + 1);
+ argc -= 2;
+ argv += 2;
+#endif
} else {
usage();
exit(EXIT_FAILURE);
@@ -2613,6 +2649,10 @@ int main(int argc,
if (irm_start() < 0)
goto fail_irm_start;
+#ifdef HAVE_TOML
+ if (irm_configure(irmd.cfg_file) < 0)
+ irmd_set_state(IRMD_NULL);
+#endif
irm_sigwait(sigset);
irm_stop();
diff --git a/src/irmd/registry.c b/src/irmd/registry.c
index c68b9abc..0aebdab7 100644
--- a/src/irmd/registry.c
+++ b/src/irmd/registry.c
@@ -296,6 +296,7 @@ int reg_entry_add_pid(struct reg_entry * e,
list_add(&i->next, &e->reg_pids);
break;
default:
+ free(i);
assert(false);
};
diff --git a/src/irmd/utils.h b/src/irmd/utils.h
index 7fd72cd4..83585f21 100644
--- a/src/irmd/utils.h
+++ b/src/irmd/utils.h
@@ -23,6 +23,8 @@
#ifndef OUROBOROS_IRMD_UTILS_H
#define OUROBOROS_IRMD_UTILS_H
+#include <ouroboros/list.h>
+
#include <sys/types.h>
struct str_el {