From 89b58eaa2706c54aeb0a48252d1cfbd2b5ae01b7 Mon Sep 17 00:00:00 2001 From: Dimitri Staessens Date: Sat, 4 Mar 2023 03:48:48 +0100 Subject: 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 Signed-off-by: Sander Vrijders --- src/irmd/CMakeLists.txt | 37 ++- src/irmd/config.h.in | 6 + src/irmd/configfile.c | 837 ++++++++++++++++++++++++++++++++++++++++++++++++ src/irmd/configfile.h | 29 ++ src/irmd/ipcp.c | 21 +- src/irmd/ipcp.h | 7 +- src/irmd/irmd.h | 61 ++++ src/irmd/main.c | 150 +++++---- src/irmd/registry.c | 1 + src/irmd/utils.h | 2 + 10 files changed, 1081 insertions(+), 70 deletions(-) create mode 100644 src/irmd/configfile.c create mode 100644 src/irmd/configfile.h create mode 100644 src/irmd/irmd.h (limited to 'src/irmd') 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 + * Sander Vrijders + * + * 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 + * Sander Vrijders + * + * 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 +#include #include #include @@ -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 + * Sander Vrijders + * + * 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 +#include + +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 #include @@ -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 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 + #include struct str_el { -- cgit v1.2.3