diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ipcpd/normal/main.c | 21 | ||||
| -rw-r--r-- | src/ipcpd/normal/pol/link_state.c | 124 | ||||
| -rw-r--r-- | src/irmd/config.h.in | 5 | ||||
| -rw-r--r-- | src/irmd/main.c | 12 | ||||
| -rw-r--r-- | src/lib/CMakeLists.txt | 25 | ||||
| -rw-r--r-- | src/lib/config.h.in | 7 | ||||
| -rw-r--r-- | src/lib/rib.c | 389 | 
7 files changed, 565 insertions, 18 deletions
| diff --git a/src/ipcpd/normal/main.c b/src/ipcpd/normal/main.c index 2b35a04a..e6dd6717 100644 --- a/src/ipcpd/normal/main.c +++ b/src/ipcpd/normal/main.c @@ -26,21 +26,21 @@  #define OUROBOROS_PREFIX "normal-ipcp" -#include <ouroboros/endian.h> -#include <ouroboros/logs.h> +#include <ouroboros/errno.h> +#include <ouroboros/hash.h>  #include <ouroboros/ipcp-dev.h> -#include <ouroboros/time_utils.h>  #include <ouroboros/irm.h> -#include <ouroboros/hash.h> -#include <ouroboros/errno.h> +#include <ouroboros/logs.h>  #include <ouroboros/notifier.h> +#include <ouroboros/rib.h> +#include <ouroboros/time_utils.h>  #include "addr_auth.h"  #include "connmgr.h"  #include "dir.h" +#include "dt.h"  #include "enroll.h"  #include "fa.h" -#include "dt.h"  #include "ipcp.h"  #include <stdbool.h> @@ -338,6 +338,11 @@ int main(int    argc,          }          /* These components must be init at creation. */ +        if (rib_init("ipcpd-normal")) { +                log_err("Failed to initialize RIB."); +                goto fail_rib_init; +        } +          if (connmgr_init()) {                  log_err("Failed to initialize connection manager.");                  goto fail_connmgr_init; @@ -378,6 +383,8 @@ int main(int    argc,          connmgr_fini(); +        rib_fini(); +          irm_unbind_api(getpid(), ipcpi.name);          ipcp_fini(); @@ -393,6 +400,8 @@ int main(int    argc,   fail_enroll_init:          connmgr_fini();   fail_connmgr_init: +        rib_fini(); + fail_rib_init:          irm_unbind_api(getpid(), ipcpi.name);   fail_bind_api:         ipcp_fini(); diff --git a/src/ipcpd/normal/pol/link_state.c b/src/ipcpd/normal/pol/link_state.c index 7df09bce..3d9e8246 100644 --- a/src/ipcpd/normal/pol/link_state.c +++ b/src/ipcpd/normal/pol/link_state.c @@ -22,15 +22,18 @@  #define _POSIX_C_SOURCE 200112L +#include "config.h" +  #define OUROBOROS_PREFIX "link-state-routing" +#include <ouroboros/dev.h>  #include <ouroboros/errno.h> +#include <ouroboros/fqueue.h>  #include <ouroboros/list.h>  #include <ouroboros/logs.h> -#include <ouroboros/utils.h>  #include <ouroboros/notifier.h> -#include <ouroboros/dev.h> -#include <ouroboros/fqueue.h> +#include <ouroboros/rib.h> +#include <ouroboros/utils.h>  #include "ae.h"  #include "connmgr.h" @@ -52,6 +55,7 @@ typedef LinkStateMsg link_state_msg_t;  #define LS_UPDATE_TIME 15  #define LS_TIMEO       60  #define LSA_MAX_LEN    128 +#define LSDB           "lsdb"  #ifndef CLOCK_REALTIME_COARSE  #define CLOCK_REALTIME_COARSE CLOCK_REALTIME @@ -90,6 +94,7 @@ struct {          fset_t *         mgmt_set;          struct list_head db; +        size_t           db_len;          pthread_rwlock_t db_lock; @@ -107,6 +112,106 @@ struct pol_routing_ops link_state_ops = {          .routing_i_destroy = link_state_routing_i_destroy  }; +static int str_adj(struct adjacency * adj, +                   char *             buf, +                   size_t             len) +{ +        char        tmbuf[64]; +        struct tm * tm; + +        if (len < 256) +                return -1; + +        tm = localtime(&adj->stamp); +        strftime(tmbuf, sizeof(tmbuf), "%Y-%m-%d %H:%M:%S", tm); + +        sprintf(buf, +                "src: %" PRIu64 "\n" +                "dst: %" PRIu64 "\n" +                "upd: %s\n", +                adj->src, +                adj->dst, +                tmbuf); + +        return strlen(buf); +} + +static int lsdb_read(const char * path, +                     char *       buf, +                     size_t       len) +{ +        struct list_head * p; +        char               entry[RIB_PATH_LEN + 1]; + +        pthread_rwlock_rdlock(&ls.db_lock); + +        if (ls.db_len == 0) { +                pthread_rwlock_unlock(&ls.db_lock); +                return -EPERM; +        } + +        list_for_each(p, &ls.db) { +                struct adjacency * a = list_entry(p, struct adjacency, next); +                sprintf(entry, "%" PRIu64 ".%" PRIu64, a->src, a->dst); +                if (strcmp(entry, path) == 0) { +                        len = str_adj(a, buf, len); +                        pthread_rwlock_unlock(&ls.db_lock); +                        return len; +                } +        } + +        pthread_rwlock_unlock(&ls.db_lock); + +        return -1; +} + +static int lsdb_readdir(char *** buf) +{ +        struct list_head * p; +        char               entry[RIB_PATH_LEN + 1]; +        ssize_t            idx = 0; + +        pthread_rwlock_rdlock(&ls.db_lock); + +        if (ls.db_len == 0) { +                pthread_rwlock_unlock(&ls.db_lock); +                return 0; +        } + +        *buf = malloc(sizeof(**buf) * ls.db_len); +        if (*buf == NULL) { +                pthread_rwlock_unlock(&ls.db_lock); +                return -ENOMEM; +        } + +        list_for_each(p, &ls.db) { +                struct adjacency * a = list_entry(p, struct adjacency, next); +                sprintf(entry, "%" PRIu64 ".%" PRIu64, a->src, a->dst); +                (*buf)[idx] = malloc(strlen(entry) + 1); +                if ((*buf)[idx] == NULL) { +                        ssize_t j; +                        for (j = 0; j < idx; ++j) +                                free(*buf[j]); +                        free(buf); +                        pthread_rwlock_unlock(&ls.db_lock); +                        return -ENOMEM; +                } + +                strcpy((*buf)[idx], entry); + +                idx++; +        } + +        pthread_rwlock_unlock(&ls.db_lock); + +        return idx; +} + +static struct rib_ops r_ops = { +        .read    = lsdb_read, +        .readdir = lsdb_readdir +}; +  static int lsdb_add_nb(uint64_t     addr,                         int          fd,                         enum nb_type type) @@ -214,11 +319,11 @@ static int lsdb_add_link(uint64_t    src,          list_add_tail(&adj->next, p); +        ls.db_len++; +          if (graph_update_edge(ls.graph, src, dst, *qs))                  log_warn("Failed to add edge to graph."); -        log_dbg("Added %" PRIu64 " - %" PRIu64" to lsdb.", adj->src, adj->dst); -          pthread_rwlock_unlock(&ls.db_lock);          return 0; @@ -239,8 +344,7 @@ static int lsdb_del_link(uint64_t src,                          if (graph_del_edge(ls.graph, src, dst))                                  log_warn("Failed to delete edge from graph."); -                        log_dbg("Removed %" PRIu64 " - %" PRIu64" from lsdb.", -                                a->src, a->dst); +                        ls.db_len--;                          pthread_rwlock_unlock(&ls.db_lock);                          free(a); @@ -587,6 +691,10 @@ int link_state_init(void)          if (pthread_create(&ls.listener, NULL, ls_conn_handle, NULL))                  goto fail_pthread_create_listener; +        ls.db_len = 0; + +        rib_reg(LSDB, &r_ops); +          return 0;   fail_pthread_create_listener: @@ -614,6 +722,8 @@ void link_state_fini(void)          struct list_head * p;          struct list_head * h; +        rib_unreg(LSDB); +          pthread_cancel(ls.listener);          pthread_join(ls.listener, NULL); diff --git a/src/irmd/config.h.in b/src/irmd/config.h.in index c217fe93..d253a1ac 100644 --- a/src/irmd/config.h.in +++ b/src/irmd/config.h.in @@ -45,3 +45,8 @@  #define IRMD_MIN_THREADS       @IRMD_MIN_THREADS@  #define IRMD_ADD_THREADS       @IRMD_ADD_THREADS@ + +#cmakedefine HAVE_FUSE +#ifdef HAVE_FUSE +#define FUSE_PREFIX "@FUSE_PREFIX@" +#endif diff --git a/src/irmd/main.c b/src/irmd/main.c index c5caff6c..df903f40 100644 --- a/src/irmd/main.c +++ b/src/irmd/main.c @@ -1631,6 +1631,11 @@ static void irm_fini(void)          pthread_cond_destroy(&irmd.cmd_cond);          pthread_rwlock_destroy(&irmd.reg_lock);          pthread_rwlock_destroy(&irmd.state_lock); + +#ifdef HAVE_FUSE +        if (rmdir(FUSE_PREFIX)) +                log_dbg("Failed to remove " FUSE_PREFIX); +#endif  }  void irmd_sig_handler(int         sig, @@ -2249,7 +2254,12 @@ static int irm_init(void)                  log_err("Failed to create rdrbuff.");                  goto fail_rdrbuff;          } - +#ifdef HAVE_FUSE +        if (stat(FUSE_PREFIX, &st) != -1) +                log_warn(FUSE_PREFIX " already exists..."); +        else +                mkdir(FUSE_PREFIX, 0777); +#endif          irmd.csockfd = -1;          irmd.state   = IRMD_RUNNING; diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index fd7ece83..26cecb44 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -37,10 +37,30 @@ if (HAVE_ROBUST_MUTEX)      set(HAVE_ROBUST_MUTEX TRUE)    else ()      message(STATUS "Robust mutex support disabled by user") -    set(HAVE_ROBUST_MUTEX FALSE)    endif ()  endif () +find_library(FUSE_LIBRARIES fuse QUIET) +if (FUSE_LIBRARIES) +  #FIXME: Check for version >= 2.6 +  set(DISABLE_FUSE FALSE CACHE BOOL "Disable FUSE support") +  if (NOT DISABLE_FUSE) +    message(STATUS "FUSE support enabled") +    set(FUSE_PREFIX "/tmp/ouroboros" CACHE STRING +    "Mountpoint for RIB filesystem") +    set(HAVE_FUSE TRUE CACHE INTERNAL "") +  else () +    message(STATUS "FUSE support disabled by user") +  endif () +endif () + +if (NOT HAVE_FUSE) +  set(FUSE_LIBRARIES "") +  set(FUSE_INCLUDE_DIR "") +endif () + +mark_as_advanced(FUSE_LIBRARIES) +  find_library(LIBGCRYPT_LIBRARIES gcrypt QUIET)  if (LIBGCRYPT_LIBRARIES)    find_path(LIBGCRYPT_INCLUDE_DIR gcrypt.h @@ -163,6 +183,7 @@ set(SOURCE_FILES    qos.c    qoscube.c    random.c +  rib.c    rq.c    sha3.c    shm_flow_set.c @@ -188,7 +209,7 @@ endif (CMAKE_BUILD_TYPE MATCHES Debug)  target_link_libraries(ouroboros ${LIBRT_LIBRARIES}    ${LIBPTHREAD_LIBRARIES} ${PROTOBUF_C_LIBRARY} ${OPENSSL_LIBRARIES} -  ${LIBGCRYPT_LIBRARIES}) +  ${LIBGCRYPT_LIBRARIES} ${FUSE_LIBRARIES})  install(TARGETS ouroboros LIBRARY DESTINATION usr/lib) diff --git a/src/lib/config.h.in b/src/lib/config.h.in index e9c43389..a85ce7b4 100644 --- a/src/lib/config.h.in +++ b/src/lib/config.h.in @@ -45,6 +45,11 @@  #cmakedefine HAVE_ROBUST_MUTEX  #endif +#cmakedefine HAVE_FUSE +#ifdef HAVE_FUSE +#define FUSE_PREFIX "@FUSE_PREFIX@" +#endif +  #define PTHREAD_COND_CLOCK  @PTHREAD_COND_CLOCK@  #define AP_MAX_FLOWS        @AP_MAX_FLOWS@ @@ -53,5 +58,3 @@  #define DU_BUFF_HEADSPACE   @DU_BUFF_HEADSPACE@  #define DU_BUFF_TAILSPACE   @DU_BUFF_TAILSPACE@ - -#define CDAP_REPLY_TIMEOUT  @CDAP_REPLY_TIMEOUT@ diff --git a/src/lib/rib.c b/src/lib/rib.c new file mode 100644 index 00000000..b6c8e140 --- /dev/null +++ b/src/lib/rib.c @@ -0,0 +1,389 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2017 + * + * RIB export using FUSE + * + *    Dimitri Staessens <dimitri.staessens@ugent.be> + *    Sander Vrijders   <sander.vrijders@ugent.be> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#define _POSIX_C_SOURCE 200112L + +#include "config.h" + +#include <ouroboros/errno.h> +#include <ouroboros/list.h> +#include <ouroboros/rib.h> +#include <ouroboros/utils.h> + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifdef HAVE_FUSE +#define _FILE_OFFSET_BITS 64 +#define FUSE_USE_VERSION  26 +#include <fuse.h> +#endif + +#ifdef HAVE_FUSE + +#ifndef CLOCK_REALTIME_COARSE +#define CLOCK_REALTIME_COARSE CLOCK_REALTIME +#endif + +#define RT "/" + +struct reg_comp { +        struct list_head next; + +        char             path[RIB_PATH_LEN + 1]; +        struct rib_ops * ops; +}; + +struct { +        struct list_head   reg_comps; + +        char               mnt[RIB_PATH_LEN + 1]; + +        struct fuse *      fuse; +        struct fuse_chan * ch; + +        pthread_rwlock_t   lock; + +        pthread_t          fuse_thr; +} rib; + +static int rib_open(const char *            path, +                    struct fuse_file_info * info) +{ +        (void) path; + +        info->nonseekable = 1; + +        return 0; +} + +static int rib_opendir(const char *         path, +                    struct fuse_file_info * info) +{ +        (void) path; +        (void) info; + +        return 0; +} + +static int rib_read(const char *            path, +                    char *                  buf, +                    size_t                  size, +                    off_t                   offset, +                    struct fuse_file_info * info) +{ +        struct list_head * p; +        char               comp[RIB_PATH_LEN + 1]; +        char *             c; + +        strcpy(comp, path + 1); + +        c = strstr(comp, "/"); + +        if (c != NULL) +                *c = '\0'; + +        (void) info; +        (void) offset; + +        pthread_rwlock_wrlock(&rib.lock); + +        list_for_each(p, &rib.reg_comps) { +                struct reg_comp * r = list_entry(p, struct reg_comp, next); +                if (strcmp(comp, r->path) == 0) { +                        int ret = r->ops->read(c + 1, buf, size); +                        pthread_rwlock_unlock(&rib.lock); +                        return ret; +                } +        } + +        pthread_rwlock_unlock(&rib.lock); + +        return -1; +} + +static int rib_readdir(const char *            path, +                       void *                  buf, +                       fuse_fill_dir_t         filler, +                       off_t                   offset, +                       struct fuse_file_info * info) +{ +        struct list_head * p; + +        (void) offset; +        (void) info; + +        filler(buf, ".", NULL, 0); +        filler(buf, "..", NULL, 0); + +        pthread_rwlock_rdlock(&rib.lock); + +        if (strcmp(path, RT) == 0) { +                list_for_each(p, &rib.reg_comps) { +                        struct reg_comp * c; +                        c = list_entry(p, struct reg_comp, next); +                        filler(buf, c->path, NULL, 0); +                } +        } else { +                list_for_each(p, &rib.reg_comps) { +                        char **           dir_entries; +                        ssize_t           len; +                        ssize_t           i; +                        struct reg_comp * c; +                        c = list_entry(p, struct reg_comp, next); +                        if (strcmp(path + 1, c->path) == 0) +                                if (c->ops->readdir == NULL) +                                        break; + +                        len = c->ops->readdir(&dir_entries); +                        if (len < 0) +                                break; +                        for (i = 0; i < len; ++i) +                                filler(buf, dir_entries[i], NULL, 0); +                        freepp(char, dir_entries, len); +                } +        } + +        pthread_rwlock_unlock(&rib.lock); + +        return 0; +} + +static int rib_getattr(const char *  path, +                       struct stat * st) +{ +        struct list_head * p; +        struct timespec    now; + +        clock_gettime(CLOCK_REALTIME_COARSE, &now); + +        memset(st, 0, sizeof(*st)); + +        if (strcmp(path, RT) == 0) { +                st->st_mode  = __S_IFDIR | 0755; +                st->st_nlink = 2; +                st->st_uid   = getuid(); +                st->st_gid   = getgid(); +                st->st_mtime = now.tv_sec; +                return 0; +        } + +        pthread_rwlock_rdlock(&rib.lock); + +        list_for_each(p, &rib.reg_comps) { +                struct reg_comp * rc = list_entry(p, struct reg_comp, next); +                if (strcmp(path + 1, rc->path) == 0) { +                        st->st_mode  = __S_IFDIR | 0755; +                        st->st_nlink = 2; +                        break; +                } +        } + +        pthread_rwlock_unlock(&rib.lock); + +        if (st->st_mode == 0) { +                char buf[4096]; +                st->st_nlink = 2; +                st->st_mode = __S_IFREG | 0755; +                st->st_size = rib_read(path, buf, 4096, 0, NULL); +        } + +        st->st_uid   = getuid(); +        st->st_gid   = getgid(); +        st->st_mtime = now.tv_sec; + +        return 0; +} + +static struct fuse_operations r_ops = { +        .getattr = rib_getattr, +        .open    = rib_open, +        .opendir = rib_opendir, +        .read    = rib_read, +        .readdir = rib_readdir +}; + +static void * fuse_thr(void * o) +{ +        (void) o; + +        if (fuse_loop(rib.fuse) < 0) +                return (void *) -1; + +        return (void *) 0; +} +#endif /* HAVE_FUSE */ + +int rib_init(const char * prefix) +{ +#ifdef HAVE_FUSE +        struct stat      st; +        char *           argv[] = {"ignored", +                                   NULL, +                                   "-f", +                                   "-o", +                                   "ro,", +                                   "allow_other,", +                                   "default_permissions,", +                                   "fsname=rib", +                                   NULL}; +        struct fuse_args args   = FUSE_ARGS_INIT(0, NULL); + +        if (stat(FUSE_PREFIX, &st) == -1) +                return -1; + +        sprintf(rib.mnt, FUSE_PREFIX "/%s.%d", prefix, getpid()); + +        if (stat(rib.mnt, &st) == -1) +                mkdir(rib.mnt, 0777); + +        argv[1] = rib.mnt; + +        fuse_opt_parse(&args, argv, NULL, NULL); + +        list_head_init(&rib.reg_comps); + +        rib.ch = fuse_mount(rib.mnt,  &args); +        if (rib.ch == NULL) +                goto fail_mount; + +        rib.fuse = fuse_new(rib.ch, &args, &r_ops, sizeof(r_ops), NULL); +        if (rib.fuse == NULL) +                goto fail_fuse; + +        if (pthread_rwlock_init(&rib.lock, NULL)) +                goto fail_rwlock_init; + +        if (pthread_create(&rib.fuse_thr, NULL, fuse_thr, NULL)) +                goto fail_fuse_thr; + +        fuse_opt_free_args(&args); + +        return 0; + + fail_fuse_thr: +        pthread_rwlock_destroy(&rib.lock); + fail_rwlock_init: +        fuse_destroy(rib.fuse); + fail_fuse: +        fuse_unmount(rib.mnt, rib.ch); + fail_mount: +        fuse_opt_free_args(&args); +        rmdir(rib.mnt); +        return -1; +#else +        (void) prefix; +        return 0; +#endif +} + +void rib_fini(void) +{ +#ifdef HAVE_FUSE +        struct list_head * p; +        struct list_head * h; + +        fuse_unmount(rib.mnt, rib.ch); +        pthread_join(rib.fuse_thr, NULL); + +        fuse_destroy(rib.fuse); + +        rmdir(rib.mnt); + +        pthread_rwlock_wrlock(&rib.lock); + +        list_for_each_safe(p, h, &rib.reg_comps) { +                struct reg_comp * c = list_entry(p, struct reg_comp, next); +                list_del(&c->next); +                free(c); +        } + +        pthread_rwlock_unlock(&rib.lock); + +        pthread_rwlock_destroy(&rib.lock); +#endif +} + +int rib_reg(const char *     path, +            struct rib_ops * ops) +{ +#ifdef HAVE_FUSE +        struct reg_comp *  rc; +        struct list_head * p; + +        pthread_rwlock_wrlock(&rib.lock); + +        list_for_each(p, &rib.reg_comps) { +                struct reg_comp * r = list_entry(p, struct reg_comp, next); +                if (strcmp(r->path, path) == 0) { +                        pthread_rwlock_unlock(&rib.lock); +                        return -EPERM; +                } + +                if (strcmp(r->path, path) > 0) +                        break; +        } + +        rc = malloc(sizeof(*rc)); +        if (rc == NULL) { +                pthread_rwlock_unlock(&rib.lock); +                return -ENOMEM; +        } + +        strcpy(rc->path, path); +        rc->ops = ops; + +        list_add_tail(&rc->next, p); + +        pthread_rwlock_unlock(&rib.lock); +#else +        (void) path; +        (void) ops; +#endif +        return 0; +} + +void rib_unreg(const char * path) +{ +#ifdef HAVE_FUSE +        struct list_head * p; +        struct list_head * h; + +        pthread_rwlock_wrlock(&rib.lock); + +        list_for_each_safe(p, h, &rib.reg_comps) { +                struct reg_comp * r = list_entry(p, struct reg_comp, next); +                if (strcmp(r->path, path) == 0) { +                        list_del(&r->next); +                        free(r); +                        break; +                } +        } + +        pthread_rwlock_unlock(&rib.lock); +#else +        (void) path; +#endif +} | 
