This patch implements merging of IMMEDIATE ASSIGN REJECT messages as
sugegsted in GSM 08.58, 5.7. When a new IMM.ASS.REJ is to be appended
to the AGCH queue and the last message in that queue is of the same
type, the individual entries (up to 4 per message) of both messages
are extracted, combined and stored back. If there are less than 5
entries all entries fit into the old message and the new one is
discarded. Otherwise, the old message will contain 4 entries and the
remaining ones are stored into the new one which is then appended to
the queue.
Ticket: #224
Sponsored-by: On-Waves ehf
---
src/common/bts.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++
src/common/vty.c | 12 ++--
tests/agch/agch_test.ok | 4 +-
3 files changed, 154 insertions(+), 8 deletions(-)
diff --git a/src/common/bts.c b/src/common/bts.c
index 0b14020..566cadb 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -302,10 +302,138 @@ void bts_update_agch_max_queue_length(struct gsm_bts *bts)
si3->control_channel_desc.bs_ag_blks_res);
}
+#define REQ_REFS_PER_IMM_ASS_REJ 4
+static int store_imm_ass_rej_refs(struct gsm48_imm_ass_rej *rej,
+ struct gsm48_req_ref *req_refs,
+ uint8_t *wait_inds,
+ int count)
+{
+ switch (count) {
+ case 0:
+ /* TODO: Warning ? */
+ return 0;
+ default:
+ count = 4;
+ rej->req_ref4 = req_refs[3];
+ rej->wait_ind4 = wait_inds[3];
+ /* no break */
+ case 3:
+ rej->req_ref3 = req_refs[2];
+ rej->wait_ind3 = wait_inds[2];
+ /* no break */
+ case 2:
+ rej->req_ref2 = req_refs[1];
+ rej->wait_ind2 = wait_inds[1];
+ /* no break */
+ case 1:
+ rej->req_ref1 = req_refs[0];
+ rej->wait_ind1 = wait_inds[0];
+ break;
+ }
+
+ switch (count) {
+ case 1:
+ rej->req_ref2 = req_refs[0];
+ rej->wait_ind2 = wait_inds[0];
+ /* no break */
+ case 2:
+ rej->req_ref3 = req_refs[0];
+ rej->wait_ind3 = wait_inds[0];
+ /* no break */
+ case 3:
+ rej->req_ref4 = req_refs[0];
+ rej->wait_ind4 = wait_inds[0];
+ /* no break */
+ default:
+ break;
+ }
+
+ return count;
+}
+
+static int extract_imm_ass_rej_refs(struct gsm48_imm_ass_rej *rej,
+ struct gsm48_req_ref *req_refs,
+ uint8_t *wait_inds)
+{
+ int count = 0;
+ req_refs[count] = rej->req_ref1;
+ wait_inds[count] = rej->wait_ind1;
+ count++;
+
+ if (memcmp(&rej->req_ref1, &rej->req_ref2, sizeof(rej->req_ref2))) {
+ req_refs[count] = rej->req_ref2;
+ wait_inds[count] = rej->wait_ind2;
+ count++;
+ }
+
+ if (memcmp(&rej->req_ref1, &rej->req_ref3, sizeof(rej->req_ref3))
+ && memcmp(&rej->req_ref2, &rej->req_ref3,
sizeof(rej->req_ref3))) {
+ req_refs[count] = rej->req_ref3;
+ wait_inds[count] = rej->wait_ind3;
+ count++;
+ }
+
+ if (memcmp(&rej->req_ref1, &rej->req_ref4, sizeof(rej->req_ref4))
+ && memcmp(&rej->req_ref2, &rej->req_ref4,
sizeof(rej->req_ref4))
+ && memcmp(&rej->req_ref3, &rej->req_ref4,
sizeof(rej->req_ref4))) {
+ req_refs[count] = rej->req_ref4;
+ wait_inds[count] = rej->wait_ind4;
+ count++;
+ }
+
+ return count;
+}
+
+static int try_merge_imm_ass_rej(struct gsm48_imm_ass_rej *old_rej,
+ struct gsm48_imm_ass_rej *new_rej)
+{
+ struct gsm48_req_ref req_refs[2 * REQ_REFS_PER_IMM_ASS_REJ];
+ uint8_t wait_inds[2 * REQ_REFS_PER_IMM_ASS_REJ];
+ int count = 0;
+ int stored = 0;
+
+ if (new_rej->msg_type != GSM48_MT_RR_IMM_ASS_REJ)
+ return 0;
+ if (old_rej->msg_type != GSM48_MT_RR_IMM_ASS_REJ)
+ return 0;
+
+ /* GSM 08.58, 5.7
+ * -> The BTS may combine serveral IMM.ASS.REJ messages
+ * -> Identical request refs in one message may be squeezed
+ *
+ * GSM 04.08, 9.1.20.2
+ * -> Request ref and wait ind are duplicated to fill the message
+ */
+
+ /* Extract all entries */
+ count = extract_imm_ass_rej_refs(old_rej,
+ &req_refs[count], &wait_inds[count]);
+ if (count == REQ_REFS_PER_IMM_ASS_REJ)
+ return 0;
+
+ count += extract_imm_ass_rej_refs(new_rej,
+ &req_refs[count], &wait_inds[count]);
+
+ /* Store entries into old message */
+ stored = store_imm_ass_rej_refs(old_rej,
+ &req_refs[stored], &wait_inds[stored],
+ count);
+ count -= stored;
+ if (count == 0)
+ return 1;
+
+ /* Store remaining entries into new message */
+ stored += store_imm_ass_rej_refs(new_rej,
+ &req_refs[stored], &wait_inds[stored],
+ count);
+ return 0;
+}
+
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;
+ struct gsm48_imm_ass_rej *imm_ass_cmd = msgb_l3(msg);
if (btsb->agch_queue_length > hard_limit) {
LOGP(DSUM, LOGL_ERROR,
@@ -318,6 +446,24 @@ int bts_agch_enqueue(struct gsm_bts *bts, struct msgb *msg)
return -ENOMEM;
}
+ if (btsb->agch_queue_length > 0) {
+ struct msgb *last_msg =
+ llist_entry(btsb->agch_queue.prev, struct msgb, list);
+ struct gsm48_imm_ass_rej *last_imm_ass_rej = msgb_l3(last_msg);
+
+ if (try_merge_imm_ass_rej(last_imm_ass_rej, imm_ass_cmd)) {
+ LOGP(DSUM, LOGL_DEBUG,
+ "AGCH: merged message type 0x%02x, length = %d/%d, "
+ "msg = %s\n",
+ last_imm_ass_rej->msg_type,
+ btsb->agch_queue_length, btsb->agch_max_queue_length,
+ osmo_hexdump(msgb_l3(last_msg), msgb_l3len(last_msg)));
+
+ btsb->agch_queue_merged_msgs++;
+ return 0;
+ }
+ }
+
msgb_enqueue(&btsb->agch_queue, msg);
btsb->agch_queue_length++;
diff --git a/src/common/vty.c b/src/common/vty.c
index f7a04d6..b59cc9b 100644
--- a/src/common/vty.c
+++ b/src/common/vty.c
@@ -158,15 +158,15 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts
*bts)
VTY_NEWLINE);
vty_out(vty, " paging lifetime %u%s",
paging_get_lifetime(btsb->paging_state),
VTY_NEWLINE);
- if (btsb->agch_queue_thres_level == GSM_BTS_AGCH_QUEUE_THRES_LEVEL_DISABLE)
+ if (btsb->agch_queue_thresh_level == GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DISABLE)
vty_out(vty, " no agch-queue-mgmt%s", VTY_NEWLINE);
- else if (btsb->agch_queue_thres_level == GSM_BTS_AGCH_QUEUE_THRES_LEVEL_DEFAULT
+ else if (btsb->agch_queue_thresh_level == GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DEFAULT
&& btsb->agch_queue_low_level == GSM_BTS_AGCH_QUEUE_LOW_LEVEL_DEFAULT
&& btsb->agch_queue_high_level == GSM_BTS_AGCH_QUEUE_HIGH_LEVEL_DEFAULT)
vty_out(vty, " agch-queue-mgmt%s", VTY_NEWLINE);
else
vty_out(vty, " agch-queue-mgmt threshold %d low %d high %d%s",
- btsb->agch_queue_thres_level, btsb->agch_queue_low_level,
+ btsb->agch_queue_thresh_level, btsb->agch_queue_low_level,
btsb->agch_queue_high_level, VTY_NEWLINE);
bts_model_config_write_bts(vty, bts);
@@ -347,7 +347,7 @@ DEFUN(cfg_bts_agch_queue_mgmt_params,
struct gsm_bts *bts = vty->index;
struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
- btsb->agch_queue_thres_level = atoi(argv[0]);
+ btsb->agch_queue_thresh_level = atoi(argv[0]);
btsb->agch_queue_low_level = atoi(argv[1]);
btsb->agch_queue_high_level = atoi(argv[2]);
@@ -362,7 +362,7 @@ DEFUN(cfg_bts_agch_queue_mgmt,
struct gsm_bts *bts = vty->index;
struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
- btsb->agch_queue_thres_level = GSM_BTS_AGCH_QUEUE_THRES_LEVEL_DEFAULT;
+ btsb->agch_queue_thresh_level = GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DEFAULT;
btsb->agch_queue_low_level = GSM_BTS_AGCH_QUEUE_LOW_LEVEL_DEFAULT;
btsb->agch_queue_high_level = GSM_BTS_AGCH_QUEUE_HIGH_LEVEL_DEFAULT;
@@ -377,7 +377,7 @@ DEFUN(cfg_bts_no_agch_queue_mgmt,
struct gsm_bts *bts = vty->index;
struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
- btsb->agch_queue_thres_level = GSM_BTS_AGCH_QUEUE_THRES_LEVEL_DISABLE;
+ btsb->agch_queue_thresh_level = GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DISABLE;
btsb->agch_queue_low_level = 0;
btsb->agch_queue_high_level = 0;
diff --git a/tests/agch/agch_test.ok b/tests/agch/agch_test.ok
index 57439ed..f31676a 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 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
+AGCH filled: count 720, imm.ass 80, imm.ass.rej 640 (refs 640), queue limit 32, occupied
240, dropped 0, merged 480, rejected 0, ag-res 0, non-res 0
+AGCH drained: multiframes 32, imm.ass 80, imm.ass.rej 12 (refs 48), queue limit 32,
occupied 0, dropped 148, merged 480, rejected 0, ag-res 31, non-res 61
Success
--
1.7.9.5