diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ipcpd/ipcp.c | 4 | ||||
-rw-r--r-- | src/ipcpd/unicast/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/ipcpd/unicast/ca.c | 99 | ||||
-rw-r--r-- | src/ipcpd/unicast/ca.h | 61 | ||||
-rw-r--r-- | src/ipcpd/unicast/dt.c | 43 | ||||
-rw-r--r-- | src/ipcpd/unicast/fa.c | 222 | ||||
-rw-r--r-- | src/ipcpd/unicast/fa.h | 4 | ||||
-rw-r--r-- | src/ipcpd/unicast/main.c | 10 | ||||
-rw-r--r-- | src/ipcpd/unicast/pol-ca-ops.h | 50 | ||||
-rw-r--r-- | src/ipcpd/unicast/pol/ca-mb-ecn.c | 216 | ||||
-rw-r--r-- | src/ipcpd/unicast/pol/ca-mb-ecn.h | 50 | ||||
-rw-r--r-- | src/ipcpd/unicast/pol/ca-nop.c | 93 | ||||
-rw-r--r-- | src/ipcpd/unicast/pol/ca-nop.h | 50 | ||||
-rw-r--r-- | src/ipcpd/unicast/pol/link_state.c | 6 | ||||
-rw-r--r-- | src/lib/dev.c | 15 | ||||
-rw-r--r-- | src/lib/ipcp_config.proto | 13 | ||||
-rw-r--r-- | src/lib/irm.c | 2 | ||||
-rw-r--r-- | src/tools/irm/irm_ipcp_bootstrap.c | 69 |
18 files changed, 904 insertions, 106 deletions
diff --git a/src/ipcpd/ipcp.c b/src/ipcpd/ipcp.c index 95d2f783..c8b5f848 100644 --- a/src/ipcpd/ipcp.c +++ b/src/ipcpd/ipcp.c @@ -241,6 +241,7 @@ static void * mainloop(void * o) conf.max_ttl = conf_msg->max_ttl; conf.addr_auth_type = conf_msg->addr_auth_type; conf.routing_type = conf_msg->routing_type; + conf.cong_avoid = conf_msg->cong_avoid; break; case IPCP_ETH_DIX: conf.ethertype = conf_msg->ethertype; @@ -261,7 +262,8 @@ static void * mainloop(void * o) layer_info.dir_hash_algo = HASH_SHA3_256; break; default: - log_err("Unknown IPCP type: %d.", conf_msg->ipcp_type); + log_err("Unknown IPCP type: %d.", + conf_msg->ipcp_type); } /* UDP and broadcast use fixed hash algorithm. */ diff --git a/src/ipcpd/unicast/CMakeLists.txt b/src/ipcpd/unicast/CMakeLists.txt index c0c55519..035ee5f4 100644 --- a/src/ipcpd/unicast/CMakeLists.txt +++ b/src/ipcpd/unicast/CMakeLists.txt @@ -33,6 +33,7 @@ endif () set(SOURCE_FILES # Add source files here addr_auth.c + ca.c connmgr.c dht.c dir.c @@ -51,6 +52,8 @@ set(SOURCE_FILES pol/simple_pff.c pol/alternate_pff.c pol/multipath_pff.c + pol/ca-mb-ecn.c + pol/ca-nop.c ) add_executable(ipcpd-unicast ${SOURCE_FILES} ${IPCP_SOURCES} diff --git a/src/ipcpd/unicast/ca.c b/src/ipcpd/unicast/ca.c new file mode 100644 index 00000000..f93d0504 --- /dev/null +++ b/src/ipcpd/unicast/ca.c @@ -0,0 +1,99 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2020 + * + * Congestion Avoidance + * + * Dimitri Staessens <dimitri.staessens@ugent.be> + * Sander Vrijders <sander.vrijders@ugent.be> + * + * 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/. + */ + +#define OUROBOROS_PREFIX "ca" + +#include <ouroboros/logs.h> + +#include "ca.h" +#include "pol-ca-ops.h" +#include "pol/ca-mb-ecn.h" +#include "pol/ca-nop.h" + +struct { + struct pol_ca_ops * ops; +} ca; + +int ca_init(enum pol_cong_avoid pol) +{ + switch(pol) { + case CA_NONE: + log_dbg("Disabling congestion control."); + ca.ops = &nop_ca_ops; + break; + case CA_MB_ECN: + log_dbg("Using multi-bit ECN."); + ca.ops = &mb_ecn_ca_ops; + break; + default: + return -1; + } + + return 0; +} + + +void ca_fini(void) +{ + ca.ops = NULL; +} + +void * ca_ctx_create(void) +{ + return ca.ops->ctx_create(); +} + +void ca_ctx_destroy(void * ctx) +{ + return ca.ops->ctx_destroy(ctx); +} + +ca_wnd_t ca_ctx_update_snd(void * ctx, + size_t len) +{ + return ca.ops->ctx_update_snd(ctx, len); +} + +bool ca_ctx_update_rcv(void * ctx, + size_t len, + uint8_t ecn, + uint16_t * ece) +{ + return ca.ops->ctx_update_rcv(ctx, len, ecn, ece); +} + +void ca_ctx_update_ece(void * ctx, + uint16_t ece) +{ + return ca.ops->ctx_update_ece(ctx, ece); +} + +void ca_wnd_wait(ca_wnd_t wnd) +{ + return ca.ops->wnd_wait(wnd); +} + +uint8_t ca_calc_ecn(int fd, + size_t len) +{ + return ca.ops->calc_ecn(fd, len); +} diff --git a/src/ipcpd/unicast/ca.h b/src/ipcpd/unicast/ca.h new file mode 100644 index 00000000..5cf6199c --- /dev/null +++ b/src/ipcpd/unicast/ca.h @@ -0,0 +1,61 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2020 + * + * Congestion avoidance + * + * Dimitri Staessens <dimitri.staessens@ugent.be> + * Sander Vrijders <sander.vrijders@ugent.be> + * + * 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_IPCPD_UNICAST_CA_H +#define OUROBOROS_IPCPD_UNICAST_CA_H + +#include <ouroboros/ipcp.h> + +#include <stdbool.h> +#include <sys/types.h> + +typedef union { + time_t wait; +} ca_wnd_t; + +int ca_init(enum pol_cong_avoid ca); + +void ca_fini(void); + + +/* OPS */ +void * ca_ctx_create(void); + +void ca_ctx_destroy(void * ctx); + +ca_wnd_t ca_ctx_update_snd(void * ctx, + size_t len); + +bool ca_ctx_update_rcv(void * ctx, + size_t len, + uint8_t ecn, + uint16_t * ece); + +void ca_ctx_update_ece(void * ctx, + uint16_t ece); + +void ca_wnd_wait(ca_wnd_t wnd); + +uint8_t ca_calc_ecn(int fd, + size_t len); + +#endif /* OUROBOROS_IPCPD_UNICAST_CA_H */ diff --git a/src/ipcpd/unicast/dt.c b/src/ipcpd/unicast/dt.c index 7db766a5..53accba3 100644 --- a/src/ipcpd/unicast/dt.c +++ b/src/ipcpd/unicast/dt.c @@ -41,6 +41,7 @@ #include <ouroboros/fccntl.h> #endif +#include "ca.h" #include "connmgr.h" #include "ipcp.h" #include "dt.h" @@ -115,16 +116,12 @@ static void dt_pci_ser(uint8_t * head, } -static void dt_pci_des(struct shm_du_buff * sdb, - struct dt_pci * dt_pci) +static void dt_pci_des(uint8_t * head, + struct dt_pci * dt_pci) { - uint8_t * head; - - assert(sdb); + assert(head); assert(dt_pci); - head = shm_du_buff_head(sdb); - /* Decrease TTL */ --*(head + dt_pci_info.ttl_o); @@ -226,7 +223,6 @@ static int dt_stat_read(const char * path, "Queued packets (rx): %20zu\n" "Queued packets (tx): %20zu\n\n", tmstr, addrstr, rxqlen, txqlen); - for (i = 0; i < QOS_CUBE_MAX; ++i) { sprintf(str, "Qos cube %3d:\n" @@ -434,13 +430,14 @@ static void packet_handler(int fd, struct dt_pci dt_pci; int ret; int ofd; -#ifndef IPCP_FLOW_STATS - (void) fd; -#else + uint8_t * head; size_t len; len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb); +#ifndef IPCP_FLOW_STATS + (void) fd; +#else pthread_mutex_lock(&dt.stat[fd].lock); ++dt.stat[fd].rcv_pkt[qc]; @@ -449,7 +446,10 @@ static void packet_handler(int fd, pthread_mutex_unlock(&dt.stat[fd].lock); #endif memset(&dt_pci, 0, sizeof(dt_pci)); - dt_pci_des(sdb, &dt_pci); + + head = shm_du_buff_head(sdb); + + dt_pci_des(head, &dt_pci); if (dt_pci.dst_addr != ipcpi.dt_addr) { if (dt_pci.ttl == 0) { log_dbg("TTL was zero."); @@ -481,6 +481,8 @@ static void packet_handler(int fd, return; } + *(head + dt_pci_info.ecn_o) |= ca_calc_ecn(ofd, len); + ret = ipcp_flow_write(ofd, sdb); if (ret < 0) { log_dbg("Failed to write packet to fd %d.", ofd); @@ -508,6 +510,9 @@ static void packet_handler(int fd, } else { dt_pci_shrink(sdb); if (dt_pci.eid >= PROG_RES_FDS) { + uint8_t ecn = *(head + dt_pci_info.ecn_o); + fa_ecn_update(dt_pci.eid, ecn, len); + if (ipcp_flow_write(dt_pci.eid, sdb)) { ipcp_sdb_release(sdb); #ifdef IPCP_FLOW_STATS @@ -792,15 +797,15 @@ int dt_write_packet(uint64_t dst_addr, int fd; int ret; uint8_t * head; -#ifdef IPCP_FLOW_STATS size_t len; -#endif + assert(sdb); assert(dst_addr != ipcpi.dt_addr); -#ifdef IPCP_FLOW_STATS len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb); +#ifdef IPCP_FLOW_STATS + pthread_mutex_lock(&dt.stat[np1_fd].lock); ++dt.stat[np1_fd].lcl_r_pkt[qc]; @@ -829,15 +834,15 @@ int dt_write_packet(uint64_t dst_addr, goto fail_write; } + len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb); + dt_pci.dst_addr = dst_addr; dt_pci.qc = qc; dt_pci.eid = np1_fd; - dt_pci.ecn = 0; + dt_pci.ecn = ca_calc_ecn(fd, len); dt_pci_ser(head, &dt_pci); -#ifdef IPCP_FLOW_STATS - len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb); -#endif + ret = ipcp_flow_write(fd, sdb); if (ret < 0) { log_dbg("Failed to write packet to fd %d.", fd); diff --git a/src/ipcpd/unicast/fa.c b/src/ipcpd/unicast/fa.c index e154d785..8f268a9d 100644 --- a/src/ipcpd/unicast/fa.c +++ b/src/ipcpd/unicast/fa.c @@ -42,6 +42,7 @@ #include "psched.h" #include "ipcp.h" #include "dt.h" +#include "ca.h" #include <pthread.h> #include <stdlib.h> @@ -49,9 +50,10 @@ #define TIMEOUT 10000 /* nanoseconds */ -#define FLOW_REQ 0 -#define FLOW_REPLY 1 -#define MSGBUFSZ 2048 +#define FLOW_REQ 0 +#define FLOW_REPLY 1 +#define FLOW_UPDATE 2 +#define MSGBUFSZ 2048 struct fa_msg { uint64_t s_addr; @@ -59,6 +61,7 @@ struct fa_msg { uint32_t s_eid; uint8_t code; int8_t response; + uint16_t ece; /* QoS parameters from spec, aligned */ uint8_t availability; uint8_t in_order; @@ -75,10 +78,16 @@ struct cmd { struct shm_du_buff * sdb; }; +struct fa_flow { + int r_eid; /* remote endpoint id */ + uint64_t r_addr; /* remote address */ + void * ctx; /* congestion avoidance context */ +}; + struct { pthread_rwlock_t flows_lock; - int r_eid[PROG_MAX_FLOWS]; - uint64_t r_addr[PROG_MAX_FLOWS]; + struct fa_flow flows[PROG_MAX_FLOWS]; + int fd; struct list_head cmds; @@ -93,22 +102,56 @@ static void packet_handler(int fd, qoscube_t qc, struct shm_du_buff * sdb) { - pthread_rwlock_rdlock(&fa.flows_lock); + struct fa_flow * flow; + uint64_t r_addr; + uint32_t r_eid; + ca_wnd_t wnd; + size_t len; - if (dt_write_packet(fa.r_addr[fd], qc, fa.r_eid[fd], sdb)) { - pthread_rwlock_unlock(&fa.flows_lock); + flow = &fa.flows[fd]; + + pthread_rwlock_wrlock(&fa.flows_lock); + + len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb); + + wnd = ca_ctx_update_snd(flow->ctx, len); + + r_addr = flow->r_addr; + r_eid = flow->r_eid; + + pthread_rwlock_unlock(&fa.flows_lock); + + ca_wnd_wait(wnd); + + if (dt_write_packet(r_addr, qc, r_eid, sdb)) { ipcp_sdb_release(sdb); log_warn("Failed to forward packet."); return; } +} - pthread_rwlock_unlock(&fa.flows_lock); +static int fa_flow_init(struct fa_flow * flow) +{ + memset(flow, 0, sizeof(*flow)); + + flow->r_eid = -1; + flow->r_addr = INVALID_ADDR; + + flow->ctx = ca_ctx_create(); + if (flow->ctx == NULL) + return -1; + + return 0; } -static void destroy_conn(int fd) +static void fa_flow_fini(struct fa_flow * flow) { - fa.r_eid[fd] = -1; - fa.r_addr[fd] = INVALID_ADDR; + ca_ctx_destroy(flow->ctx); + + memset(flow, 0, sizeof(*flow)); + + flow->r_eid = -1; + flow->r_addr = INVALID_ADDR; } static void fa_post_packet(void * comp, @@ -145,14 +188,15 @@ static void * fa_handle_packet(void * o) (void) o; while (true) { - struct timespec abstime; - int fd; - uint8_t buf[MSGBUFSZ]; - struct fa_msg * msg; - qosspec_t qs; - struct cmd * cmd; - size_t len; - size_t msg_len; + struct timespec abstime; + int fd; + uint8_t buf[MSGBUFSZ]; + struct fa_msg * msg; + qosspec_t qs; + struct cmd * cmd; + size_t len; + size_t msg_len; + struct fa_flow * flow; pthread_mutex_lock(&fa.mtx); @@ -232,10 +276,14 @@ static void * fa_handle_packet(void * o) continue; } + flow = &fa.flows[fd]; + pthread_rwlock_wrlock(&fa.flows_lock); - fa.r_eid[fd] = ntoh32(msg->s_eid); - fa.r_addr[fd] = ntoh64(msg->s_addr); + fa_flow_init(flow); + + flow->r_eid = ntoh32(msg->s_eid); + flow->r_addr = ntoh64(msg->s_addr); pthread_rwlock_unlock(&fa.flows_lock); @@ -248,19 +296,32 @@ static void * fa_handle_packet(void * o) case FLOW_REPLY: assert(len >= sizeof(*msg)); + flow = &fa.flows[ntoh32(msg->r_eid)]; + pthread_rwlock_wrlock(&fa.flows_lock); - fa.r_eid[ntoh32(msg->r_eid)] = ntoh32(msg->s_eid); + flow->r_eid = ntoh32(msg->s_eid); + + if (msg->response < 0) + fa_flow_fini(flow); + else + psched_add(fa.psched, ntoh32(msg->r_eid)); + + pthread_rwlock_unlock(&fa.flows_lock); ipcp_flow_alloc_reply(ntoh32(msg->r_eid), msg->response, buf + sizeof(*msg), len - sizeof(*msg)); + break; + case FLOW_UPDATE: + assert(len >= sizeof(*msg)); - if (msg->response < 0) - destroy_conn(ntoh32(msg->r_eid)); - else - psched_add(fa.psched, ntoh32(msg->r_eid)); + flow = &fa.flows[ntoh32(msg->r_eid)]; + + pthread_rwlock_wrlock(&fa.flows_lock); + + ca_ctx_update_ece(flow->ctx, ntoh16(msg->ece)); pthread_rwlock_unlock(&fa.flows_lock); @@ -275,10 +336,6 @@ static void * fa_handle_packet(void * o) int fa_init(void) { pthread_condattr_t cattr; - int i; - - for (i = 0; i < PROG_MAX_FLOWS; ++i) - destroy_conn(i); if (pthread_rwlock_init(&fa.flows_lock, NULL)) goto fail_rwlock; @@ -383,9 +440,10 @@ int fa_alloc(int fd, size_t dlen) { struct fa_msg * msg; - uint64_t addr; struct shm_du_buff * sdb; - qoscube_t qc; + struct fa_flow * flow; + uint64_t addr; + qoscube_t qc = QOS_CUBE_BE; size_t len; addr = dir_query(dst); @@ -397,7 +455,9 @@ int fa_alloc(int fd, if (ipcp_sdb_reserve(&sdb, len + dlen)) return -1; - msg = (struct fa_msg *) shm_du_buff_head(sdb); + msg = (struct fa_msg *) shm_du_buff_head(sdb); + memset(msg, 0, sizeof(*msg)); + msg->code = FLOW_REQ; msg->s_eid = hton32(fd); msg->s_addr = hton64(ipcpi.dt_addr); @@ -413,17 +473,17 @@ int fa_alloc(int fd, memcpy(msg + 1, dst, ipcp_dir_hash_len()); memcpy(shm_du_buff_head(sdb) + len, data, dlen); - qc = qos_spec_to_cube(qs); - if (dt_write_packet(addr, qc, fa.fd, sdb)) { ipcp_sdb_release(sdb); return -1; } + flow = &fa.flows[fd]; + pthread_rwlock_wrlock(&fa.flows_lock); - assert(fa.r_eid[fd] == -1); - fa.r_addr[fd] = addr; + fa_flow_init(flow); + flow->r_addr = addr; pthread_rwlock_unlock(&fa.flows_lock); @@ -439,10 +499,13 @@ int fa_alloc_resp(int fd, struct timespec abstime; struct fa_msg * msg; struct shm_du_buff * sdb; - qoscube_t qc; + struct fa_flow * flow; + qoscube_t qc = QOS_CUBE_BE; clock_gettime(PTHREAD_COND_CLOCK, &abstime); + flow = &fa.flows[fd]; + pthread_mutex_lock(&ipcpi.alloc_lock); while (ipcpi.alloc_id != fd && ipcp_get_state() == IPCP_OPERATIONAL) { @@ -463,33 +526,31 @@ int fa_alloc_resp(int fd, pthread_mutex_unlock(&ipcpi.alloc_lock); if (ipcp_sdb_reserve(&sdb, sizeof(*msg) + len)) { - destroy_conn(fd); + fa_flow_fini(flow); return -1; } + msg = (struct fa_msg *) shm_du_buff_head(sdb); + memset(msg, 0, sizeof(*msg)); + pthread_rwlock_wrlock(&fa.flows_lock); - msg = (struct fa_msg *) shm_du_buff_head(sdb); msg->code = FLOW_REPLY; - msg->r_eid = hton32(fa.r_eid[fd]); + msg->r_eid = hton32(flow->r_eid); msg->s_eid = hton32(fd); msg->response = response; memcpy(msg + 1, data, len); if (response < 0) { - destroy_conn(fd); + fa_flow_fini(flow); ipcp_sdb_release(sdb); } else { psched_add(fa.psched, fd); } - ipcp_flow_get_qoscube(fd, &qc); - - assert(qc >= 0 && qc < QOS_CUBE_MAX); - - if (dt_write_packet(fa.r_addr[fd], qc, fa.fd, sdb)) { - destroy_conn(fd); + if (dt_write_packet(flow->r_addr, qc, fa.fd, sdb)) { + fa_flow_fini(flow); pthread_rwlock_unlock(&fa.flows_lock); ipcp_sdb_release(sdb); return -1; @@ -505,11 +566,11 @@ int fa_dealloc(int fd) if (ipcp_flow_fini(fd) < 0) return 0; - pthread_rwlock_wrlock(&fa.flows_lock); - psched_del(fa.psched, fd); - destroy_conn(fd); + pthread_rwlock_wrlock(&fa.flows_lock); + + fa_flow_fini(&fa.flows[fd]); pthread_rwlock_unlock(&fa.flows_lock); @@ -517,3 +578,60 @@ int fa_dealloc(int fd) return 0; } + +static int fa_update_remote(int fd, + uint16_t ece) +{ + struct fa_msg * msg; + struct shm_du_buff * sdb; + qoscube_t qc = QOS_CUBE_BE; + struct fa_flow * flow; + + if (ipcp_sdb_reserve(&sdb, sizeof(*msg))) { + return -1; + } + + msg = (struct fa_msg *) shm_du_buff_head(sdb); + + memset(msg, 0, sizeof(*msg)); + + flow = &fa.flows[fd]; + + pthread_rwlock_rdlock(&fa.flows_lock); + + msg->code = FLOW_UPDATE; + 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; + } + + pthread_rwlock_unlock(&fa.flows_lock); + + + return 0; +} + +void fa_ecn_update(int eid, + uint8_t ecn, + size_t len) +{ + struct fa_flow * flow; + bool update; + uint16_t ece; + + flow = &fa.flows[eid]; + + pthread_rwlock_wrlock(&fa.flows_lock); + + update = ca_ctx_update_rcv(flow->ctx, len, ecn, &ece); + + pthread_rwlock_unlock(&fa.flows_lock); + + if (update) + fa_update_remote(eid, ece); + +} diff --git a/src/ipcpd/unicast/fa.h b/src/ipcpd/unicast/fa.h index 12a10a0c..daba2a51 100644 --- a/src/ipcpd/unicast/fa.h +++ b/src/ipcpd/unicast/fa.h @@ -47,4 +47,8 @@ int fa_alloc_resp(int fd, int fa_dealloc(int fd); +void fa_ecn_update(int eid, + uint8_t ecn, + size_t len); + #endif /* OUROBOROS_IPCPD_UNICAST_FA_H */ diff --git a/src/ipcpd/unicast/main.c b/src/ipcpd/unicast/main.c index 0ab37d25..1b2cc14e 100644 --- a/src/ipcpd/unicast/main.c +++ b/src/ipcpd/unicast/main.c @@ -39,6 +39,7 @@ #include <ouroboros/time_utils.h> #include "addr_auth.h" +#include "ca.h" #include "connmgr.h" #include "dir.h" #include "dt.h" @@ -83,6 +84,11 @@ static int initialize_components(const struct ipcp_config * conf) log_dbg("IPCP got address %" PRIu64 ".", ipcpi.dt_addr); + if (ca_init(conf->cong_avoid)) { + log_err("Failed to initialize congestion avoidance."); + goto fail_ca; + } + if (dt_init(conf->routing_type, conf->addr_size, conf->eid_size, @@ -110,6 +116,8 @@ static int initialize_components(const struct ipcp_config * conf) fail_fa: dt_fini(); fail_dt: + ca_fini(); + fail_ca: addr_auth_fini(); fail_addr_auth: free(ipcpi.layer_name); @@ -125,6 +133,8 @@ static void finalize_components(void) dt_fini(); + ca_fini(); + addr_auth_fini(); free(ipcpi.layer_name); diff --git a/src/ipcpd/unicast/pol-ca-ops.h b/src/ipcpd/unicast/pol-ca-ops.h new file mode 100644 index 00000000..3cb8a9d2 --- /dev/null +++ b/src/ipcpd/unicast/pol-ca-ops.h @@ -0,0 +1,50 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2020 + * + * Congestion avoidance policy ops + * + * Dimitri Staessens <dimitri.staessens@ugent.be> + * Sander Vrijders <sander.vrijders@ugent.be> + * + * 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_IPCPD_UNICAST_POL_CA_OPS_H +#define OUROBOROS_IPCPD_UNICAST_POL_CA_OPS_H + +#include "ca.h" + +struct pol_ca_ops { + void * (* ctx_create)(void); + + void (* ctx_destroy)(void * ctx); + + ca_wnd_t (* ctx_update_snd)(void * ctx, + size_t len); + + bool (* ctx_update_rcv)(void * ctx, + size_t len, + uint8_t ecn, + uint16_t * ece); + + void (* ctx_update_ece)(void * ctx, + uint16_t ece); + + void (* wnd_wait)(ca_wnd_t wnd); + + uint8_t (* calc_ecn)(int fd, + 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 new file mode 100644 index 00000000..2de8f8e7 --- /dev/null +++ b/src/ipcpd/unicast/pol/ca-mb-ecn.c @@ -0,0 +1,216 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2020 + * + * Multi-bit ECN Congestion Avoidance + * + * Dimitri Staessens <dimitri.staessens@ugent.be> + * Sander Vrijders <sander.vrijders@ugent.be> + * + * 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/. + */ + +#if defined(__linux__) || defined(__CYGWIN__) +#define _DEFAULT_SOURCE +#else +#define _POSIX_C_SOURCE 200809L +#endif + +#include "config.h" + +#include <ouroboros/ipcp-dev.h> +#include <ouroboros/time_utils.h> + +#include "ca-mb-ecn.h" + +#include <stdlib.h> +#include <string.h> + +/* congestion avoidance constants */ +#define CA_SHFT 5 +#define CA_WND (1 << CA_SHFT) +#define CA_UPD (1 << (CA_SHFT - 3)) +#define CA_SLOT 18 +#define CA_AI 20000 +#define ECN_Q_SHFT 5 +#define ts_to_ns(ts) (ts.tv_sec * BILLION + ts.tv_nsec) + +struct mb_ecn_ctx { + uint16_t rx_ece; /* level of congestion (upstream) */ + size_t rx_ctr; /* receiver side packet counter */ + + uint16_t tx_ece; /* level of congestion (downstream) */ + size_t tx_ctr; /* sender side packet counter */ + size_t tx_aps; /* average packet size */ + time_t tx_wnd; /* tgt time to send packets (ns) */ + bool tx_cav; /* Congestion avoidance */ + size_t tx_slot; + + struct timespec t_sent; /* last sent packet */ +}; + +struct pol_ca_ops mb_ecn_ca_ops = { + .ctx_create = mb_ecn_ctx_create, + .ctx_destroy = mb_ecn_ctx_destroy, + .ctx_update_snd = mb_ecn_ctx_update_snd, + .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 +}; + +void * mb_ecn_ctx_create(void) +{ + + struct mb_ecn_ctx * ctx; + + ctx = malloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + memset(ctx, 0, sizeof(*ctx)); + + return (void *) ctx; +} + +void mb_ecn_ctx_destroy(void * ctx) +{ + free(ctx); +} + +ca_wnd_t mb_ecn_ctx_update_snd(void * _ctx, + size_t len) +{ + struct timespec now; + size_t slot; + time_t gap; + ca_wnd_t wnd; + + struct mb_ecn_ctx * ctx = _ctx; + + clock_gettime(PTHREAD_COND_CLOCK, &now); + + if (ctx->tx_wnd == 0) { /* 10 ms initial window estimate */ + ctx->tx_wnd = 10 * MILLION; + gap = ctx->tx_wnd >> CA_SHFT; + ctx->tx_aps = len >> CA_SHFT; + ctx->tx_slot = ts_to_ns(now) >> CA_SLOT; + } else { + gap = ts_diff_ns(&ctx->t_sent, &now); + ctx->tx_aps -= ctx->tx_aps >> CA_SHFT; + ctx->tx_aps += len; + } + + ctx->t_sent = now; + + slot = ts_to_ns(now) >> CA_SLOT; + + ctx->tx_ctr++; + + if (slot - ctx->tx_slot > 0) { + ctx->tx_slot = slot; + + if (ctx->tx_ctr > CA_WND) + ctx->tx_ece = 0; + + /* Slow start */ + if (!ctx->tx_cav) { + ctx->tx_wnd >>= 1; + /* Multiplicative Decrease */ + } else if (ctx->tx_ece) { /* MD */ + ctx->tx_wnd += (ctx->tx_wnd * ctx->tx_ece) + >> (CA_SHFT + 8); + /* Additive Increase */ + } else { + size_t bw = ctx->tx_aps * BILLION / ctx->tx_wnd; + bw += CA_AI; + ctx->tx_wnd = ctx->tx_aps * BILLION / bw; + } + } + + wnd.wait = (ctx->tx_wnd >> CA_SHFT) - gap; + + return wnd; +} + +void mb_ecn_wnd_wait(ca_wnd_t wnd) +{ + if (wnd.wait > 0) { + struct timespec s = {0, 0}; + if (wnd.wait > BILLION) /* Don't care throttling < 1pps */ + s.tv_sec = 1; + else + s.tv_nsec = wnd.wait; + + nanosleep(&s, NULL); + } +} + +bool mb_ecn_ctx_update_rcv(void * _ctx, + size_t len, + uint8_t ecn, + uint16_t * ece) +{ + struct mb_ecn_ctx* ctx = _ctx; + bool update; + + (void) len; + + if ((ctx->rx_ece | ecn) == 0) + return false; + + if (ecn == 0) { + /* end of congestion */ + ctx->rx_ece >>= 2; + update = ctx->rx_ece == 0; + } else { + if (ctx->rx_ece == 0) { + /* start of congestion */ + ctx->rx_ece = ecn; + ctx->rx_ctr = 0; + update = true; + } else { + /* congestion update */ + ctx->rx_ece -= ctx->rx_ece >> CA_SHFT; + ctx->rx_ece += ecn; + update = (ctx->rx_ctr++ & (CA_UPD - 1)) == true; + } + } + + *ece = ctx->rx_ece; + + return update; +} + + +void mb_ecn_ctx_update_ece(void * _ctx, + uint16_t ece) +{ + struct mb_ecn_ctx* ctx = _ctx; + + ctx->tx_ece = ece; + ctx->tx_ctr = 0; + ctx->tx_cav = true; +} + +uint8_t mb_ecn_calc_ecn(int fd, + size_t len) +{ + size_t q; + + (void) len; + + q = ipcp_flow_queued(fd); + + return (uint8_t) (q >> ECN_Q_SHFT); +} diff --git a/src/ipcpd/unicast/pol/ca-mb-ecn.h b/src/ipcpd/unicast/pol/ca-mb-ecn.h new file mode 100644 index 00000000..456b9b13 --- /dev/null +++ b/src/ipcpd/unicast/pol/ca-mb-ecn.h @@ -0,0 +1,50 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2020 + * + * Multi-bit ECN Congestion Avoidance + * + * Dimitri Staessens <dimitri.staessens@ugent.be> + * Sander Vrijders <sander.vrijders@ugent.be> + * + * 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_IPCPD_UNICAST_CA_MB_ECN_H +#define OUROBOROS_IPCPD_UNICAST_CA_MB_ECN_H + +#include "pol-ca-ops.h" + +void * mb_ecn_ctx_create(void); + +void mb_ecn_ctx_destroy(void * ctx); + +ca_wnd_t mb_ecn_ctx_update_snd(void * ctx, + size_t len); + +bool mb_ecn_ctx_update_rcv(void * ctx, + size_t len, + uint8_t ecn, + uint16_t * ece); + +void mb_ecn_ctx_update_ece(void * ctx, + uint16_t ece); + +void mb_ecn_wnd_wait(ca_wnd_t wnd); + +uint8_t mb_ecn_calc_ecn(int fd, + 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 new file mode 100644 index 00000000..d0d89a2e --- /dev/null +++ b/src/ipcpd/unicast/pol/ca-nop.c @@ -0,0 +1,93 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2020 + * + * Dummy Congestion Avoidance + * + * Dimitri Staessens <dimitri.staessens@ugent.be> + * Sander Vrijders <sander.vrijders@ugent.be> + * + * 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 "ca-nop.h" + +#include <string.h> + +struct pol_ca_ops nop_ca_ops = { + .ctx_create = nop_ctx_create, + .ctx_destroy = nop_ctx_destroy, + .ctx_update_snd = nop_ctx_update_snd, + .ctx_update_rcv = nop_ctx_update_rcv, + .ctx_update_ece = nop_ctx_update_ece, + .wnd_wait = nop_wnd_wait, + .calc_ecn = nop_calc_ecn +}; + +void * nop_ctx_create(void) +{ + return (void *) 1; +} + +void nop_ctx_destroy(void * ctx) +{ + (void) ctx; +} + +ca_wnd_t nop_ctx_update_snd(void * ctx, + size_t len) +{ + ca_wnd_t wnd; + + (void) ctx; + (void) len; + + memset(&wnd, 0, sizeof(wnd)); + + return wnd; +} + +void nop_wnd_wait(ca_wnd_t wnd) +{ + (void) wnd; +} + +bool nop_ctx_update_rcv(void * ctx, + size_t len, + uint8_t ecn, + uint16_t * ece) +{ + (void) ctx; + (void) len; + (void) ecn; + (void) ece; + + return false; +} + +void nop_ctx_update_ece(void * ctx, + uint16_t ece) +{ + (void) ctx; + (void) ece; +} + + +uint8_t nop_calc_ecn(int fd, + size_t len) +{ + (void) fd; + (void) len; + + return 0; +} diff --git a/src/ipcpd/unicast/pol/ca-nop.h b/src/ipcpd/unicast/pol/ca-nop.h new file mode 100644 index 00000000..baf649d8 --- /dev/null +++ b/src/ipcpd/unicast/pol/ca-nop.h @@ -0,0 +1,50 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2020 + * + * Dummy Congestion Avoidance + * + * Dimitri Staessens <dimitri.staessens@ugent.be> + * Sander Vrijders <sander.vrijders@ugent.be> + * + * 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_IPCPD_UNICAST_CA_NOP_H +#define OUROBOROS_IPCPD_UNICAST_CA_NOP_H + +#include "pol-ca-ops.h" + +void * nop_ctx_create(void); + +void nop_ctx_destroy(void * ctx); + +ca_wnd_t nop_ctx_update_snd(void * ctx, + size_t len); + +bool nop_ctx_update_rcv(void * ctx, + size_t len, + uint8_t ecn, + uint16_t * ece); + +void nop_ctx_update_ece(void * ctx, + uint16_t ece); + +void nop_wnd_wait(ca_wnd_t wnd); + +uint8_t nop_calc_ecn(int fd, + size_t len); + +extern struct pol_ca_ops nop_ca_ops; + +#endif /* OUROBOROS_IPCPD_UNICAST_CA_NOP_H */ diff --git a/src/ipcpd/unicast/pol/link_state.c b/src/ipcpd/unicast/pol/link_state.c index d9482876..ca8a7c50 100644 --- a/src/ipcpd/unicast/pol/link_state.c +++ b/src/ipcpd/unicast/pol/link_state.c @@ -812,8 +812,12 @@ static void handle_event(void * self, switch (event) { case NOTIFY_DT_CONN_ADD: pthread_rwlock_rdlock(&ls.db_lock); + + pthread_cleanup_push((void (*) (void *)) pthread_rwlock_unlock, + (void *) &ls.db_lock); + send_lsm(ipcpi.dt_addr, c->conn_info.addr, 0); - pthread_rwlock_unlock(&ls.db_lock); + pthread_cleanup_pop(true); if (lsdb_add_nb(c->conn_info.addr, c->flow_info.fd, NB_DT)) log_dbg("Failed to add neighbor to LSDB."); diff --git a/src/lib/dev.c b/src/lib/dev.c index 4b78c1db..a6be762b 100644 --- a/src/lib/dev.c +++ b/src/lib/dev.c @@ -1768,6 +1768,21 @@ int ipcp_flow_get_qoscube(int fd, return 0; } +size_t ipcp_flow_queued(int fd) +{ + size_t q; + + pthread_rwlock_rdlock(&ai.lock); + + assert(ai.flows[fd].flow_id >= 0); + + q = shm_rbuff_queued(ai.flows[fd].tx_rb); + + pthread_rwlock_unlock(&ai.lock); + + return q; +} + ssize_t local_flow_read(int fd) { ssize_t ret; diff --git a/src/lib/ipcp_config.proto b/src/lib/ipcp_config.proto index 23c65e94..7bf5329e 100644 --- a/src/lib/ipcp_config.proto +++ b/src/lib/ipcp_config.proto @@ -36,15 +36,16 @@ message ipcp_config_msg { optional uint32 max_ttl = 5; optional uint32 addr_auth_type = 6; optional uint32 routing_type = 7; + optional uint32 cong_avoid = 8; // Config for UDP - optional uint32 ip_addr = 8; - optional uint32 dns_addr = 9; - optional uint32 clt_port = 10; - optional uint32 srv_port = 11; + optional uint32 ip_addr = 9; + optional uint32 dns_addr = 10; + optional uint32 clt_port = 11; + optional uint32 srv_port = 12; // Config for the Ethernet - optional string dev = 12; + optional string dev = 13; // Config for DIX Ethernet - optional uint32 ethertype = 13; + optional uint32 ethertype = 14; } enum enroll_code { diff --git a/src/lib/irm.c b/src/lib/irm.c index 08dffb6c..42ad74fa 100644 --- a/src/lib/irm.c +++ b/src/lib/irm.c @@ -132,6 +132,8 @@ int irm_bootstrap_ipcp(pid_t pid, config.addr_auth_type = conf->addr_auth_type; config.has_routing_type = true; config.routing_type = conf->routing_type; + config.has_cong_avoid = true; + config.cong_avoid = conf->cong_avoid; break; case IPCP_UDP: config.has_ip_addr = true; diff --git a/src/tools/irm/irm_ipcp_bootstrap.c b/src/tools/irm/irm_ipcp_bootstrap.c index 84b6759a..ba57a506 100644 --- a/src/tools/irm/irm_ipcp_bootstrap.c +++ b/src/tools/irm/irm_ipcp_bootstrap.c @@ -50,7 +50,7 @@ #include <sys/socket.h> #endif -#define UNICAST "unicast" +#define UNICAST "unicast" #define BROADCAST "broadcast" #define UDP "udp" #define ETH_LLC "eth-llc" @@ -70,6 +70,7 @@ #define DEFAULT_TTL 60 #define DEFAULT_ADDR_AUTH ADDR_AUTH_FLAT_RANDOM #define DEFAULT_ROUTING ROUTING_LINK_STATE +#define DEFAULT_CONG_AVOID CA_MB_ECN #define DEFAULT_HASH_ALGO DIR_HASH_SHA3_256 #define DEFAULT_ETHERTYPE 0xA000 #define DEFAULT_CLIENT_PORT 0x0000 /* random port */ @@ -79,6 +80,8 @@ #define LINK_STATE_ROUTING "link_state" #define LINK_STATE_LFA_ROUTING "lfa" #define LINK_STATE_ECM_ROUTING "ecmp" +#define NONE_CA "none" +#define MB_ECN_CA "mb-ecn" static void usage(void) { @@ -95,11 +98,13 @@ static void usage(void) " [ttl (max time-to-live value, default: %d)]\n" " [addr_auth <ADDRESS_POLICY> (default: %s)]\n" " [routing <ROUTING_POLICY> (default: %s)]\n" + " [congestion <CONG_POLICY> (default: %s)]\n" " [hash [ALGORITHM] (default: %s)]\n" " [autobind]\n" - "where ADDRESS_POLICY = {"FLAT_RANDOM_ADDR_AUTH"}\n" - " ROUTING_POLICY = {"LINK_STATE_ROUTING " " + "where ADDRESS_POLICY = {" FLAT_RANDOM_ADDR_AUTH "}\n" + " ROUTING_POLICY = {" LINK_STATE_ROUTING " " LINK_STATE_LFA_ROUTING " " LINK_STATE_ECM_ROUTING "}\n" + " CONG_POLICY = {" NONE_CA " " MB_ECN_CA "}\n" " ALGORITHM = {" SHA3_224 " " SHA3_256 " " SHA3_384 " " SHA3_512 "}\n\n" "if TYPE == " UDP "\n" @@ -130,7 +135,7 @@ static void usage(void) "if TYPE == " BROADCAST "\n" " [autobind]\n\n", DEFAULT_ADDR_SIZE, DEFAULT_EID_SIZE, DEFAULT_TTL, - FLAT_RANDOM_ADDR_AUTH, LINK_STATE_ROUTING, + FLAT_RANDOM_ADDR_AUTH, LINK_STATE_ROUTING, MB_ECN_CA, SHA3_256, DEFAULT_SERVER_PORT, SHA3_256, 0xA000, SHA3_256, SHA3_256, SHA3_256); } @@ -138,29 +143,30 @@ static void usage(void) int do_bootstrap_ipcp(int argc, char ** argv) { - char * ipcp = NULL; - pid_t pid = -1; - struct ipcp_config conf; - uint8_t addr_size = DEFAULT_ADDR_SIZE; - uint8_t eid_size = DEFAULT_EID_SIZE; - uint8_t max_ttl = DEFAULT_TTL; - enum pol_addr_auth addr_auth_type = DEFAULT_ADDR_AUTH; - enum pol_routing routing_type = DEFAULT_ROUTING; - enum pol_dir_hash hash_algo = DEFAULT_HASH_ALGO; - uint32_t ip_addr = 0; - uint32_t dns_addr = DEFAULT_DDNS; - char * ipcp_type = NULL; - enum ipcp_type type = IPCP_INVALID; - char * layer = NULL; - char * dev = NULL; - uint16_t ethertype = DEFAULT_ETHERTYPE; - struct ipcp_info * ipcps; - ssize_t len = 0; - int i = 0; - bool autobind = false; - int cargs; - int cport = DEFAULT_CLIENT_PORT; - int sport = DEFAULT_SERVER_PORT; + char * ipcp = NULL; + pid_t pid = -1; + struct ipcp_config conf; + uint8_t addr_size = DEFAULT_ADDR_SIZE; + uint8_t eid_size = DEFAULT_EID_SIZE; + uint8_t max_ttl = DEFAULT_TTL; + enum pol_addr_auth addr_auth_type = DEFAULT_ADDR_AUTH; + enum pol_routing routing_type = DEFAULT_ROUTING; + enum pol_dir_hash hash_algo = DEFAULT_HASH_ALGO; + enum pol_cong_avoid cong_avoid = DEFAULT_CONG_AVOID; + uint32_t ip_addr = 0; + uint32_t dns_addr = DEFAULT_DDNS; + char * ipcp_type = NULL; + enum ipcp_type type = IPCP_INVALID; + char * layer = NULL; + char * dev = NULL; + uint16_t ethertype = DEFAULT_ETHERTYPE; + struct ipcp_info * ipcps; + ssize_t len = 0; + int i = 0; + bool autobind = false; + int cargs; + int cport = DEFAULT_CLIENT_PORT; + int sport = DEFAULT_SERVER_PORT; while (argc > 0) { cargs = 2; @@ -230,6 +236,14 @@ int do_bootstrap_ipcp(int argc, routing_type = ROUTING_LINK_STATE_ECMP; else goto unknown_param; + } else if (matches(*argv, "congestion") == 0) { + if (strcmp(NONE_CA, *(argv + 1)) == 0) + cong_avoid = CA_NONE; + else if (strcmp(MB_ECN_CA, + *(argv + 1)) == 0) + cong_avoid = CA_MB_ECN; + else + goto unknown_param; } else { printf("Unknown option: \"%s\".\n", *argv); return -1; @@ -315,6 +329,7 @@ int do_bootstrap_ipcp(int argc, conf.max_ttl = max_ttl; conf.addr_auth_type = addr_auth_type; conf.routing_type = routing_type; + conf.cong_avoid = cong_avoid; break; case IPCP_UDP: if (ip_addr == 0) |