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.deThis 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