From b74980761cdcd9a706760ae9a4efb3806ca9bee2 Mon Sep 17 00:00:00 2001 From: Dimitri Staessens Date: Thu, 7 Jun 2018 23:35:14 +0200 Subject: lib: Add a data qos cube This adds a data qos cube that is reliable. Reliable qos can be selected by setting the loss parameter of the qosspec to 0. Signed-off-by: Dimitri Staessens Signed-off-by: Sander Vrijders --- include/ouroboros/qos.h | 2 ++ include/ouroboros/qoscube.h | 1 + src/ipcpd/CMakeLists.txt | 6 ++++++ src/ipcpd/config.h.in | 1 + src/ipcpd/eth/eth.c | 2 +- src/ipcpd/normal/sdu_sched.c | 3 ++- src/lib/dev.c | 4 ++-- src/lib/frct.c | 9 ++++++++- src/lib/qos.c | 27 +++++++++++++++++++-------- src/lib/qoscube.c | 6 +++++- src/tools/oping/oping.c | 5 ++++- 11 files changed, 51 insertions(+), 15 deletions(-) diff --git a/include/ouroboros/qos.h b/include/ouroboros/qos.h index 2419195b..011828d7 100644 --- a/include/ouroboros/qos.h +++ b/include/ouroboros/qos.h @@ -30,6 +30,7 @@ typedef struct qos_spec { uint32_t delay; /* In ms */ uint64_t bandwidth; /* In bits/s */ uint8_t availability; /* Class of 9s */ + uint32_t loss; /* Packet loss */ uint8_t in_order; /* In-order delivery, enables FRCT */ uint32_t maximum_interruption; /* In ms */ } qosspec_t; @@ -38,6 +39,7 @@ qosspec_t qos_raw; qosspec_t qos_best_effort; qosspec_t qos_video; qosspec_t qos_voice; +qosspec_t qos_data; __BEGIN_DECLS diff --git a/include/ouroboros/qoscube.h b/include/ouroboros/qoscube.h index 99563a06..e0e93a82 100644 --- a/include/ouroboros/qoscube.h +++ b/include/ouroboros/qoscube.h @@ -28,6 +28,7 @@ typedef enum qos_cube { QOS_CUBE_RAW = 0, QOS_CUBE_BE, + QOS_CUBE_DATA, QOS_CUBE_VIDEO, QOS_CUBE_VOICE, QOS_CUBE_MAX diff --git a/src/ipcpd/CMakeLists.txt b/src/ipcpd/CMakeLists.txt index d7523aeb..b706d432 100644 --- a/src/ipcpd/CMakeLists.txt +++ b/src/ipcpd/CMakeLists.txt @@ -8,6 +8,8 @@ set(IPCP_QOS_CUBE_VIDEO_PRIO 90 CACHE STRING "Priority for video QoS cube (0-99)") set(IPCP_QOS_CUBE_VOICE_PRIO 99 CACHE STRING "Priority for voice QoS cube (0-99)") +set(IPCP_QOS_CUBE_DATA_PRIO 0 CACHE STRING + "Priority for data QoS cube (0-99)") set(IPCP_MIN_THREADS 4 CACHE STRING "Minimum number of worker threads in the IPCP") set(IPCP_ADD_THREADS 4 CACHE STRING @@ -27,6 +29,10 @@ if ((IPCP_QOS_CUBE_BE_PRIO LESS 0) OR (IPCP_QOS_CUBE_BE_PRIO GREATER 99)) message(FATAL_ERROR "Invalid priority for best effort QoS cube") endif () +if ((IPCP_QOS_CUBE_DATA_PRIO LESS 0) OR (IPCP_QOS_CUBE_DATA_PRIO GREATER 99)) + message(FATAL_ERROR "Invalid priority for data QoS cube") +endif () + if ((IPCP_QOS_CUBE_VIDEO_PRIO LESS 0) OR (IPCP_QOS_CUBE_VIDEO_PRIO GREATER 99)) message(FATAL_ERROR "Invalid priority for video QoS cube") endif () diff --git a/src/ipcpd/config.h.in b/src/ipcpd/config.h.in index b7806f60..375ac750 100644 --- a/src/ipcpd/config.h.in +++ b/src/ipcpd/config.h.in @@ -42,6 +42,7 @@ #define QOS_PRIO_BE @IPCP_QOS_CUBE_BE_PRIO@ #define QOS_PRIO_VIDEO @IPCP_QOS_CUBE_VIDEO_PRIO@ #define QOS_PRIO_VOICE @IPCP_QOS_CUBE_VOICE_PRIO@ +#define QOS_PRIO_DATA @IPCP_QOS_CUBE_DATA_PRIO@ #define IPCP_SCHED_THR_MUL @IPCP_SCHED_THR_MUL@ #define PFT_SIZE @PFT_SIZE@ diff --git a/src/ipcpd/eth/eth.c b/src/ipcpd/eth/eth.c index caf9d2df..a58839f0 100644 --- a/src/ipcpd/eth/eth.c +++ b/src/ipcpd/eth/eth.c @@ -1504,7 +1504,7 @@ static int eth_ipcp_flow_alloc(int fd, assert(hash); - if (cube > QOS_CUBE_BE) { + if (cube > QOS_CUBE_DATA) { log_dbg("Unsupported QoS requested."); return -1; } diff --git a/src/ipcpd/normal/sdu_sched.c b/src/ipcpd/normal/sdu_sched.c index 529da113..0ae22895 100644 --- a/src/ipcpd/normal/sdu_sched.c +++ b/src/ipcpd/normal/sdu_sched.c @@ -39,7 +39,8 @@ static int qos_prio [] = { QOS_PRIO_RAW, QOS_PRIO_BE, QOS_PRIO_VIDEO, - QOS_PRIO_VOICE + QOS_PRIO_VOICE, + QOS_PRIO_DATA }; struct sdu_sched { diff --git a/src/lib/dev.c b/src/lib/dev.c index ee82bbaa..8417d63b 100644 --- a/src/lib/dev.c +++ b/src/lib/dev.c @@ -536,7 +536,7 @@ int flow_accept(qosspec_t * qs, assert(ai.flows[fd].frcti == NULL); if (qc != QOS_CUBE_RAW) { - ai.flows[fd].frcti = frcti_create(fd); + ai.flows[fd].frcti = frcti_create(fd, qc); if (ai.flows[fd].frcti == NULL) { flow_fini(fd); pthread_rwlock_unlock(&ai.lock); @@ -611,7 +611,7 @@ int flow_alloc(const char * dst, assert(ai.flows[fd].frcti == NULL); if (qc != QOS_CUBE_RAW) { - ai.flows[fd].frcti = frcti_create(fd); + ai.flows[fd].frcti = frcti_create(fd, qc); if (ai.flows[fd].frcti == NULL) { flow_fini(fd); pthread_rwlock_unlock(&ai.lock); diff --git a/src/lib/frct.c b/src/lib/frct.c index bcb031c3..00261272 100644 --- a/src/lib/frct.c +++ b/src/lib/frct.c @@ -105,7 +105,8 @@ static void frct_fini(void) timerwheel_destroy(frct.tw); } -static struct frcti * frcti_create(int fd) +static struct frcti * frcti_create(int fd, + qoscube_t qc) { struct frcti * frcti; time_t delta_t; @@ -133,6 +134,9 @@ static struct frcti * frcti_create(int fd) delta_t = (frcti->mpl + frcti->a + frcti->r) / 1000; + if (qc == QOS_CUBE_DATA) + frcti->snd_cr.cflags |= FRCTFRTX; + frcti->snd_cr.conf = true; frcti->snd_cr.inact = 3 * delta_t + 1; frcti->snd_cr.act = now.tv_sec - (frcti->snd_cr.inact + 1); @@ -317,6 +321,9 @@ static int __frcti_snd(struct frcti * frcti, pci->seqno = hton32(snd_cr->seqno++); if (!(snd_cr->cflags & FRCTFRTX)) snd_cr->lwe++; + else + /* TODO: update on ACK */ + snd_cr->lwe++; snd_cr->act = now.tv_sec; snd_cr->conf = false; diff --git a/src/lib/qos.c b/src/lib/qos.c index f5fbf1fb..bee6ed71 100644 --- a/src/lib/qos.c +++ b/src/lib/qos.c @@ -25,19 +25,22 @@ #include #include +#include qosspec_t qos_raw = { .delay = UINT32_MAX, - .bandwidth = UINT64_MAX, + .bandwidth = 0, .availability = 0, + .loss = 1, .in_order = 0, .maximum_interruption = UINT32_MAX }; qosspec_t qos_best_effort = { .delay = UINT32_MAX, - .bandwidth = UINT64_MAX, + .bandwidth = 0, .availability = 0, + .loss = 1, .in_order = 1, .maximum_interruption = UINT32_MAX }; @@ -46,27 +49,35 @@ qosspec_t qos_video = { .delay = 100, .bandwidth = UINT64_MAX, .availability = 3, + .loss = 1, .in_order = 1, .maximum_interruption = 100 }; qosspec_t qos_voice = { - .delay = 10, + .delay = 50, .bandwidth = 100000, .availability = 5, + .loss = 1, .in_order = 1, .maximum_interruption = 50 }; +qosspec_t qos_data = { + .delay = 1000, + .bandwidth = 0, + .availability = 0, + .in_order = 1, + .loss = 0, + .maximum_interruption = 2000 +}; + int qosspec_init(qosspec_t * qs) { if (qs == NULL) return -EINVAL; - qs->delay = UINT32_MAX; - qs->bandwidth = UINT64_MAX; - qs->availability = 0; - qs->maximum_interruption = UINT32_MAX; + *qs = qos_best_effort; return 0; } @@ -76,7 +87,7 @@ int qosspec_fini(qosspec_t * qs) if (qs == NULL) return -EINVAL; - qs = NULL; + memset(qs, 0, sizeof(*qs)); return 0; } diff --git a/src/lib/qoscube.c b/src/lib/qoscube.c index 12f7c277..5dfa35ad 100644 --- a/src/lib/qoscube.c +++ b/src/lib/qoscube.c @@ -27,7 +27,9 @@ qoscube_t qos_spec_to_cube(qosspec_t qs) { - if (qs.delay <= qos_voice.delay && + if (qs.loss == 0) + return QOS_CUBE_DATA; + else if (qs.delay <= qos_voice.delay && qs.bandwidth <= qos_voice.bandwidth && qs.availability >= qos_voice.availability && qs.maximum_interruption <= qos_voice.maximum_interruption) @@ -52,6 +54,8 @@ qosspec_t qos_cube_to_spec(qoscube_t qc) return qos_video; case QOS_CUBE_BE: return qos_best_effort; + case QOS_CUBE_DATA: + return qos_data; default: return qos_raw; } diff --git a/src/tools/oping/oping.c b/src/tools/oping/oping.c index 18801c2d..8396e261 100644 --- a/src/tools/oping/oping.c +++ b/src/tools/oping/oping.c @@ -122,7 +122,8 @@ static void usage(void) " -d, --duration Duration of the test (default 1s)\n" " -i, --interval Interval (default 1000ms)\n" " -n, --server-name Name of the oping server\n" - " -q, --qos QoS (raw, best, video or voice)\n" + " -q, --qos QoS (raw, best, video, voice, data)" + "\n" " -s, --size Payload size (B, default 64)\n" " -Q, --quiet Only print final statistics\n" " -D, --timeofday Print time of day before each line" @@ -230,6 +231,8 @@ int main(int argc, client.qs = qos_video; else if (strcmp(qos, "voice") == 0) client.qs = qos_voice; + else if (strcmp(qos, "data") == 0) + client.qs = qos_data; else printf("Unknown QoS cube, defaulting to raw.\n"); } -- cgit v1.2.3