diff options
Diffstat (limited to 'src/ipcpd/unicast')
-rw-r--r-- | src/ipcpd/unicast/ca.c | 10 | ||||
-rw-r--r-- | src/ipcpd/unicast/ca.h | 4 | ||||
-rw-r--r-- | src/ipcpd/unicast/dt.c | 4 | ||||
-rw-r--r-- | src/ipcpd/unicast/fa.c | 195 | ||||
-rw-r--r-- | src/ipcpd/unicast/pol-ca-ops.h | 6 | ||||
-rw-r--r-- | src/ipcpd/unicast/pol/ca-mb-ecn.c | 41 | ||||
-rw-r--r-- | src/ipcpd/unicast/pol/ca-mb-ecn.h | 4 | ||||
-rw-r--r-- | src/ipcpd/unicast/pol/ca-nop.c | 3 |
8 files changed, 255 insertions, 12 deletions
diff --git a/src/ipcpd/unicast/ca.c b/src/ipcpd/unicast/ca.c index f93d0504..73de14a5 100644 --- a/src/ipcpd/unicast/ca.c +++ b/src/ipcpd/unicast/ca.c @@ -97,3 +97,13 @@ uint8_t ca_calc_ecn(int fd, { return ca.ops->calc_ecn(fd, len); } + +ssize_t ca_print_stats(void * ctx, + char * buf, + size_t len) +{ + if (ca.ops->print_stats == NULL) + return 0; + + return ca.ops->print_stats(ctx, buf, len); +} diff --git a/src/ipcpd/unicast/ca.h b/src/ipcpd/unicast/ca.h index 5cf6199c..7e3ab384 100644 --- a/src/ipcpd/unicast/ca.h +++ b/src/ipcpd/unicast/ca.h @@ -58,4 +58,8 @@ void ca_wnd_wait(ca_wnd_t wnd); uint8_t ca_calc_ecn(int fd, size_t len); +ssize_t ca_print_stats(void * ctx, + char * buf, + size_t len); + #endif /* OUROBOROS_IPCPD_UNICAST_CA_H */ diff --git a/src/ipcpd/unicast/dt.c b/src/ipcpd/unicast/dt.c index 53accba3..cb069544 100644 --- a/src/ipcpd/unicast/dt.c +++ b/src/ipcpd/unicast/dt.c @@ -317,11 +317,10 @@ static int dt_stat_readdir(char *** buf) pthread_mutex_unlock(&dt.stat[i].lock); } + assert((size_t) idx == dt.n_flows); pthread_rwlock_unlock(&dt.lock); - assert((size_t) idx == dt.n_flows); - return idx; #else (void) buf; @@ -367,7 +366,6 @@ static struct rib_ops r_ops = { }; #ifdef IPCP_FLOW_STATS - static void stat_used(int fd, uint64_t addr) { diff --git a/src/ipcpd/unicast/fa.c b/src/ipcpd/unicast/fa.c index b2eed7e5..2fc37d95 100644 --- a/src/ipcpd/unicast/fa.c +++ b/src/ipcpd/unicast/fa.c @@ -36,6 +36,7 @@ #include <ouroboros/errno.h> #include <ouroboros/dev.h> #include <ouroboros/ipcp-dev.h> +#include <ouroboros/rib.h> #include "dir.h" #include "fa.h" @@ -44,6 +45,7 @@ #include "dt.h" #include "ca.h" +#include <inttypes.h> #include <pthread.h> #include <stdlib.h> #include <string.h> @@ -55,6 +57,8 @@ #define FLOW_UPDATE 2 #define MSGBUFSZ 2048 +#define STAT_FILE_LEN 0 + struct fa_msg { uint64_t s_addr; uint32_t r_eid; @@ -79,6 +83,9 @@ struct cmd { }; struct fa_flow { +#ifdef IPCP_FLOW_STATS + time_t stamp; +#endif int r_eid; /* remote endpoint id */ uint64_t r_addr; /* remote address */ void * ctx; /* congestion avoidance context */ @@ -87,7 +94,9 @@ struct fa_flow { struct { pthread_rwlock_t flows_lock; struct fa_flow flows[PROG_MAX_FLOWS]; - +#ifdef IPCP_FLOW_STATS + size_t n_flows; +#endif int fd; struct list_head cmds; @@ -98,6 +107,156 @@ struct { struct psched * psched; } fa; +static int fa_stat_read(const char * path, + char * buf, + size_t len) +{ +#ifdef IPCP_FLOW_STATS + struct fa_flow * flow; + int fd; + char r_addrstr[20]; + char tmstr[20]; + char castr[1024]; + struct tm * tm; + + fd = atoi(path); + + if (fd < 0 || fd > PROG_MAX_FLOWS) + return -1; + + if (len < 1536) + return 0; + + flow = &fa.flows[fd]; + + buf[0] = '\0'; + + pthread_rwlock_rdlock(&fa.flows_lock); + + if (flow->stamp ==0) { + pthread_rwlock_unlock(&fa.flows_lock); + return 0; + } + + sprintf(r_addrstr, "%" PRIu64, flow->r_addr); + + tm = localtime(&flow->stamp); + strftime(tmstr, sizeof(tmstr), "%F %T", tm); + + ca_print_stats(flow->ctx, castr, 1024); + + sprintf(buf, + "Flow established at: %20s\n" + "Remote address: %20s\n" + "Local endpoint ID: %20d\n" + "Remote endpoint ID: %20d\n" + "%s", + tmstr, r_addrstr, fd, flow->r_eid, + castr); + + pthread_rwlock_unlock(&fa.flows_lock); + + return strlen(buf); +#else + (void) path; + (void) buf; + (void) len; + return 0; +#endif +} + +static int fa_stat_readdir(char *** buf) +{ +#ifdef IPCP_FLOW_STATS + char entry[RIB_PATH_LEN + 1]; + size_t i; + int idx = 0; + + pthread_rwlock_rdlock(&fa.flows_lock); + + if (fa.n_flows < 1) { + pthread_rwlock_unlock(&fa.flows_lock); + return 0; + } + + *buf = malloc(sizeof(**buf) * fa.n_flows); + if (*buf == NULL) { + pthread_rwlock_unlock(&fa.flows_lock); + return -ENOMEM; + } + + for (i = 0; i < PROG_MAX_FLOWS; ++i) { + struct fa_flow * flow; + + flow = &fa.flows[i]; + if (flow->stamp == 0) + continue; + + sprintf(entry, "%zu", i); + + (*buf)[idx] = malloc(strlen(entry) + 1); + if ((*buf)[idx] == NULL) { + while (idx-- > 0) + free((*buf)[idx]); + free(buf); + pthread_rwlock_unlock(&fa.flows_lock); + return -ENOMEM; + } + + strcpy((*buf)[idx++], entry); + } + + assert((size_t) idx == fa.n_flows); + + pthread_rwlock_unlock(&fa.flows_lock); + + return idx; +#else + (void) buf; + return 0; +#endif +} + +static int fa_stat_getattr(const char * path, + struct stat * st) +{ +#ifdef IPCP_FLOW_STATS + int fd; + struct fa_flow * flow; + + fd = atoi(path); + + st->st_mode = S_IFREG | 0755; + st->st_nlink = 1; + st->st_uid = getuid(); + st->st_gid = getgid(); + + flow = &fa.flows[fd]; + + pthread_rwlock_rdlock(&fa.flows_lock); + + if (flow->stamp != 0) { + st->st_size = 1536; + st->st_mtime = flow->stamp; + } else { + st->st_size = 0; + st->st_mtime = 0; + } + + pthread_rwlock_unlock(&fa.flows_lock); +#else + (void) path; + (void) st; +#endif + return 0; +} + +static struct rib_ops r_ops = { + .read = fa_stat_read, + .readdir = fa_stat_readdir, + .getattr = fa_stat_getattr +}; + static void packet_handler(int fd, qoscube_t qc, struct shm_du_buff * sdb) @@ -132,6 +291,9 @@ static void packet_handler(int fd, static int fa_flow_init(struct fa_flow * flow) { +#ifdef IPCP_FLOW_STATS + struct timespec now; +#endif memset(flow, 0, sizeof(*flow)); flow->r_eid = -1; @@ -141,6 +303,13 @@ static int fa_flow_init(struct fa_flow * flow) if (flow->ctx == NULL) return -1; +#ifdef IPCP_FLOW_STATS + clock_gettime(CLOCK_REALTIME_COARSE, &now); + + flow->stamp = now.tv_sec; + + ++fa.n_flows; +#endif return 0; } @@ -152,6 +321,10 @@ static void fa_flow_fini(struct fa_flow * flow) flow->r_eid = -1; flow->r_addr = INVALID_ADDR; + +#ifdef IPCP_FLOW_STATS + --fa.n_flows; +#endif } static void fa_post_packet(void * comp, @@ -336,6 +509,7 @@ static void * fa_handle_packet(void * o) int fa_init(void) { pthread_condattr_t cattr; + char fastr[256]; if (pthread_rwlock_init(&fa.flows_lock, NULL)) goto fail_rwlock; @@ -358,8 +532,14 @@ int fa_init(void) fa.fd = dt_reg_comp(&fa, &fa_post_packet, FA); + sprintf(fastr, "%s", FA); + if (rib_reg(fastr, &r_ops)) + goto fail_rib_reg; + return 0; + fail_rib_reg: + pthread_cond_destroy(&fa.cond); fail_cond: pthread_condattr_destroy(&cattr); fail_cattr: @@ -586,6 +766,7 @@ static int fa_update_remote(int fd, struct shm_du_buff * sdb; qoscube_t qc = QOS_CUBE_BE; struct fa_flow * flow; + uint64_t r_addr; if (ipcp_sdb_reserve(&sdb, sizeof(*msg))) { return -1; @@ -603,15 +784,16 @@ static int fa_update_remote(int fd, msg->r_eid = hton32(flow->r_eid); msg->ece = hton16(ece); - if (dt_write_packet(flow->r_addr, qc, fa.fd, sdb)) { - pthread_rwlock_unlock(&fa.flows_lock); - ipcp_sdb_release(sdb); - return -1; - } + r_addr = flow->r_addr; pthread_rwlock_unlock(&fa.flows_lock); + if (dt_write_packet(r_addr, qc, fa.fd, sdb)) { + ipcp_sdb_release(sdb); + return -1; + } + return 0; } @@ -638,5 +820,4 @@ void fa_ecn_update(int eid, if (update) fa_update_remote(eid, ece); - } diff --git a/src/ipcpd/unicast/pol-ca-ops.h b/src/ipcpd/unicast/pol-ca-ops.h index 3cb8a9d2..69bd0d21 100644 --- a/src/ipcpd/unicast/pol-ca-ops.h +++ b/src/ipcpd/unicast/pol-ca-ops.h @@ -45,6 +45,12 @@ struct pol_ca_ops { uint8_t (* calc_ecn)(int fd, size_t len); + + /* Optional, can be NULL */ + ssize_t (* print_stats)(void * ctx, + char * buf, + size_t len); + }; #endif /* OUROBOROS_IPCPD_UNICAST_POL_CA_OPS_H */ diff --git a/src/ipcpd/unicast/pol/ca-mb-ecn.c b/src/ipcpd/unicast/pol/ca-mb-ecn.c index 03f7044d..0542e291 100644 --- a/src/ipcpd/unicast/pol/ca-mb-ecn.c +++ b/src/ipcpd/unicast/pol/ca-mb-ecn.c @@ -35,6 +35,7 @@ #include <stdlib.h> #include <string.h> +#include <stdio.h> /* congestion avoidance constants */ #define CA_SHFT 5 /* Average over 32 pkts */ @@ -72,7 +73,8 @@ struct pol_ca_ops mb_ecn_ca_ops = { .ctx_update_rcv = mb_ecn_ctx_update_rcv, .ctx_update_ece = mb_ecn_ctx_update_ece, .wnd_wait = mb_ecn_wnd_wait, - .calc_ecn = mb_ecn_calc_ecn + .calc_ecn = mb_ecn_calc_ecn, + .print_stats = mb_ecn_print_stats }; void * mb_ecn_ctx_create(void) @@ -229,3 +231,40 @@ uint8_t mb_ecn_calc_ecn(int fd, return (uint8_t) (q >> ECN_Q_SHFT); } + +ssize_t mb_ecn_print_stats(void * _ctx, + char * buf, + size_t len) +{ + struct mb_ecn_ctx* ctx = _ctx; + char * regime; + + if (len < 1024) + return 0; + + if (!ctx->tx_cav) + regime = "Slow start"; + else if (ctx->tx_ece) + regime = "Multiplicative dec"; + else + regime = "Additive inc"; + + sprintf(buf, + "Congestion avoidance algorithm: %20s\n" + "Upstream congestion level: %20u\n" + "Upstream packet counter: %20zu\n" + "Downstream congestion level: %20u\n" + "Downstream packet counter: %20zu\n" + "Congestion window size (ns): %20zu\n" + "Packets in this window: %20zu\n" + "Bytes in this window: %20zu\n" + "Max bytes in this window: %20zu\n" + "Current congestion regime: %20s\n", + "Multi-bit ECN", + ctx->rx_ece, ctx->rx_ctr, + ctx->tx_ece, ctx->tx_ctr, (size_t) (1 << ctx->tx_mul), + ctx->tx_wpc, ctx->tx_wbc, ctx->tx_wbl, + regime); + + return strlen(buf); +} diff --git a/src/ipcpd/unicast/pol/ca-mb-ecn.h b/src/ipcpd/unicast/pol/ca-mb-ecn.h index 456b9b13..945b0df5 100644 --- a/src/ipcpd/unicast/pol/ca-mb-ecn.h +++ b/src/ipcpd/unicast/pol/ca-mb-ecn.h @@ -45,6 +45,10 @@ void mb_ecn_wnd_wait(ca_wnd_t wnd); uint8_t mb_ecn_calc_ecn(int fd, size_t len); +ssize_t mb_ecn_print_stats(void * ctx, + char * buf, + size_t len); + extern struct pol_ca_ops mb_ecn_ca_ops; #endif /* OUROBOROS_IPCPD_UNICAST_CA_MB_ECN_H */ diff --git a/src/ipcpd/unicast/pol/ca-nop.c b/src/ipcpd/unicast/pol/ca-nop.c index d0d89a2e..15b253ca 100644 --- a/src/ipcpd/unicast/pol/ca-nop.c +++ b/src/ipcpd/unicast/pol/ca-nop.c @@ -31,7 +31,8 @@ struct pol_ca_ops nop_ca_ops = { .ctx_update_rcv = nop_ctx_update_rcv, .ctx_update_ece = nop_ctx_update_ece, .wnd_wait = nop_wnd_wait, - .calc_ecn = nop_calc_ecn + .calc_ecn = nop_calc_ecn, + .print_stats = NULL }; void * nop_ctx_create(void) |