[PATCH 6/8] agch: Manage AGCH queue length

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/OpenBSC@lists.osmocom.org/.

Jacob Erlbeck jerlbeck at sysmocom.de
Fri Feb 21 23:36:07 UTC 2014


Currently, the AGCH queue length is not limited. This can lead to
large delays and network malfunction if there are many IMM.ASS.REJ
messages.

This patch adds two features:
- Don't accept msgs from the RSL layer when the queue is way too
  full (safety measure, mainly if bts_ccch_copy_msg() is not being
  called by the L1 layer, currently hard coded to 1000 messages)
- Selectively drop IMM.ASS.REJ from the queue output depending on the
  queue length

Ticket: #224
Sponsored-by: On-Waves ehf
---
 include/osmo-bts/gsm_data.h |    9 ++++
 src/common/bts.c            |  123 ++++++++++++++++++++++++++++++++++++++-----
 tests/agch/agch_test.c      |    4 ++
 tests/agch/agch_test.ok     |    2 +-
 4 files changed, 125 insertions(+), 13 deletions(-)

diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h
index b139903..c7a0fc6 100644
--- a/include/osmo-bts/gsm_data.h
+++ b/include/osmo-bts/gsm_data.h
@@ -7,6 +7,11 @@
 
 #include <osmo-bts/paging.h>
 
+#define GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DEFAULT 41
+#define GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DISABLE 999999
+#define GSM_BTS_AGCH_QUEUE_LOW_LEVEL_DEFAULT 41
+#define GSM_BTS_AGCH_QUEUE_HIGH_LEVEL_DEFAULT 91
+
 struct pcu_sock_state;
 
 struct gsm_network {
@@ -54,6 +59,10 @@ struct gsm_bts_role_bts {
 	int agch_queue_length;
 	int agch_max_queue_length;
 
+	int agch_queue_thresh_level;	/* Cleanup threshold in percent of max len */
+	int agch_queue_low_level;	/* Low water mark in percent of max len */
+	int agch_queue_high_level;	/* High water mark in percent of max len */
+
 	/* TODO: Use a rate counter group instead */
 	uint64_t agch_queue_dropped_msgs;
 	uint64_t agch_queue_merged_msgs;
diff --git a/src/common/bts.c b/src/common/bts.c
index 4ba2ec7..0b14020 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -89,6 +89,14 @@ int bts_init(struct gsm_bts *bts)
 	INIT_LLIST_HEAD(&btsb->agch_queue);
 	btsb->agch_queue_length = 0;
 
+	/* enable management with default levels,
+	 * raise threshold to GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DISABLE to
+	 * disable this feature.
+	 */
+	btsb->agch_queue_low_level = GSM_BTS_AGCH_QUEUE_LOW_LEVEL_DEFAULT;
+	btsb->agch_queue_high_level = GSM_BTS_AGCH_QUEUE_HIGH_LEVEL_DEFAULT;
+	btsb->agch_queue_thresh_level = GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DEFAULT;
+
 	/* configurable via VTY */
 	btsb->paging_state = paging_init(btsb, 200, 0);
 
@@ -297,6 +305,18 @@ void bts_update_agch_max_queue_length(struct gsm_bts *bts)
 int bts_agch_enqueue(struct gsm_bts *bts, struct msgb *msg)
 {
 	struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
+	int hard_limit = 1000;
+
+	if (btsb->agch_queue_length > hard_limit) {
+		LOGP(DSUM, LOGL_ERROR,
+		     "AGCH: too many messages in queue, "
+		     "refusing message type 0x%02x, length = %d/%d\n",
+		     ((struct gsm48_imm_ass *)msgb_l3(msg))->msg_type,
+		     btsb->agch_queue_length, btsb->agch_max_queue_length);
+
+		btsb->agch_queue_rejected_msgs++;
+		return -ENOMEM;
+	}
 
 	msgb_enqueue(&btsb->agch_queue, msg);
 	btsb->agch_queue_length++;
@@ -325,30 +345,109 @@ struct msgb *bts_agch_dequeue(struct gsm_bts *bts)
 	return msg;
 }
 
+/* Remove lower prio messages if the queue has grown to long.
+ *
+ * \return 0 iff the number of messages in the queue would fit into the AGCH
+ *         reserved part of the CCCH.
+ */
+static int compact_agch_queue(struct gsm_bts *bts)
+{
+	struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
+	struct msgb *msg, *msg2;
+	int max_len, slope, offs;
+	int level_low = btsb->agch_queue_low_level;
+	int level_high = btsb->agch_queue_high_level;
+	int level_thres = btsb->agch_queue_thresh_level;
+	struct gsm48_system_information_type_3 *si3 = GSM_BTS_SI(bts, SYSINFO_TYPE_3);
+	int bs_ag_blks_res = si3->control_channel_desc.bs_ag_blks_res;
+
+	max_len = btsb->agch_max_queue_length;
+
+	if (max_len == 0)
+		max_len = 1;
+
+	/* TODO: Make the constants configurable */
+	if (btsb->agch_queue_length < max_len * level_thres / 100)
+		goto out;
+
+	/* p^
+	 * 1+      /'''''
+	 *  |     /
+	 *  |    /
+	 * 0+---/--+----+--> Q length
+	 *    low high max_len
+	 */
+
+	offs = max_len * level_low / 100;
+	if (level_high > level_low)
+		slope = 0x10000 * 100 / (level_high - level_low);
+	else
+		slope = 0x10000 * max_len; /* p_drop >= 1 if len > offs */
+
+	llist_for_each_entry_safe(msg, msg2, &btsb->agch_queue, list) {
+		struct gsm48_imm_ass *imm_ass_cmd = msgb_l3(msg);
+		int p_drop;
+		LOGP(DSUM, LOGL_DEBUG,
+		     "AGCH: head is message type 0x%02x, length = %d/%d\n",
+		     imm_ass_cmd->msg_type,
+		     btsb->agch_queue_length, btsb->agch_max_queue_length);
+
+		if (imm_ass_cmd->msg_type != GSM48_MT_RR_IMM_ASS_REJ)
+			goto out;
+
+		/* IMMEDIATE ASSIGN REJECT */
+
+		p_drop = (btsb->agch_queue_length - offs) * slope / max_len;
+
+		if ((random() & 0xffff) >= p_drop)
+			goto out;
+
+		LOGP(DSUM, LOGL_DEBUG,
+		     "AGCH: dropping message type 0x%02x, length = %d/%d, "
+		     "p = %f\n",
+		     imm_ass_cmd->msg_type,
+		     btsb->agch_queue_length, btsb->agch_max_queue_length,
+		     p_drop / 65536.0);
+
+		llist_del(&msg->list);
+		btsb->agch_queue_length--;
+		msgb_free(msg);
+
+		btsb->agch_queue_dropped_msgs++;
+	}
+out:
+	return btsb->agch_queue_length > bs_ag_blks_res;
+}
+
 int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt,
 		      int is_ag_res)
 {
-	struct msgb *msg;
+	struct msgb *msg = NULL;
 	struct gsm_bts_role_bts *btsb = bts->role;
-	int rc;
+	int rc = 0;
 	int is_empty = 1;
-	struct gsm48_system_information_type_3 *si3 =
-		GSM_BTS_SI(bts, SYSINFO_TYPE_3);
-	int bs_ag_blks_res = si3->control_channel_desc.bs_ag_blks_res;
-	int agch_res_full = btsb->agch_queue_length > bs_ag_blks_res;
+	int agch_res_full;
+
+	/* Do queue house keeping.
+	 * This needs to be done every time a CCCH message is requested, since
+	 * the queue max length is calculated based on the CCCH block rate and
+	 * PCH messages also reduce the drain of the AGCH queue.
+	 */
+	agch_res_full = compact_agch_queue(bts);
 
-	if (!is_ag_res) {
+	/* Check for paging messages first if this is PCH */
+	if (!is_ag_res)
 		rc = paging_gen_msg(btsb->paging_state, out_buf, gt, &is_empty);
 
-		if (!is_empty || !agch_res_full)
-			return rc;
-	}
+	/* Check whether the block may be overwritten */
+	if (!is_empty || (!is_ag_res && !agch_res_full))
+		return rc;
 
-	/* special queue of messages from IMM ASS CMD */
 	msg = bts_agch_dequeue(bts);
 	if (!msg)
-		return 0;
+		return rc;
 
+	/* Copy AGCH message */
 	memcpy(out_buf, msgb_l3(msg), msgb_l3len(msg));
 	rc = msgb_l3len(msg);
 	LOGP(DSUM, LOGL_DEBUG,
diff --git a/tests/agch/agch_test.c b/tests/agch/agch_test.c
index 7e87bcf..a3868c1 100644
--- a/tests/agch/agch_test.c
+++ b/tests/agch/agch_test.c
@@ -129,6 +129,10 @@ static void test_agch_queue(void)
 	printf("Testing AGCH messages queue handling.\n");
 	btsb->agch_max_queue_length = 32;
 
+	btsb->agch_queue_low_level = 30;
+	btsb->agch_queue_high_level = 30;
+	btsb->agch_queue_thresh_level = 60;
+
 	for (round = 1; round <= num_rounds; round++) {
 		for (idx = 0; idx < num_ima_per_round; idx++) {
 			msg = msgb_alloc(GSM_MACBLOCK_LEN, __FUNCTION__);
diff --git a/tests/agch/agch_test.ok b/tests/agch/agch_test.ok
index 70a9797..57439ed 100644
--- a/tests/agch/agch_test.ok
+++ b/tests/agch/agch_test.ok
@@ -1,4 +1,4 @@
 Testing AGCH messages queue handling.
 AGCH filled: count 720, imm.ass 80, imm.ass.rej 640 (refs 640), queue limit 32, occupied 720, dropped 0, merged 0, rejected 0, ag-res 0, non-res 0
-AGCH drained: multiframes 241, imm.ass 80, imm.ass.rej 641 (refs 641), queue limit 32, occupied 0, dropped 0, merged 0, rejected 0, ag-res 240, non-res 480
+AGCH drained: multiframes 33, imm.ass 80, imm.ass.rej 17 (refs 17), queue limit 32, occupied 0, dropped 624, merged 0, rejected 0, ag-res 32, non-res 64
 Success
-- 
1.7.9.5





More information about the OpenBSC mailing list