diff options
-rw-r--r-- | include/osmocom/gprs/gprs_bssgp.h | 45 | ||||
-rw-r--r-- | src/gb/gprs_bssgp.c | 254 | ||||
-rw-r--r-- | src/gb/gprs_bssgp_vty.c | 13 | ||||
-rw-r--r-- | src/gb/libosmogb.map | 3 | ||||
-rw-r--r-- | tests/Makefile.am | 6 | ||||
-rw-r--r-- | tests/gb/bssgp_fc_test.c | 167 | ||||
-rw-r--r-- | tests/gb/bssgp_fc_tests.err | 51 | ||||
-rw-r--r-- | tests/gb/bssgp_fc_tests.ok | 150 | ||||
-rwxr-xr-x | tests/gb/bssgp_fc_tests.sh | 15 | ||||
-rw-r--r-- | tests/testsuite.at | 7 |
10 files changed, 705 insertions, 6 deletions
diff --git a/include/osmocom/gprs/gprs_bssgp.h b/include/osmocom/gprs/gprs_bssgp.h index 8ca42bf9..eb4e7219 100644 --- a/include/osmocom/gprs/gprs_bssgp.h +++ b/include/osmocom/gprs/gprs_bssgp.h @@ -2,6 +2,8 @@ #define _GPRS_BSSGP_H #include <stdint.h> +#include <osmocom/core/timer.h> +#include <osmocom/core/linuxlist.h> #include <osmocom/gsm/gsm48.h> #include <osmocom/gsm/prim.h> @@ -54,6 +56,25 @@ struct osmo_bssgp_prim { /* gprs_bssgp.c */ +/*! \brief BSSGP flow control (SGSN side) According to Section 8.2 */ +struct bssgp_flow_control { + uint32_t bucket_size_max; /*!< maximum size of the bucket (octets) */ + uint32_t bucket_leak_rate; /*!< leak rate of the bucket (octets/sec) */ + + uint32_t bucket_counter; /*!< number of tokens in the bucket */ + struct timeval time_last_pdu; /*!< timestamp of last PDU sent */ + + /* the built-in queue */ + uint32_t max_queue_depth; /*!< how many packets to queue (mgs) */ + uint32_t queue_depth; /*!< current length of queue (msgs) */ + struct llist_head queue; /*!< linked list of msgb's */ + struct osmo_timer_list timer; /*!< timer-based dequeueing */ + + /*! callback to be called at output of flow control */ + int (*out_cb)(struct bssgp_flow_control *fc, struct msgb *msg, + uint32_t llc_pdu_len, void *priv); +}; + #define BVC_S_BLOCKED 0x0001 /* The per-BTS context that we keep on the SGSN side of the BSSGP link */ @@ -72,6 +93,12 @@ struct bssgp_bvc_ctx { struct rate_ctr_group *ctrg; + struct bssgp_flow_control *fc; + /*! default maximum size of per-MS bucket in octets */ + uint32_t bmax_default_ms; + /*! default bucket leak rate of per-MS bucket in octests/s */ + uint32_t r_default_ms; + /* we might want to add this as a shortcut later, avoiding the NSVC * lookup for every packet, similar to a routing cache */ //struct gprs_nsvc *nsvc; @@ -109,6 +136,7 @@ struct bssgp_lv { struct bssgp_dl_ud_par { uint32_t *tlli; char *imsi; + struct bssgp_flow_control *fc; uint16_t drx_parms; /* FIXME: priority */ struct bssgp_lv ms_ra_cap; @@ -157,6 +185,23 @@ struct bssgp_paging_info { int bssgp_tx_paging(uint16_t nsei, uint16_t ns_bvci, struct bssgp_paging_info *pinfo); +void bssgp_fc_init(struct bssgp_flow_control *fc, + uint32_t bucket_size_max, uint32_t bucket_leak_rate, + uint32_t max_queue_depth, + int (*out_cb)(struct bssgp_flow_control *fc, struct msgb *msg, + uint32_t llc_pdu_len, void *priv)); + +/* input function of the flow control implementation, called first + * for the MM flow control, and then as the MM flow control output + * callback in order to perform BVC flow control */ +int bssgp_fc_in(struct bssgp_flow_control *fc, struct msgb *msg, + uint32_t llc_pdu_len, void *priv); + +/* Initialize the Flow Control parameters for a new MS according to + * default values for the BVC specified by BVCI and NSEI */ +int bssgp_fc_ms_init(struct bssgp_flow_control *fc_ms, uint16_t bvci, + uint16_t nsei, uint32_t max_queue_depth); + /* gprs_bssgp_vty.c */ int bssgp_vty_init(void); void bssgp_set_log_ss(int ss); diff --git a/src/gb/gprs_bssgp.c b/src/gb/gprs_bssgp.c index 142e69b8..e41c7efb 100644 --- a/src/gb/gprs_bssgp.c +++ b/src/gb/gprs_bssgp.c @@ -57,6 +57,9 @@ static const struct rate_ctr_group_desc bssgp_ctrg_desc = { LLIST_HEAD(bssgp_bvc_ctxts); +static int _bssgp_tx_dl_ud(struct bssgp_flow_control *fc, struct msgb *msg, + uint32_t llc_pdu_len, void *priv); + /* Find a BTS Context based on parsed RA ID and Cell ID */ struct bssgp_bvc_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid) { @@ -93,6 +96,9 @@ struct bssgp_bvc_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei) ctx->nsei = nsei; /* FIXME: BVCI is not unique, only BVCI+NSEI ?!? */ ctx->ctrg = rate_ctr_group_alloc(ctx, &bssgp_ctrg_desc, bvci); + ctx->fc = talloc_zero(ctx, struct bssgp_flow_control); + /* cofigure for 2Mbit, 30 packets in queue */ + bssgp_fc_init(ctx->fc, 100000, 2*1024*1024/8, 30, &_bssgp_tx_dl_ud); llist_add(&ctx->list, &bssgp_bvc_ctxts); @@ -510,6 +516,229 @@ static int bssgp_rx_llc_disc(struct msgb *msg, struct tlv_parsed *tp, return bssgp_prim_cb(&nmp.oph, NULL); } +/* One element (msgb) in a BSSGP Flow Control queue */ +struct bssgp_fc_queue_element { + /* linked list of queue elements */ + struct llist_head list; + /* The message that we have enqueued */ + struct msgb *msg; + /* Length of the LLC PDU part of the contained message */ + uint32_t llc_pdu_len; + /* private pointer passed to the flow control out_cb function */ + void *priv; +}; + +static int fc_queue_timer_cfg(struct bssgp_flow_control *fc); +static int bssgp_fc_needs_queueing(struct bssgp_flow_control *fc, uint32_t pdu_len); + +static void fc_timer_cb(void *data) +{ + struct bssgp_flow_control *fc = data; + struct bssgp_fc_queue_element *fcqe; + struct timeval time_now; + + /* if the queue is empty, we return without sending something + * and without re-starting the timer */ + if (llist_empty(&fc->queue)) + return; + + /* get the first entry from the queue */ + fcqe = llist_entry(fc->queue.next, struct bssgp_fc_queue_element, + list); + + if (bssgp_fc_needs_queueing(fc, fcqe->llc_pdu_len)) { + LOGP(DBSSGP, LOGL_NOTICE, "BSSGP-FC: fc_timer_cb() but still " + "not able to send PDU of %u bytes\n", fcqe->llc_pdu_len); + /* make sure we re-start the timer */ + fc_queue_timer_cfg(fc); + return; + } + + /* remove from the queue */ + llist_del(&fcqe->list); + + fc->queue_depth--; + + /* record the time we transmitted this PDU */ + gettimeofday(&time_now, NULL); + fc->time_last_pdu = time_now; + + /* call the output callback for this FC instance */ + fc->out_cb(fcqe->priv, fcqe->msg, fcqe->llc_pdu_len, NULL); + + /* we expect that out_cb will in the end free the msgb once + * it is no longer needed */ + + /* but we have to free the queue element ourselves */ + talloc_free(fcqe); + + /* re-configure the timer for the next PDU */ + fc_queue_timer_cfg(fc); +} + +/* configure/schedule the flow control timer to expire once the bucket + * will have leaked a sufficient number of bytes to transmit the next + * PDU in the queue */ +static int fc_queue_timer_cfg(struct bssgp_flow_control *fc) +{ + struct bssgp_fc_queue_element *fcqe; + uint32_t msecs; + + if (llist_empty(&fc->queue)) + return 0; + + fcqe = llist_entry(&fc->queue.next, struct bssgp_fc_queue_element, + list); + + /* Calculate the point in time at which we will have leaked + * a sufficient number of bytes from the bucket to transmit + * the first PDU in the queue */ + msecs = (fcqe->llc_pdu_len * 1000) / fc->bucket_leak_rate; + /* FIXME: add that time to fc->time_last_pdu and subtract it from + * current time */ + + fc->timer.data = fc; + fc->timer.cb = &fc_timer_cb; + osmo_timer_schedule(&fc->timer, msecs / 1000, (msecs % 1000) * 1000); + + return 0; +} + +/* Enqueue a PDU in the flow control queue for delayed transmission */ +static int fc_enqueue(struct bssgp_flow_control *fc, struct msgb *msg, + uint32_t llc_pdu_len, void *priv) +{ + struct bssgp_fc_queue_element *fcqe; + + if (fc->queue_depth >= fc->max_queue_depth) + return -ENOSPC; + + fcqe = talloc_zero(fc, struct bssgp_fc_queue_element); + if (!fcqe) + return -ENOMEM; + fcqe->msg = msg; + fcqe->llc_pdu_len = llc_pdu_len; + fcqe->priv = priv; + + llist_add_tail(&fcqe->list, &fc->queue); + + fc->queue_depth++; + + /* re-configure the timer for dequeueing the pdu */ + fc_queue_timer_cfg(fc); + + return 0; +} + +/* According to Section 8.2 */ +static int bssgp_fc_needs_queueing(struct bssgp_flow_control *fc, uint32_t pdu_len) +{ + struct timeval time_now, time_diff; + int64_t bucket_predicted; + uint32_t csecs_elapsed, leaked; + + /* B' = B + L(p) - (Tc - Tp)*R */ + + /* compute number of centi-seconds that have elapsed since transmitting + * the last PDU (Tc - Tp) */ + gettimeofday(&time_now, NULL); + timersub(&time_now, &fc->time_last_pdu, &time_diff); + csecs_elapsed = time_diff.tv_sec*100 + time_diff.tv_usec/10000; + + /* compute number of bytes that have leaked in the elapsed number + * of centi-seconds */ + leaked = csecs_elapsed * (fc->bucket_leak_rate / 100); + /* add the current PDU length to the last bucket level */ + bucket_predicted = fc->bucket_counter + pdu_len; + /* ... and subtract the number of leaked bytes */ + bucket_predicted -= leaked; + + if (bucket_predicted < pdu_len) { + /* this is just to make sure the bucket doesn't underflow */ + bucket_predicted = pdu_len; + goto pass; + } + + if (bucket_predicted <= fc->bucket_size_max) { + /* the bucket is not full yet, we can pass the packet */ + fc->bucket_counter = bucket_predicted; + goto pass; + } + + /* bucket is full, PDU needs to be delayed */ + return 1; + +pass: + /* if we reach here, the PDU can pass */ + return 0; +} + +/* output callback for BVC flow control */ +static int _bssgp_tx_dl_ud(struct bssgp_flow_control *fc, struct msgb *msg, + uint32_t llc_pdu_len, void *priv) +{ + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/* input function of the flow control implementation, called first + * for the MM flow control, and then as the MM flow control output + * callback in order to perform BVC flow control */ +int bssgp_fc_in(struct bssgp_flow_control *fc, struct msgb *msg, + uint32_t llc_pdu_len, void *priv) +{ + struct timeval time_now; + + if (llc_pdu_len > fc->bucket_size_max) { + LOGP(DBSSGP, LOGL_NOTICE, "Single PDU (size=%u) is larger " + "than maximum bucket size (%u)!\n", llc_pdu_len, + fc->bucket_size_max); + return -EIO; + } + + if (bssgp_fc_needs_queueing(fc, llc_pdu_len)) { + return fc_enqueue(fc, msg, llc_pdu_len, priv); + } else { + /* record the time we transmitted this PDU */ + gettimeofday(&time_now, NULL); + fc->time_last_pdu = time_now; + return fc->out_cb(priv, msg, llc_pdu_len, NULL); + } +} + + +/* Initialize the Flow Control structure */ +void bssgp_fc_init(struct bssgp_flow_control *fc, + uint32_t bucket_size_max, uint32_t bucket_leak_rate, + uint32_t max_queue_depth, + int (*out_cb)(struct bssgp_flow_control *fc, struct msgb *msg, + uint32_t llc_pdu_len, void *priv)) +{ + fc->out_cb = out_cb; + fc->bucket_size_max = bucket_size_max; + fc->bucket_leak_rate = bucket_leak_rate; + fc->max_queue_depth = max_queue_depth; + INIT_LLIST_HEAD(&fc->queue); + gettimeofday(&fc->time_last_pdu, NULL); +} + +/* Initialize the Flow Control parameters for a new MS according to + * default values for the BVC specified by BVCI and NSEI */ +int bssgp_fc_ms_init(struct bssgp_flow_control *fc_ms, uint16_t bvci, + uint16_t nsei, uint32_t max_queue_depth) +{ + struct bssgp_bvc_ctx *ctx; + + ctx = btsctx_by_bvci_nsei(bvci, nsei); + if (!ctx) + return -ENODEV; + + /* output call-back of per-MS FC is per-CTX FC */ + bssgp_fc_init(fc_ms, ctx->bmax_default_ms, ctx->r_default_ms, + max_queue_depth, bssgp_fc_in); + + return 0; +} + static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *bctx) { @@ -527,7 +756,18 @@ static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); } - /* FIXME: actually implement flow control */ + /* 11.3.5 Bucket Size in 100 octets unit */ + bctx->fc->bucket_size_max = 100 * + ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVC_BUCKET_SIZE)); + /* 11.3.4 Bucket Leak Rate in 100 bits/sec unit */ + bctx->fc->bucket_leak_rate = 100 * + ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BUCKET_LEAK_RATE)) / 8; + /* 11.3.2 in octets */ + bctx->bmax_default_ms = + ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BMAX_DEFAULT_MS)); + /* 11.3.32 Bucket Leak rate in 100bits/sec unit */ + bctx->r_default_ms = 100 * + ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_R_DEFAULT_MS)) / 8; /* Send FLOW_CONTROL_BVC_ACK */ return bssgp_tx_fc_bvc_ack(msgb_nsei(msg), *TLVP_VAL(tp, BSSGP_IE_TAG), @@ -777,8 +1017,9 @@ int bssgp_tx_dl_ud(struct msgb *msg, uint16_t pdu_lifetime, bctx = btsctx_by_bvci_nsei(bvci, nsei); if (!bctx) { - /* FIXME: don't simply create missing context, but reject message */ - bctx = btsctx_alloc(bvci, nsei); + LOGP(DBSSGP, LOGL_ERROR, "Cannot send DL-UD to unknown BVCI %u\n", + bvci); + return -ENODEV; } if (msg->len > TVLV_MAX_ONEBYTE) @@ -841,7 +1082,12 @@ int bssgp_tx_dl_ud(struct msgb *msg, uint16_t pdu_lifetime, /* Identifiers down: BVCI, NSEI (in msgb->cb) */ - return gprs_ns_sendmsg(bssgp_nsi, msg); + /* check if we have to go through per-ms flow control or can go + * directly to the per-BSS flow control */ + if (dup->fc) + return bssgp_fc_in(dup->fc, msg, msg_len, bctx->fc); + else + return bssgp_fc_in(bctx->fc, msg, msg_len, NULL); } /* Send a single GMM-PAGING.req to a given NSEI/NS-BVCI */ diff --git a/src/gb/gprs_bssgp_vty.c b/src/gb/gprs_bssgp_vty.c index aa1f1065..d8e1d32f 100644 --- a/src/gb/gprs_bssgp_vty.c +++ b/src/gb/gprs_bssgp_vty.c @@ -88,8 +88,19 @@ static void dump_bvc(struct vty *vty, struct bssgp_bvc_ctx *bvc, int stats) bvc->ra_id.mnc, bvc->ra_id.lac, bvc->ra_id.rac, bvc->cell_id, bvc->state & BVC_S_BLOCKED ? "BLOCKED" : "UNBLOCKED", VTY_NEWLINE); - if (stats) + + if (stats) { + struct bssgp_flow_control *fc = bvc->fc; + vty_out_rate_ctr_group(vty, " ", bvc->ctrg); + + if (fc) + vty_out(vty, "FC-BVC(bucket_max: %uoct, leak_rate: " + "%uoct/s, cur_tokens: %uoct, max_q_d: %u, " + "cur_q_d: %u)\n", fc->bucket_size_max, + fc->bucket_leak_rate, fc->bucket_counter, + fc->max_queue_depth, fc->queue_depth); + } } static void dump_bssgp(struct vty *vty, int stats) diff --git a/src/gb/libosmogb.map b/src/gb/libosmogb.map index a41a91a1..d0f76f86 100644 --- a/src/gb/libosmogb.map +++ b/src/gb/libosmogb.map @@ -2,6 +2,9 @@ LIBOSMOGB_1.0 { global: bssgp_cause_str; bssgp_create_cell_id; +bssgp_fc_in; +bssgp_fc_init; +bssgp_fc_ms_init; bssgp_msgb_alloc; bssgp_msgb_tlli_put; bssgp_parse_cell_id; diff --git a/tests/Makefile.am b/tests/Makefile.am index ce5fefbf..b489b3b2 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -3,7 +3,8 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include check_PROGRAMS = timer/timer_test sms/sms_test ussd/ussd_test \ smscb/smscb_test bits/bitrev_test a5/a5_test \ conv/conv_test auth/milenage_test lapd/lapd_test \ - gsm0808/gsm0808_test gsm0408/gsm0408_test + gsm0808/gsm0808_test gsm0408/gsm0408_test \ + gb/bssgp_fc_test if ENABLE_MSGFILE check_PROGRAMS += msgfile/msgfile_test endif @@ -44,6 +45,9 @@ timer_timer_test_LDADD = $(top_builddir)/src/libosmocore.la ussd_ussd_test_SOURCES = ussd/ussd_test.c ussd_ussd_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la +gb_bssgp_fc_test_SOURCES = gb/bssgp_fc_test.c +gb_bssgp_fc_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gb/libosmogb.la + # The `:;' works around a Bash 3.2 bug when the output is not writeable. $(srcdir)/package.m4: $(top_srcdir)/configure.ac :;{ \ diff --git a/tests/gb/bssgp_fc_test.c b/tests/gb/bssgp_fc_test.c new file mode 100644 index 00000000..c5e864d4 --- /dev/null +++ b/tests/gb/bssgp_fc_test.c @@ -0,0 +1,167 @@ +/* test routines for BSSGP flow control implementation in libosmogb + * (C) 2012 by Harald Welte <laforge@gnumonks.org> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <getopt.h> + +#include <osmocom/core/utils.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/talloc.h> +#include <osmocom/gprs/gprs_bssgp.h> + +static unsigned long in_ctr = 1; +static struct timeval tv_start; + +int get_centisec_diff(void) +{ + struct timeval tv; + struct timeval now; + gettimeofday(&now, NULL); + + timersub(&now, &tv_start, &tv); + + return tv.tv_sec * 100 + tv.tv_usec/10000; +} + +/* round to deciseconds to make sure test output is always consistent */ +int round_decisec(int csec_in) +{ + int tmp = csec_in / 10; + + return tmp * 10; +} + +static int fc_out_cb(struct bssgp_flow_control *fc, struct msgb *msg, + uint32_t llc_pdu_len, void *priv) +{ + unsigned int csecs = get_centisec_diff(); + csecs = round_decisec(csecs); + + printf("%u: FC OUT Nr %lu\n", csecs, (unsigned long) msg); +} + +static int fc_in(struct bssgp_flow_control *fc, unsigned int pdu_len) +{ + unsigned int csecs = get_centisec_diff(); + csecs = round_decisec(csecs); + + printf("%u: FC IN Nr %lu\n", csecs, in_ctr); + bssgp_fc_in(fc, (struct msgb *) in_ctr, pdu_len, NULL); + in_ctr++; +} + + +static void test_fc(uint32_t bucket_size_max, uint32_t bucket_leak_rate, + uint32_t max_queue_depth, uint32_t pdu_len, + uint32_t pdu_count) +{ + struct bssgp_flow_control *fc = talloc_zero(NULL, struct bssgp_flow_control); + int i; + + bssgp_fc_init(fc, bucket_size_max, bucket_leak_rate, max_queue_depth, + fc_out_cb); + + gettimeofday(&tv_start, NULL); + + for (i = 0; i < pdu_count; i++) { + fc_in(fc, pdu_len); + osmo_timers_check(); + osmo_timers_prepare(); + osmo_timers_update(); + } + + while (1) { + usleep(100000); + osmo_timers_check(); + osmo_timers_prepare(); + osmo_timers_update(); + + if (llist_empty(&fc->queue)) + break; + } +} + +static void help(void) +{ + printf(" -h --help This help message\n"); + printf(" -s --bucket-size-max N Maximum size of bucket in octets\n"); + printf(" -r --bucket-leak-rate N Bucket leak rate in octets/sec\n"); + printf(" -d --max-queue-depth N Maximum length of pending PDU queue (msgs)\n"); + printf(" -l --pdu-length N Length of each PDU in octets\n"); +} + +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + return -1; +} + +static struct log_info info = {}; + +int main(int argc, char **argv) +{ + uint32_t bucket_size_max = 100; /* octets */ + uint32_t bucket_leak_rate = 100; /* octets / second */ + uint32_t max_queue_depth = 5; /* messages */ + uint32_t pdu_length = 10; /* octets */ + uint32_t pdu_count = 20; /* messages */ + int c; + + static const struct option long_options[] = { + { "bucket-size-max", 1, 0, 's' }, + { "bucket-leak-rate", 1, 0, 'r' }, + { "max-queue-depth", 1, 0, 'd' }, + { "pdu-length", 1, 0, 'l' }, + { "pdu-count", 1, 0, 'c' }, + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } + }; + + osmo_init_logging(&info); + + while ((c = getopt_long(argc, argv, "s:r:d:l:c:", + long_options, NULL)) != -1) { + switch (c) { + case 's': + bucket_size_max = atoi(optarg); + break; + case 'r': + bucket_leak_rate = atoi(optarg); + break; + case 'd': + max_queue_depth = atoi(optarg); + break; + case 'l': + pdu_length = atoi(optarg); + break; + case 'c': + pdu_count = atoi(optarg); + break; + case 'h': + help(); + exit(EXIT_SUCCESS); + break; + default: + exit(EXIT_FAILURE); + } + } + + /* bucket leak rate less than 100 not supported! */ + if (bucket_leak_rate < 100) { + fprintf(stderr, "Bucket leak rate < 100 not supported!\n"); + exit(EXIT_FAILURE); + } + + printf("===== BSSGP flow-control test START\n"); + printf("size-max=%u oct, leak-rate=%u oct/s, " + "queue-len=%u msgs, pdu_len=%u oct, pdu_cnt=%u\n\n", bucket_size_max, + bucket_leak_rate, max_queue_depth, pdu_length, pdu_count); + test_fc(bucket_size_max, bucket_leak_rate, max_queue_depth, + pdu_length, pdu_count); + printf("===== BSSGP flow-control test END\n\n"); + + exit(EXIT_SUCCESS); +} diff --git a/tests/gb/bssgp_fc_tests.err b/tests/gb/bssgp_fc_tests.err new file mode 100644 index 00000000..ae5d6f66 --- /dev/null +++ b/tests/gb/bssgp_fc_tests.err @@ -0,0 +1,51 @@ +<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:699 Single PDU (size=1000) is larger than maximum bucket size (100)! +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m<0000> gprs_bssgp.c:556 BSSGP-FC: fc_timer_cb() but still not able to send PDU of 10 bytes +[0;m
\ No newline at end of file diff --git a/tests/gb/bssgp_fc_tests.ok b/tests/gb/bssgp_fc_tests.ok new file mode 100644 index 00000000..fda96f30 --- /dev/null +++ b/tests/gb/bssgp_fc_tests.ok @@ -0,0 +1,150 @@ +===== BSSGP flow-control test START +size-max=100 oct, leak-rate=100 oct/s, queue-len=5 msgs, pdu_len=10 oct, pdu_cnt=20 + +0: FC IN Nr 1 +0: FC OUT Nr 1 +0: FC IN Nr 2 +0: FC OUT Nr 2 +0: FC IN Nr 3 +0: FC OUT Nr 3 +0: FC IN Nr 4 +0: FC OUT Nr 4 +0: FC IN Nr 5 +0: FC OUT Nr 5 +0: FC IN Nr 6 +0: FC OUT Nr 6 +0: FC IN Nr 7 +0: FC OUT Nr 7 +0: FC IN Nr 8 +0: FC OUT Nr 8 +0: FC IN Nr 9 +0: FC OUT Nr 9 +0: FC IN Nr 10 +0: FC OUT Nr 10 +0: FC IN Nr 11 +0: FC IN Nr 12 +0: FC IN Nr 13 +0: FC IN Nr 14 +0: FC IN Nr 15 +0: FC IN Nr 16 +0: FC IN Nr 17 +0: FC IN Nr 18 +0: FC IN Nr 19 +0: FC IN Nr 20 +10: FC OUT Nr 11 +20: FC OUT Nr 12 +30: FC OUT Nr 13 +40: FC OUT Nr 14 +50: FC OUT Nr 15 +===== BSSGP flow-control test END + +===== BSSGP flow-control test START +size-max=100 oct, leak-rate=100 oct/s, queue-len=100 msgs, pdu_len=10 oct, pdu_cnt=20 + +0: FC IN Nr 1 +0: FC OUT Nr 1 +0: FC IN Nr 2 +0: FC OUT Nr 2 +0: FC IN Nr 3 +0: FC OUT Nr 3 +0: FC IN Nr 4 +0: FC OUT Nr 4 +0: FC IN Nr 5 +0: FC OUT Nr 5 +0: FC IN Nr 6 +0: FC OUT Nr 6 +0: FC IN Nr 7 +0: FC OUT Nr 7 +0: FC IN Nr 8 +0: FC OUT Nr 8 +0: FC IN Nr 9 +0: FC OUT Nr 9 +0: FC IN Nr 10 +0: FC OUT Nr 10 +0: FC IN Nr 11 +0: FC IN Nr 12 +0: FC IN Nr 13 +0: FC IN Nr 14 +0: FC IN Nr 15 +0: FC IN Nr 16 +0: FC IN Nr 17 +0: FC IN Nr 18 +0: FC IN Nr 19 +0: FC IN Nr 20 +10: FC OUT Nr 11 +20: FC OUT Nr 12 +30: FC OUT Nr 13 +40: FC OUT Nr 14 +50: FC OUT Nr 15 +60: FC OUT Nr 16 +70: FC OUT Nr 17 +80: FC OUT Nr 18 +90: FC OUT Nr 19 +100: FC OUT Nr 20 +===== BSSGP flow-control test END + +===== BSSGP flow-control test START +size-max=100 oct, leak-rate=100 oct/s, queue-len=5 msgs, pdu_len=1000 oct, pdu_cnt=20 + +0: FC IN Nr 1 +0: FC IN Nr 2 +0: FC IN Nr 3 +0: FC IN Nr 4 +0: FC IN Nr 5 +0: FC IN Nr 6 +0: FC IN Nr 7 +0: FC IN Nr 8 +0: FC IN Nr 9 +0: FC IN Nr 10 +0: FC IN Nr 11 +0: FC IN Nr 12 +0: FC IN Nr 13 +0: FC IN Nr 14 +0: FC IN Nr 15 +0: FC IN Nr 16 +0: FC IN Nr 17 +0: FC IN Nr 18 +0: FC IN Nr 19 +0: FC IN Nr 20 +===== BSSGP flow-control test END + +===== BSSGP flow-control test START +size-max=100 oct, leak-rate=100 oct/s, queue-len=5 msgs, pdu_len=10 oct, pdu_cnt=20 + +0: FC IN Nr 1 +0: FC OUT Nr 1 +0: FC IN Nr 2 +0: FC OUT Nr 2 +0: FC IN Nr 3 +0: FC OUT Nr 3 +0: FC IN Nr 4 +0: FC OUT Nr 4 +0: FC IN Nr 5 +0: FC OUT Nr 5 +0: FC IN Nr 6 +0: FC OUT Nr 6 +0: FC IN Nr 7 +0: FC OUT Nr 7 +0: FC IN Nr 8 +0: FC OUT Nr 8 +0: FC IN Nr 9 +0: FC OUT Nr 9 +0: FC IN Nr 10 +0: FC OUT Nr 10 +0: FC IN Nr 11 +0: FC IN Nr 12 +0: FC IN Nr 13 +0: FC IN Nr 14 +0: FC IN Nr 15 +0: FC IN Nr 16 +0: FC IN Nr 17 +0: FC IN Nr 18 +0: FC IN Nr 19 +0: FC IN Nr 20 +10: FC OUT Nr 11 +20: FC OUT Nr 12 +30: FC OUT Nr 13 +40: FC OUT Nr 14 +50: FC OUT Nr 15 +===== BSSGP flow-control test END + diff --git a/tests/gb/bssgp_fc_tests.sh b/tests/gb/bssgp_fc_tests.sh new file mode 100755 index 00000000..38659bb9 --- /dev/null +++ b/tests/gb/bssgp_fc_tests.sh @@ -0,0 +1,15 @@ +#!/bin/sh +T=$1/bssgp_fc_test + +# default test (1 second, insufficient queue depth) +$T + +# default test (1 second, sufficient queue depth) +$T -d 100 + +# test with PDU too large for bucket max +$T -l 1000 + +# test with 100 byte PDUs (10 second) +$T -s 100 + diff --git a/tests/testsuite.at b/tests/testsuite.at index 21542695..dd22c323 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -9,6 +9,13 @@ cat $abs_srcdir/a5/a5_test.ok > expout AT_CHECK([$abs_top_builddir/tests/a5/a5_test], [], [expout]) AT_CLEANUP +AT_SETUP([bssgp-fc]) +AT_KEYWORDS([bssgp-fc]) +cat $abs_srcdir/gb/bssgp_fc_tests.ok > expout +cat $abs_srcdir/gb/bssgp_fc_tests.err > experr +AT_CHECK([$abs_top_builddir/tests/gb/bssgp_fc_tests.sh $abs_top_builddir/tests/gb], [], [expout], [experr]) +AT_CLEANUP + AT_SETUP([bits]) AT_KEYWORDS([bits]) cat $abs_srcdir/bits/bitrev_test.ok > expout |