From 7c0c62706f2ae9821dc779db268a28ef986730fe Mon Sep 17 00:00:00 2001 From: Dimitri Staessens Date: Tue, 29 Jun 2021 20:11:37 +0200 Subject: lib: Application RIB with FRCT statistics Application flows can now be monitored from the RIB, exposing FRCT statistics (window edges, retransmission timeout, rtt estimate, etc). Application RIB requires user permissions to be able to access /dev/fuse. Signed-off-by: Dimitri Staessens Signed-off-by: Sander Vrijders --- src/lib/CMakeLists.txt | 10 ++++ src/lib/config.h.in | 1 + src/lib/dev.c | 20 ++++++- src/lib/frct.c | 141 ++++++++++++++++++++++++++++++++++++++++++++----- src/lib/rib.c | 18 +++++-- 5 files changed, 173 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 76d0530d..022c5cca 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -219,6 +219,16 @@ set(ACK_WHEEL_SLOTS 128 CACHE STRING set(ACK_WHEEL_RESOLUTION 20 CACHE STRING "Minimum acknowledgment delay (ns), as a power to 2") +if (HAVE_FUSE) + set(PROC_FLOW_STATS TRUE CACHE BOOL + "Enable flow statistics tracking for application flows") + if (PROC_FLOW_STATS) + message(STATUS "Application flow statistics enabled") + else () + message(STATUS "Application flow statistics disabled") + endif () +endif () + set(SOURCE_FILES_DEV # Add source files here cacep.c diff --git a/src/lib/config.h.in b/src/lib/config.h.in index 17213a57..5c5b6caf 100644 --- a/src/lib/config.h.in +++ b/src/lib/config.h.in @@ -56,6 +56,7 @@ #cmakedefine HAVE_FUSE #ifdef HAVE_FUSE #define FUSE_PREFIX "@FUSE_PREFIX@" +#cmakedefine PROC_FLOW_STATS #endif #define PTHREAD_COND_CLOCK @PTHREAD_COND_CLOCK@ diff --git a/src/lib/dev.c b/src/lib/dev.c index ec4561b2..fbbc096d 100644 --- a/src/lib/dev.c +++ b/src/lib/dev.c @@ -44,6 +44,9 @@ #include #include #include +#ifdef PROC_FLOW_STATS +#include +#endif #include #include @@ -361,7 +364,9 @@ static void init(int argc, { const char * prog = argv[0]; int i; - +#ifdef PROC_FLOW_STATS + char procstr[32]; +#endif (void) argc; (void) envp; @@ -437,6 +442,11 @@ static void init(int argc, if (timerwheel_init() < 0) goto fail_timerwheel; +#if defined PROC_FLOW_STATS + sprintf(procstr, "proc.%d", getpid()); + /* Don't bail, it just won't show metrics */ + rib_init(procstr); +#endif return; fail_timerwheel: @@ -470,7 +480,13 @@ static void init(int argc, static void fini(void) { - int i = 0; + int i = 0; +#ifdef PROC_FLOW_STATS + char procstr[32]; + + sprintf(procstr, "proc.%d", getpid()); + rib_fini(); +#endif if (ai.fds == NULL) return; diff --git a/src/lib/frct.c b/src/lib/frct.c index 7aaf037c..5313e4da 100644 --- a/src/lib/frct.c +++ b/src/lib/frct.c @@ -20,10 +20,12 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#define DELT_RDV (100 * MILLION) /* ns */ -#define MAX_RDV (1 * BILLION) /* ns */ +#define DELT_RDV (100 * MILLION) /* ns */ +#define MAX_RDV (1 * BILLION) /* ns */ -#define FRCT_PCILEN (sizeof(struct frct_pci)) +#define FRCT "frct" +#define FRCT_PCILEN (sizeof(struct frct_pci)) +#define FRCT_NAME_STRLEN 32 struct frct_cr { uint32_t lwe; /* Left window edge */ @@ -84,6 +86,103 @@ struct frct_pci { uint32_t ackno; } __attribute__((packed)); +#ifdef PROC_FLOW_STATS + +static int frct_rib_read(const char * path, + char * buf, + size_t len) +{ + struct timespec now; + char * entry; + struct flow * flow; + struct frcti * frcti; + int fd; + + (void) len; + + entry = strstr(path, RIB_SEPARATOR); + assert(entry); + *entry = '\0'; + + fd = atoi(path); + + flow = &ai.flows[fd]; + + clock_gettime(PTHREAD_COND_CLOCK, &now); + + pthread_rwlock_rdlock(&ai.lock); + + frcti = flow->frcti; + + pthread_rwlock_rdlock(&frcti->lock); + + sprintf(buf, + "Maximum packet lifetime (ns): %20ld\n" + "Max time to Ack (ns): %20ld\n" + "Max time to Retransmit (ns): %20ld\n" + "Smoothed rtt (ns): %20ld\n" + "RTT standard deviation (ns): %20ld\n" + "Retransmit timeout RTO (ns): %20ld\n" + "Sender left window edge: %20u\n" + "Sender right window edge: %20u\n" + "Sender inactive (ns): %20ld\n" + "Sender current sequence number: %20u\n" + "Receiver left window edge: %20u\n" + "Receiver right window edge: %20u\n" + "Receiver inactive (ns): %20ld\n" + "Receiver last ack: %20u\n", + frcti->mpl, + frcti->a, + frcti->r, + frcti->srtt, + frcti->mdev, + frcti->rto, + frcti->snd_cr.lwe, + frcti->snd_cr.rwe, + ts_diff_ns(&frcti->snd_cr.act, &now), + frcti->snd_cr.seqno, + frcti->rcv_cr.lwe, + frcti->rcv_cr.rwe, + ts_diff_ns(&frcti->rcv_cr.act, &now), + frcti->rcv_cr.seqno); + + pthread_rwlock_unlock(&flow->frcti->lock); + + pthread_rwlock_unlock(&ai.lock); + + return strlen(buf); +} + +static int frct_rib_readdir(char *** buf) +{ + *buf = malloc(sizeof(**buf)); + + (*buf)[0] = strdup("frct"); + + return 1; +} + +static int frct_rib_getattr(const char * path, + struct rib_attr * attr) +{ + (void) path; + (void) attr; + + attr->size = 1024; + attr->mtime = 0; + + return 0; +} + + +static struct rib_ops r_ops = { + .read = frct_rib_read, + .readdir = frct_rib_readdir, + .getattr = frct_rib_getattr +}; + +#endif /* PROC_FLOW_STATS */ + static bool before(uint32_t seq1, uint32_t seq2) { @@ -205,14 +304,16 @@ static void __send_rdv(int fd) static struct frcti * frcti_create(int fd) { - struct frcti * frcti; - ssize_t idx; - struct timespec now; - time_t mpl; - time_t a; - time_t r; - pthread_condattr_t cattr; - + struct frcti * frcti; + ssize_t idx; + struct timespec now; + time_t mpl; + time_t a; + time_t r; + pthread_condattr_t cattr; +#ifdef PROC_FLOW_STATS + char frctstr[FRCT_NAME_STRLEN + 1]; +#endif frcti = malloc(sizeof(*frcti)); if (frcti == NULL) goto fail_malloc; @@ -233,6 +334,13 @@ static struct frcti * frcti_create(int fd) if (pthread_cond_init(&frcti->cond, &cattr)) goto fail_cond; +#ifdef PROC_FLOW_STATS + sprintf(frctstr, "%d", fd); + if (rib_reg(frctstr, &r_ops)) + goto fail_rib_reg; +#endif + pthread_condattr_destroy(&cattr); + for (idx = 0; idx < RQ_SIZE; ++idx) frcti->rq[idx] = -1; @@ -269,9 +377,13 @@ static struct frcti * frcti_create(int fd) return frcti; +#ifdef PROC_FLOW_STATS + fail_rib_reg: + pthread_cond_destroy(&frcti->cond); +#endif fail_cond: pthread_condattr_destroy(&cattr); -fail_cattr: + fail_cattr: pthread_mutex_destroy(&frcti->mtx); fail_mutex: pthread_rwlock_destroy(&frcti->lock); @@ -283,6 +395,11 @@ fail_cattr: static void frcti_destroy(struct frcti * frcti) { +#ifdef PROC_FLOW_STATS + char frctstr[FRCT_NAME_STRLEN + 1]; + sprintf(frctstr, "%d", frcti->fd); + rib_unreg(frctstr); +#endif pthread_cond_destroy(&frcti->cond); pthread_mutex_destroy(&frcti->mtx); pthread_rwlock_destroy(&frcti->lock); diff --git a/src/lib/rib.c b/src/lib/rib.c index dfac69d7..8fda19d4 100644 --- a/src/lib/rib.c +++ b/src/lib/rib.c @@ -286,8 +286,17 @@ int rib_init(const char * mountpt) NULL}; struct fuse_args args = FUSE_ARGS_INIT(3, argv); + if (access("/dev/fuse", R_OK)) + goto fail; + if (stat(FUSE_PREFIX, &st) == -1) - return -1; + goto fail; + + /* This is crap to allow IPCP RIB to remount to a different name */ + if (strlen(rib.mnt) > 0) { + fuse_unmount(rib.mnt, rib.ch); + rmdir(rib.mnt); + } sprintf(rib.mnt, FUSE_PREFIX "/%s", mountpt); @@ -295,13 +304,13 @@ int rib_init(const char * mountpt) switch(errno) { case ENOENT: if (mkdir(rib.mnt, 0777)) - return -1; + goto fail_mnt; break; case ENOTCONN: fuse_unmount(rib.mnt, rib.ch); break; default: - return -1; + goto fail_mnt; } fuse_opt_parse(&args, NULL, NULL, NULL); @@ -335,6 +344,9 @@ int rib_init(const char * mountpt) fail_mount: fuse_opt_free_args(&args); rmdir(rib.mnt); + fail_mnt: + memset(rib.mnt, 0, RIB_PATH_LEN + 1); + fail: return -1; #else (void) mountpt; -- cgit v1.2.3