diff --git a/src/gprs_ms.c b/src/gprs_ms.c index 63f454f9..6dc11a6a 100644 --- a/src/gprs_ms.c +++ b/src/gprs_ms.c @@ -113,19 +113,15 @@ struct GprsMs *ms_alloc(struct gprs_rlcmac_bts *bts, uint32_t tlli) ms->imsi[0] = '\0'; memset(&ms->timer, 0, sizeof(ms->timer)); ms->timer.cb = ms_release_timer_cb; - llc_queue_init(&ms->llc_queue); + llc_queue_init(&ms->llc_queue, ms); ms_set_mode(ms, GPRS); codel_interval = the_pcu->vty.llc_codel_interval_msec; + if (codel_interval == LLC_CODEL_USE_DEFAULT) + codel_interval = GPRS_CODEL_SLOW_INTERVAL_MS; + llc_queue_set_codel_interval(&ms->llc_queue, codel_interval); - if (codel_interval != LLC_CODEL_DISABLE) { - if (codel_interval == LLC_CODEL_USE_DEFAULT) - codel_interval = GPRS_CODEL_SLOW_INTERVAL_MS; - ms->codel_state = talloc(ms, struct gprs_codel); - gprs_codel_init(ms->codel_state); - gprs_codel_set_interval(ms->codel_state, codel_interval); - } ms->last_cs_not_low = now_msec(); ms->app_info_pending = false; diff --git a/src/gprs_ms.h b/src/gprs_ms.h index 3ebf7a5b..c5ee01c9 100644 --- a/src/gprs_ms.h +++ b/src/gprs_ms.h @@ -92,8 +92,6 @@ struct GprsMs { uint8_t reserved_dl_slots; uint8_t reserved_ul_slots; struct gprs_rlcmac_trx *current_trx; - - struct gprs_codel *codel_state; enum mcs_kind mode; struct rate_ctr_group *ctrs; @@ -218,11 +216,6 @@ static inline void ms_set_timeout(struct GprsMs *ms, unsigned secs) ms->delay = secs; } -static inline struct gprs_codel *ms_codel_state(const struct GprsMs *ms) -{ - return ms->codel_state; -} - static inline unsigned ms_nack_rate_dl(const struct GprsMs *ms) { return ms->nack_rate_dl; diff --git a/src/llc.c b/src/llc.c index c8d74d89..ddc1e038 100644 --- a/src/llc.c +++ b/src/llc.c @@ -21,6 +21,7 @@ #include #include "bts.h" +#include "gprs_ms.h" #include "pcu_utils.h" #include "llc.h" @@ -94,17 +95,32 @@ bool llc_is_user_data_frame(const uint8_t *data, size_t len) return true; } -void llc_queue_init(struct gprs_llc_queue *q) +void llc_queue_init(struct gprs_llc_queue *q, struct GprsMs *ms) { unsigned int i; + q->ms = ms; q->queue_size = 0; q->queue_octets = 0; q->avg_queue_delay = 0; - for (i = 0; i < ARRAY_SIZE(q->queue); i++) - INIT_LLIST_HEAD(&q->queue[i]); + for (i = 0; i < ARRAY_SIZE(q->pq); i++) { + INIT_LLIST_HEAD(&q->pq[i].queue); + gprs_codel_init(&q->pq[i].codel_state); + } } +/* interval=0 -> don't use codel in the LLC queue */ +void llc_queue_set_codel_interval(struct gprs_llc_queue *q, unsigned int interval) +{ + unsigned int i; + if (interval == LLC_CODEL_DISABLE) { + q->use_codel = false; + return; + } + q->use_codel = true; + for (i = 0; i < ARRAY_SIZE(q->pq); i++) + gprs_codel_set_interval(&q->pq[i].codel_state, interval); +} static enum gprs_llc_queue_prio llc_sapi2prio(uint8_t sapi) { @@ -137,7 +153,7 @@ void llc_queue_enqueue(struct gprs_llc_queue *q, struct msgb *llc_msg, const str osmo_clock_gettime(CLOCK_MONOTONIC, &meta_storage->recv_time); meta_storage->expire_time = *expire_time; - msgb_enqueue(&q->queue[prio], llc_msg); + msgb_enqueue(&q->pq[prio].queue, llc_msg); } void llc_queue_clear(struct gprs_llc_queue *q, struct gprs_rlcmac_bts *bts) @@ -145,8 +161,8 @@ void llc_queue_clear(struct gprs_llc_queue *q, struct gprs_rlcmac_bts *bts) struct msgb *msg; unsigned int i; - for (i = 0; i < ARRAY_SIZE(q->queue); i++) { - while ((msg = msgb_dequeue(&q->queue[i]))) { + for (i = 0; i < ARRAY_SIZE(q->pq); i++) { + while ((msg = msgb_dequeue(&q->pq[i].queue))) { if (bts) bts_do_rate_ctr_inc(bts, CTR_LLC_FRAME_DROPPED); msgb_free(msg); @@ -166,13 +182,13 @@ void llc_queue_move_and_merge(struct gprs_llc_queue *q, struct gprs_llc_queue *o size_t queue_octets = 0; INIT_LLIST_HEAD(&new_queue); - for (i = 0; i < ARRAY_SIZE(q->queue); i++) { + for (i = 0; i < ARRAY_SIZE(q->pq); i++) { while (1) { if (msg1 == NULL) - msg1 = msgb_dequeue(&q->queue[i]); + msg1 = msgb_dequeue(&q->pq[i].queue); if (msg2 == NULL) - msg2 = msgb_dequeue(&o->queue[i]); + msg2 = msgb_dequeue(&o->pq[i].queue); if (msg1 == NULL && msg2 == NULL) break; @@ -201,9 +217,9 @@ void llc_queue_move_and_merge(struct gprs_llc_queue *q, struct gprs_llc_queue *o queue_octets += msgb_length(msg); } - OSMO_ASSERT(llist_empty(&q->queue[i])); - OSMO_ASSERT(llist_empty(&o->queue[i])); - llist_splice_init(&new_queue, &q->queue[i]); + OSMO_ASSERT(llist_empty(&q->pq[i].queue)); + OSMO_ASSERT(llist_empty(&o->pq[i].queue)); + llist_splice_init(&new_queue, &q->pq[i].queue); } o->queue_size = 0; @@ -214,7 +230,7 @@ void llc_queue_move_and_merge(struct gprs_llc_queue *q, struct gprs_llc_queue *o #define ALPHA 0.5f -struct msgb *llc_queue_dequeue(struct gprs_llc_queue *q, const struct MetaInfo **info) +static struct msgb *llc_queue_pick_msg(struct gprs_llc_queue *q, enum gprs_llc_queue_prio *prio) { struct msgb *msg; struct timespec *tv, tv_now, tv_result; @@ -222,18 +238,17 @@ struct msgb *llc_queue_dequeue(struct gprs_llc_queue *q, const struct MetaInfo * unsigned int i; const struct MetaInfo *meta_storage; - for (i = 0; i < ARRAY_SIZE(q->queue); i++) { - if ((msg = msgb_dequeue(&q->queue[i]))) + for (i = 0; i < ARRAY_SIZE(q->pq); i++) { + if ((msg = msgb_dequeue(&q->pq[i].queue))) { + *prio = (enum gprs_llc_queue_prio)i; break; + } } if (!msg) return NULL; meta_storage = (struct MetaInfo *)&msg->cb[0]; - if (info) - *info = meta_storage; - q->queue_size -= 1; q->queue_octets -= msgb_length(msg); @@ -248,6 +263,85 @@ struct msgb *llc_queue_dequeue(struct gprs_llc_queue *q, const struct MetaInfo * return msg; } +struct msgb *llc_queue_dequeue(struct gprs_llc_queue *q) +{ + struct msgb *msg; + struct timespec tv_now, tv_now2; + uint32_t octets = 0, frames = 0; + struct gprs_rlcmac_bts *bts = q->ms->bts; + struct gprs_pcu *pcu = bts->pcu; + struct timespec hyst_delta = {0, 0}; + const unsigned keep_small_thresh = 60; + enum gprs_llc_queue_prio prio; + + if (pcu->vty.llc_discard_csec) + csecs_to_timespec(pcu->vty.llc_discard_csec, &hyst_delta); + + osmo_clock_gettime(CLOCK_MONOTONIC, &tv_now); + timespecadd(&tv_now, &hyst_delta, &tv_now2); + + while ((msg = llc_queue_pick_msg(q, &prio))) { + const struct MetaInfo *info = (const struct MetaInfo *)&msg->cb[0]; + const struct timespec *tv_disc = &info->expire_time; + const struct timespec *tv_recv = &info->recv_time; + + gprs_bssgp_update_queue_delay(tv_recv, &tv_now); + + if (q->use_codel) { + int bytes = llc_queue_octets(q); + if (gprs_codel_control(&q->pq[prio].codel_state, tv_recv, &tv_now, bytes)) + goto drop_frame; + } + + /* Is the age below the low water mark? */ + if (!llc_queue_is_frame_expired(&tv_now2, tv_disc)) + break; + + /* Is the age below the high water mark */ + if (!llc_queue_is_frame_expired(&tv_now, tv_disc)) { + /* Has the previous message not been dropped? */ + if (frames == 0) + break; + + /* Hysteresis mode, try to discard LLC messages until + * the low water mark has been reached */ + + /* Check whether to abort the hysteresis mode */ + + /* Is the frame small, perhaps only a TCP ACK? */ + if (msg->len <= keep_small_thresh) + break; + + /* Is it a GMM message? */ + if (!llc_is_user_data_frame(msg->data, msg->len)) + break; + } + + bts_do_rate_ctr_inc(bts, CTR_LLC_FRAME_TIMEDOUT); +drop_frame: + frames++; + octets += msg->len; + msgb_free(msg); + bts_do_rate_ctr_inc(bts, CTR_LLC_FRAME_DROPPED); + continue; + } + + if (frames) { + LOGPMS(q->ms, DTBFDL, LOGL_NOTICE, "Discarding LLC PDU " + "because lifetime limit reached, " + "count=%u new_queue_size=%zu\n", + frames, llc_queue_size(q)); + if (frames > 0xff) + frames = 0xff; + if (octets > 0xffffff) + octets = 0xffffff; + if (pcu->bssgp.bctx) + bssgp_tx_llc_discarded(pcu->bssgp.bctx, ms_tlli(q->ms), frames, octets); + } + + return msg; +} + void llc_queue_calc_pdu_lifetime(struct gprs_rlcmac_bts *bts, const uint16_t pdu_delay_csec, struct timespec *tv) { uint16_t delay_csec; diff --git a/src/llc.h b/src/llc.h index adfab657..fe14c6aa 100644 --- a/src/llc.h +++ b/src/llc.h @@ -28,9 +28,12 @@ extern "C" { #include #include +#include "gprs_codel.h" + #define LLC_MAX_LEN 1543 struct gprs_rlcmac_bts; +struct GprsMs; struct gprs_llc_hdr { #if OSMO_IS_LITTLE_ENDIAN @@ -110,22 +113,29 @@ enum gprs_llc_queue_prio { /* lowest value has highest prio */ LLC_QUEUE_PRIO_OTHER, /* Other SAPIs */ _LLC_QUEUE_PRIO_SIZE /* used to calculate size of enum */ }; +struct gprs_llc_prio_queue { + struct gprs_codel codel_state; + struct llist_head queue; /* queued LLC DL data. See enum gprs_llc_queue_prio. */ +}; struct gprs_llc_queue { + struct GprsMs *ms; /* backpointer */ uint32_t avg_queue_delay; /* Average delay of data going through the queue */ size_t queue_size; size_t queue_octets; - struct llist_head queue[_LLC_QUEUE_PRIO_SIZE]; /* queued LLC DL data. See enum gprs_llc_queue_prio. */ + bool use_codel; + struct gprs_llc_prio_queue pq[_LLC_QUEUE_PRIO_SIZE]; /* queued LLC DL data. See enum gprs_llc_queue_prio. */ }; void llc_queue_calc_pdu_lifetime(struct gprs_rlcmac_bts *bts, const uint16_t pdu_delay_csec, struct timespec *tv); bool llc_queue_is_frame_expired(const struct timespec *tv_now, const struct timespec *tv); -void llc_queue_init(struct gprs_llc_queue *q); +void llc_queue_init(struct gprs_llc_queue *q, struct GprsMs *ms); void llc_queue_clear(struct gprs_llc_queue *q, struct gprs_rlcmac_bts *bts); +void llc_queue_set_codel_interval(struct gprs_llc_queue *q, unsigned int interval); void llc_queue_move_and_merge(struct gprs_llc_queue *q, struct gprs_llc_queue *o); void llc_queue_enqueue(struct gprs_llc_queue *q, struct msgb *llc_msg, const struct timespec *expire_time); -struct msgb *llc_queue_dequeue(struct gprs_llc_queue *q, const struct MetaInfo **info); +struct msgb *llc_queue_dequeue(struct gprs_llc_queue *q); static inline size_t llc_queue_size(const struct gprs_llc_queue *q) { diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 01b8f684..9c99cf6d 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -343,83 +343,6 @@ int dl_tbf_handle(struct gprs_rlcmac_bts *bts, return rc; } -struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx) -{ - struct msgb *msg; - struct timespec tv_now, tv_now2; - uint32_t octets = 0, frames = 0; - struct timespec hyst_delta = {0, 0}; - const unsigned keep_small_thresh = 60; - const MetaInfo *info; - - if (the_pcu->vty.llc_discard_csec) - csecs_to_timespec(the_pcu->vty.llc_discard_csec, &hyst_delta); - - osmo_clock_gettime(CLOCK_MONOTONIC, &tv_now); - timespecadd(&tv_now, &hyst_delta, &tv_now2); - - while ((msg = llc_queue_dequeue(llc_queue(), &info))) { - const struct timespec *tv_disc = &info->expire_time; - const struct timespec *tv_recv = &info->recv_time; - - gprs_bssgp_update_queue_delay(tv_recv, &tv_now); - - if (ms() && ms_codel_state(ms())) { - int bytes = llc_queue_octets(llc_queue()); - if (gprs_codel_control(ms_codel_state(ms()), - tv_recv, &tv_now, bytes)) - goto drop_frame; - } - - /* Is the age below the low water mark? */ - if (!llc_queue_is_frame_expired(&tv_now2, tv_disc)) - break; - - /* Is the age below the high water mark */ - if (!llc_queue_is_frame_expired(&tv_now, tv_disc)) { - /* Has the previous message not been dropped? */ - if (frames == 0) - break; - - /* Hysteresis mode, try to discard LLC messages until - * the low water mark has been reached */ - - /* Check whether to abort the hysteresis mode */ - - /* Is the frame small, perhaps only a TCP ACK? */ - if (msg->len <= keep_small_thresh) - break; - - /* Is it a GMM message? */ - if (!llc_is_user_data_frame(msg->data, msg->len)) - break; - } - - bts_do_rate_ctr_inc(bts, CTR_LLC_FRAME_TIMEDOUT); -drop_frame: - frames++; - octets += msg->len; - msgb_free(msg); - bts_do_rate_ctr_inc(bts, CTR_LLC_FRAME_DROPPED); - continue; - } - - if (frames) { - LOGPTBFDL(this, LOGL_NOTICE, "Discarding LLC PDU " - "because lifetime limit reached, " - "count=%u new_queue_size=%zu\n", - frames, llc_queue_size(llc_queue())); - if (frames > 0xff) - frames = 0xff; - if (octets > 0xffffff) - octets = 0xffffff; - if (bctx) - bssgp_tx_llc_discarded(bctx, tlli(), frames, octets); - } - - return msg; -} - bool gprs_rlcmac_dl_tbf::restart_bsn_cycle() { /* If V(S) == V(A) and finished state, we would have received @@ -628,7 +551,7 @@ void gprs_rlcmac_dl_tbf::schedule_next_frame() return; /* dequeue next LLC frame, if any */ - msg = llc_dequeue(bts->pcu->bssgp.bctx); + msg = llc_queue_dequeue(llc_queue()); if (!msg) return; diff --git a/src/tbf_dl.h b/src/tbf_dl.h index c0c0284f..0f531eca 100644 --- a/src/tbf_dl.h +++ b/src/tbf_dl.h @@ -57,8 +57,6 @@ struct gprs_rlcmac_dl_tbf : public gprs_rlcmac_tbf { void set_window_size(); void update_coding_scheme_counter_dl(enum CodingScheme cs); - struct msgb *llc_dequeue(bssgp_bvc_ctx *bctx); - /* Please note that all variables here will be reset when changing * from WAIT RELEASE back to FLOW state (re-use of TBF). * All states that need reset must be in this struct, so this is why diff --git a/tests/llc/LlcTest.cpp b/tests/llc/LlcTest.cpp index b18f6de5..dd4c80ca 100644 --- a/tests/llc/LlcTest.cpp +++ b/tests/llc/LlcTest.cpp @@ -24,11 +24,14 @@ extern "C" { #include } -#include "llc.h" #include "gprs_debug.h" +#include "bts.h" extern "C" { #include "pcu_vty.h" +#include "gprs_pcu.h" +#include "llc.h" +#include "gprs_ms.h" #include #include @@ -44,6 +47,15 @@ int16_t spoof_mnc = 0, spoof_mcc = 0; bool spoof_mnc_3_digits = false; static struct timespec *clk_mono_override_time; +static struct gprs_llc_queue *prepare_queue(void) +{ + the_pcu = gprs_pcu_alloc(tall_pcu_ctx); + the_pcu->vty.llc_codel_interval_msec = LLC_CODEL_DISABLE; + struct gprs_rlcmac_bts *bts = bts_alloc(the_pcu, 0); + struct GprsMs *ms = bts_alloc_ms(bts, 0, 0); + return ms_llc_queue(ms); +} + static void enqueue_data(gprs_llc_queue *queue, const uint8_t *data, size_t len, const struct timespec *expire_time) { @@ -65,8 +77,9 @@ static void dequeue_and_check(gprs_llc_queue *queue, const uint8_t *exp_data, struct msgb *llc_msg; const MetaInfo *info_res; - llc_msg = llc_queue_dequeue(queue, &info_res); + llc_msg = llc_queue_dequeue(queue); OSMO_ASSERT(llc_msg != NULL); + info_res = (struct MetaInfo *)&llc_msg->cb[0]; fprintf(stderr, "dequeued msg, length %u (expected %zu), data %s\n", msgb_length(llc_msg), len, msgb_hexdump(llc_msg)); @@ -96,126 +109,128 @@ static void dequeue_and_check(gprs_llc_queue *queue, const char *exp_message, static void test_llc_queue() { - gprs_llc_queue queue; + gprs_llc_queue *queue = prepare_queue(); struct timespec expire_time = {0}; printf("=== start %s ===\n", __func__); - llc_queue_init(&queue); - OSMO_ASSERT(llc_queue_size(&queue) == 0); - OSMO_ASSERT(llc_queue_octets(&queue) == 0); + OSMO_ASSERT(llc_queue_size(queue) == 0); + OSMO_ASSERT(llc_queue_octets(queue) == 0); - enqueue_data(&queue, "LLC message", &expire_time); - OSMO_ASSERT(llc_queue_size(&queue) == 1); - OSMO_ASSERT(llc_queue_octets(&queue) == 11); + enqueue_data(queue, "LLC message", &expire_time); + OSMO_ASSERT(llc_queue_size(queue) == 1); + OSMO_ASSERT(llc_queue_octets(queue) == 11); - enqueue_data(&queue, "other LLC message", &expire_time); - OSMO_ASSERT(llc_queue_size(&queue) == 2); - OSMO_ASSERT(llc_queue_octets(&queue) == 28); + enqueue_data(queue, "other LLC message", &expire_time); + OSMO_ASSERT(llc_queue_size(queue) == 2); + OSMO_ASSERT(llc_queue_octets(queue) == 28); - dequeue_and_check(&queue, "LLC message"); - OSMO_ASSERT(llc_queue_size(&queue) == 1); - OSMO_ASSERT(llc_queue_octets(&queue) == 17); + dequeue_and_check(queue, "LLC message"); + OSMO_ASSERT(llc_queue_size(queue) == 1); + OSMO_ASSERT(llc_queue_octets(queue) == 17); - dequeue_and_check(&queue, "other LLC message"); - OSMO_ASSERT(llc_queue_size(&queue) == 0); - OSMO_ASSERT(llc_queue_octets(&queue) == 0); + dequeue_and_check(queue, "other LLC message"); + OSMO_ASSERT(llc_queue_size(queue) == 0); + OSMO_ASSERT(llc_queue_octets(queue) == 0); - enqueue_data(&queue, "LLC", &expire_time); - OSMO_ASSERT(llc_queue_size(&queue) == 1); - OSMO_ASSERT(llc_queue_octets(&queue) == 3); + enqueue_data(queue, "LLC", &expire_time); + OSMO_ASSERT(llc_queue_size(queue) == 1); + OSMO_ASSERT(llc_queue_octets(queue) == 3); - llc_queue_clear(&queue, NULL); - OSMO_ASSERT(llc_queue_size(&queue) == 0); - OSMO_ASSERT(llc_queue_octets(&queue) == 0); + llc_queue_clear(queue, NULL); + OSMO_ASSERT(llc_queue_size(queue) == 0); + OSMO_ASSERT(llc_queue_octets(queue) == 0); printf("=== end %s ===\n", __func__); + TALLOC_FREE(the_pcu); } static void test_llc_meta() { - gprs_llc_queue queue; + gprs_llc_queue *queue = prepare_queue(); MetaInfo info1 = {0}; MetaInfo info2 = {0}; printf("=== start %s ===\n", __func__); - llc_queue_init(&queue); - OSMO_ASSERT(llc_queue_size(&queue) == 0); - OSMO_ASSERT(llc_queue_octets(&queue) == 0); + OSMO_ASSERT(llc_queue_size(queue) == 0); + OSMO_ASSERT(llc_queue_octets(queue) == 0); info1.recv_time.tv_sec = 123456777; info1.recv_time.tv_nsec = 123456000; info1.expire_time.tv_sec = 123456789; info1.expire_time.tv_nsec = 987654000; *clk_mono_override_time = info1.recv_time; - enqueue_data(&queue, "LLC message 1", &info1.expire_time); + enqueue_data(queue, "LLC message 1", &info1.expire_time); info2.recv_time.tv_sec = 123458000; info2.recv_time.tv_nsec = 547352000; info2.expire_time.tv_sec = 123458006; info2.expire_time.tv_nsec = 867252000; *clk_mono_override_time = info2.recv_time; - enqueue_data(&queue, "LLC message 2", &info2.expire_time); + enqueue_data(queue, "LLC message 2", &info2.expire_time); - dequeue_and_check(&queue, "LLC message 1", &info1); - dequeue_and_check(&queue, "LLC message 2", &info2); + clk_mono_override_time->tv_sec = info1.expire_time.tv_sec - 1; + clk_mono_override_time->tv_nsec = info1.expire_time.tv_nsec; - llc_queue_clear(&queue, NULL); - OSMO_ASSERT(llc_queue_size(&queue) == 0); - OSMO_ASSERT(llc_queue_octets(&queue) == 0); + dequeue_and_check(queue, "LLC message 1", &info1); + dequeue_and_check(queue, "LLC message 2", &info2); + + llc_queue_clear(queue, NULL); + OSMO_ASSERT(llc_queue_size(queue) == 0); + OSMO_ASSERT(llc_queue_octets(queue) == 0); printf("=== end %s ===\n", __func__); + TALLOC_FREE(the_pcu); } static void test_llc_merge() { - gprs_llc_queue queue1; - gprs_llc_queue queue2; + gprs_llc_queue *queue1 = prepare_queue(); + struct GprsMs *ms = bts_alloc_ms(queue1->ms->bts, 0, 0); + gprs_llc_queue *queue2 = ms_llc_queue(ms); struct timespec expire_time = {0}; printf("=== start %s ===\n", __func__); - llc_queue_init(&queue1); - llc_queue_init(&queue2); + clk_mono_override_time->tv_sec += 1; + enqueue_data(queue1, "*A*", &expire_time); clk_mono_override_time->tv_sec += 1; - enqueue_data(&queue1, "*A*", &expire_time); + enqueue_data(queue1, "*B*", &expire_time); clk_mono_override_time->tv_sec += 1; - enqueue_data(&queue1, "*B*", &expire_time); + enqueue_data(queue2, "*C*", &expire_time); clk_mono_override_time->tv_sec += 1; - enqueue_data(&queue2, "*C*", &expire_time); + enqueue_data(queue1, "*D*", &expire_time); clk_mono_override_time->tv_sec += 1; - enqueue_data(&queue1, "*D*", &expire_time); + enqueue_data(queue2, "*E*", &expire_time); - clk_mono_override_time->tv_sec += 1; - enqueue_data(&queue2, "*E*", &expire_time); + OSMO_ASSERT(llc_queue_size(queue1) == 3); + OSMO_ASSERT(llc_queue_octets(queue1) == 9); + OSMO_ASSERT(llc_queue_size(queue2) == 2); + OSMO_ASSERT(llc_queue_octets(queue2) == 6); - OSMO_ASSERT(llc_queue_size(&queue1) == 3); - OSMO_ASSERT(llc_queue_octets(&queue1) == 9); - OSMO_ASSERT(llc_queue_size(&queue2) == 2); - OSMO_ASSERT(llc_queue_octets(&queue2) == 6); + llc_queue_move_and_merge(queue2, queue1); - llc_queue_move_and_merge(&queue2, &queue1); + OSMO_ASSERT(llc_queue_size(queue1) == 0); + OSMO_ASSERT(llc_queue_octets(queue1) == 0); + OSMO_ASSERT(llc_queue_size(queue2) == 5); + OSMO_ASSERT(llc_queue_octets(queue2) == 15); - OSMO_ASSERT(llc_queue_size(&queue1) == 0); - OSMO_ASSERT(llc_queue_octets(&queue1) == 0); - OSMO_ASSERT(llc_queue_size(&queue2) == 5); - OSMO_ASSERT(llc_queue_octets(&queue2) == 15); + dequeue_and_check(queue2, "*A*"); + dequeue_and_check(queue2, "*B*"); + dequeue_and_check(queue2, "*C*"); + dequeue_and_check(queue2, "*D*"); + dequeue_and_check(queue2, "*E*"); - dequeue_and_check(&queue2, "*A*"); - dequeue_and_check(&queue2, "*B*"); - dequeue_and_check(&queue2, "*C*"); - dequeue_and_check(&queue2, "*D*"); - dequeue_and_check(&queue2, "*E*"); - - OSMO_ASSERT(llc_queue_size(&queue2) == 0); - OSMO_ASSERT(llc_queue_octets(&queue2) == 0); + OSMO_ASSERT(llc_queue_size(queue2) == 0); + OSMO_ASSERT(llc_queue_octets(queue2) == 0); printf("=== end %s ===\n", __func__); + TALLOC_FREE(the_pcu); } int main(int argc, char **argv)