blob: 320a7bff983da1fa285b4aba15dfe267046e414a [file] [log] [blame]
Pau Espin Pedrol582a15e2021-03-12 15:40:48 +01001/* PDCH UL Controller test
2 *
3 * Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
4 * Author: Pau Espin Pedrol <pespin@sysmocom.de>
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <string.h>
22#include <stdio.h>
Pau Espin Pedrol95f8fa12021-03-12 17:50:10 +010023#include <stdint.h>
24#include <unistd.h>
25#include <inttypes.h>
Pau Espin Pedrol582a15e2021-03-12 15:40:48 +010026
27extern "C" {
28#include <osmocom/core/application.h>
29#include <osmocom/gsm/gsm_utils.h>
30#include <osmocom/core/talloc.h>
31#include <osmocom/core/utils.h>
32}
33
Pau Espin Pedrol95f8fa12021-03-12 17:50:10 +010034#include "gprs_ms.h"
Pau Espin Pedrol582a15e2021-03-12 15:40:48 +010035#include "bts.h"
36#include "sba.h"
37#include "pdch_ul_controller.h"
38
39/* globals used by the code */
40void *tall_pcu_ctx;
41
Pau Espin Pedrol95f8fa12021-03-12 17:50:10 +010042static void print_ulc_nodes(struct pdch_ulc *ulc)
43{
44 struct rb_node *node;
45 for (node = rb_first(&ulc->tree_root); node; node = rb_next(node)) {
46 struct pdch_ulc_node *it = container_of(node, struct pdch_ulc_node, node);
47 printf("FN=%" PRIu32 " type=%s\n",
48 it->fn, get_value_string(pdch_ul_node_names, it->type));
49 }
50}
51
Pau Espin Pedrol582a15e2021-03-12 15:40:48 +010052static void test_reserve_multiple()
53{
54 printf("=== start: %s ===\n", __FUNCTION__);
55 const uint32_t fn = 20;
56 struct gprs_rlcmac_bts *bts = bts_alloc(the_pcu, 0);
57 struct gprs_rlcmac_pdch *pdch = &bts->trx[0].pdch[0];
58 struct gprs_rlcmac_tbf *tbf1 = (struct gprs_rlcmac_tbf*)0x1234; /*Dummy pointer */
59 struct gprs_rlcmac_tbf *tbf2 = (struct gprs_rlcmac_tbf*)0x5678; /*Dummy pointer */
60 struct gprs_rlcmac_sba *sba1, *sba2;
61 pdch->last_rts_fn = fn; /* This is used by sba_alloc to set + reserve FN */
62 sba1 = sba_alloc(bts, pdch, 0);
63 pdch->last_rts_fn = fn_next_block(pdch->last_rts_fn);
64 sba2 = sba_alloc(bts, pdch, 0);
65 uint32_t tbf1_poll_fn1 = fn_next_block(sba2->fn);
66 uint32_t tbf2_poll_fn1 = fn_next_block(tbf1_poll_fn1);
67 uint32_t tbf1_poll_fn2 = fn_next_block(tbf2_poll_fn1);
68 int rc;
69 struct pdch_ulc_node *node;
70
71 /* SBAs are reserved directly during allocation: */
72 OSMO_ASSERT(pdch_ulc_fn_is_free(pdch->ulc, sba1->fn) == false);
73 OSMO_ASSERT(pdch_ulc_get_sba(pdch->ulc, sba1->fn) == sba1);
74 OSMO_ASSERT(pdch_ulc_fn_is_free(pdch->ulc, sba2->fn) == false);
75 OSMO_ASSERT(pdch_ulc_get_sba(pdch->ulc, sba2->fn) == sba2);
76
77 rc = pdch_ulc_reserve_sba(pdch->ulc, sba1);
78 OSMO_ASSERT(rc == -EEXIST);
79 OSMO_ASSERT(pdch_ulc_fn_is_free(pdch->ulc, sba1->fn) == false);
80 node = pdch_ulc_get_node(pdch->ulc, sba1->fn);
81 OSMO_ASSERT(node->type == PDCH_ULC_NODE_SBA && node->sba.sba == sba1);
82 OSMO_ASSERT(pdch_ulc_fn_is_free(pdch->ulc, sba1->fn) == false);
83
84 rc = pdch_ulc_reserve_sba(pdch->ulc, sba2);
85 OSMO_ASSERT(rc == -EEXIST);
86 OSMO_ASSERT(pdch_ulc_get_sba(pdch->ulc, sba1->fn) == sba1);
87 OSMO_ASSERT(pdch_ulc_get_sba(pdch->ulc, sba2->fn) == sba2);
88 node = pdch_ulc_get_node(pdch->ulc, sba2->fn);
89 OSMO_ASSERT(node->type == PDCH_ULC_NODE_SBA && node->sba.sba == sba2);
90
91 rc = pdch_ulc_reserve_tbf_poll(pdch->ulc, sba1->fn, tbf1);
92 OSMO_ASSERT(rc == -EEXIST);
93 OSMO_ASSERT(pdch_ulc_get_tbf_poll(pdch->ulc, sba1->fn) == NULL);
94 rc = pdch_ulc_reserve_tbf_poll(pdch->ulc, sba2->fn, tbf1);
95 OSMO_ASSERT(rc == -EEXIST);
96 OSMO_ASSERT(pdch_ulc_get_tbf_poll(pdch->ulc, sba2->fn) == NULL);
97
98 /* Now Reserve correctly TBF1 */
99 OSMO_ASSERT(pdch_ulc_fn_is_free(pdch->ulc, tbf1_poll_fn1) == true);
100 rc = pdch_ulc_reserve_tbf_poll(pdch->ulc, tbf1_poll_fn1, tbf1);
101 OSMO_ASSERT(rc == 0);
102 OSMO_ASSERT(pdch_ulc_get_tbf_poll(pdch->ulc, tbf1_poll_fn1) == tbf1);
103 OSMO_ASSERT(pdch_ulc_fn_is_free(pdch->ulc, tbf1_poll_fn1) == false);
104 node = pdch_ulc_get_node(pdch->ulc, tbf1_poll_fn1);
105 OSMO_ASSERT(node->type == PDCH_ULC_NODE_TBF_POLL && node->tbf_poll.poll_tbf == tbf1);
106 OSMO_ASSERT(pdch_ulc_fn_is_free(pdch->ulc, tbf1_poll_fn1) == false);
107
108 /* Now reserve correctly TBF2 */
109 OSMO_ASSERT(pdch_ulc_fn_is_free(pdch->ulc, tbf2_poll_fn1) == true);
110 rc = pdch_ulc_reserve_tbf_poll(pdch->ulc, tbf2_poll_fn1, tbf2);
111 OSMO_ASSERT(rc == 0);
112 OSMO_ASSERT(pdch_ulc_get_tbf_poll(pdch->ulc, tbf2_poll_fn1) == tbf2);
113 OSMO_ASSERT(pdch_ulc_fn_is_free(pdch->ulc, tbf2_poll_fn1) == false);
114 node = pdch_ulc_get_node(pdch->ulc, tbf2_poll_fn1);
115 OSMO_ASSERT(node->type == PDCH_ULC_NODE_TBF_POLL && node->tbf_poll.poll_tbf == tbf2);
116 OSMO_ASSERT(pdch_ulc_fn_is_free(pdch->ulc, tbf2_poll_fn1) == false);
117
118 /* Now Reserve TBF1 for POLL again on a later FN, which is totally expected: */
119 OSMO_ASSERT(pdch_ulc_fn_is_free(pdch->ulc, tbf1_poll_fn2) == true);
120 rc = pdch_ulc_reserve_tbf_poll(pdch->ulc, tbf1_poll_fn2, tbf1);
121 OSMO_ASSERT(rc == 0);
122 OSMO_ASSERT(pdch_ulc_get_tbf_poll(pdch->ulc, tbf1_poll_fn2) == tbf1);
123 OSMO_ASSERT(pdch_ulc_fn_is_free(pdch->ulc, tbf1_poll_fn2) == false);
124 node = pdch_ulc_get_node(pdch->ulc, tbf1_poll_fn2);
125 OSMO_ASSERT(node->type == PDCH_ULC_NODE_TBF_POLL && node->tbf_poll.poll_tbf == tbf1);
126 OSMO_ASSERT(pdch_ulc_fn_is_free(pdch->ulc, tbf1_poll_fn2) == false);
127
128 /* Now release them in different ways: */
129 node = pdch_ulc_pop_node(pdch->ulc, sba2->fn);
130 OSMO_ASSERT(node->type == PDCH_ULC_NODE_SBA && node->sba.sba == sba2);
131 OSMO_ASSERT(pdch_ulc_get_sba(pdch->ulc, sba2->fn) == NULL);
132 OSMO_ASSERT(pdch_ulc_fn_is_free(pdch->ulc, sba2->fn) == true);
133 /* This will probably print a warning since in general SBAs are expected
134 * to be released from ULC during sba_free() time: */
135 sba_free(sba2);
136
137 pdch_ulc_expire_fn(pdch->ulc, sba1->fn);
138
139 /* here the 2 tbf1 entries should be removed, so Ul Controller should
140 only have 1 entry for tbf2 after the call: */
141 pdch_ulc_release_tbf(pdch->ulc, tbf1);
142 OSMO_ASSERT(pdch_ulc_get_tbf_poll(pdch->ulc, tbf1_poll_fn1) == NULL);
143 OSMO_ASSERT(pdch_ulc_get_tbf_poll(pdch->ulc, tbf1_poll_fn2) == NULL);
144 OSMO_ASSERT(pdch_ulc_get_tbf_poll(pdch->ulc, tbf2_poll_fn1) == tbf2);
145
146 rc = pdch_ulc_release_fn(pdch->ulc, tbf1_poll_fn1);
147 OSMO_ASSERT(rc == -ENOKEY);
148 rc = pdch_ulc_release_fn(pdch->ulc, tbf1_poll_fn2);
149 OSMO_ASSERT(rc == -ENOKEY);
150 rc = pdch_ulc_release_fn(pdch->ulc, tbf2_poll_fn1);
151 OSMO_ASSERT(rc == 0);
152
153 /* Make sure the store is empty now: */
154 OSMO_ASSERT(!rb_first(&pdch->ulc->tree_root));
155
156 talloc_free(bts);
157 printf("=== end: %s ===\n", __FUNCTION__);
158}
159
Pau Espin Pedrol95f8fa12021-03-12 17:50:10 +0100160int _alloc_algorithm_dummy(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf,
161 bool single, int8_t use_tbf)
162{
163 return 0;
164}
165
166
167static void test_fn_wrap_around()
168{
169 printf("=== start: %s ===\n", __FUNCTION__);
170 const uint32_t start_fn = GSM_MAX_FN - 40;
171
172 the_pcu->alloc_algorithm = _alloc_algorithm_dummy;
173
174 struct gprs_rlcmac_bts *bts = bts_alloc(the_pcu, 0);
175 struct GprsMs *ms = ms_alloc(bts, 0x12345678);
176 struct gprs_rlcmac_tbf *tbf1 = tbf_alloc_dl_tbf(bts, ms, 0, true);
177 tbf1->trx = &bts->trx[0];
178 struct gprs_rlcmac_pdch *pdch = &tbf1->trx->pdch[0];
179 int rc;
180 uint32_t fn, last_fn;
181
182 fn = start_fn;
183 while (fn < 40 || fn >= start_fn) {
184 printf("*** RESERVE FN=%" PRIu32 ":\n", fn);
185 rc = pdch_ulc_reserve_tbf_poll(pdch->ulc, fn, tbf1);
186 OSMO_ASSERT(rc == 0);
187 print_ulc_nodes(pdch->ulc);
188 fn = fn_next_block(fn);
189 }
190 last_fn = fn;
191
192 /* Expiring fn_next_block(start_fn) should only expire first 2 entries here: */
193 fn = fn_next_block(start_fn);
194 printf("*** EXPIRE FN=%" PRIu32 ":\n", fn);
195 pdch_ulc_expire_fn(pdch->ulc, fn);
196 print_ulc_nodes(pdch->ulc);
197
198 /* We should still be able to release FN=0 here, since it came later: */
199 printf("*** RELEASE fn=%" PRIu32 ":\n", 0);
200 rc = pdch_ulc_release_fn(pdch->ulc, 0);
201 print_ulc_nodes(pdch->ulc);
202 //OSMO_ASSERT(rc == 0); FIXME: DISABLED DUE TO BUG!
203
204 /* Expiring last FN should expire all entries */
205 printf("*** EXPIRE FN=%" PRIu32 ":\n", last_fn);
206 pdch_ulc_expire_fn(pdch->ulc, last_fn);
207 print_ulc_nodes(pdch->ulc);
208 /* Make sure the store is empty now: */
209 //OSMO_ASSERT(!rb_first(&pdch->ulc->tree_root)); FIXME: DISABLED DUE TO BUG!
210
211 talloc_free(bts);
212 printf("=== end: %s ===\n", __FUNCTION__);
213}
214
Pau Espin Pedrol582a15e2021-03-12 15:40:48 +0100215int main(int argc, char **argv)
216{
217 tall_pcu_ctx = talloc_named_const(NULL, 1, "pdch_ulc test context");
218 if (!tall_pcu_ctx)
219 abort();
220
221 msgb_talloc_ctx_init(tall_pcu_ctx, 0);
222 osmo_init_logging2(tall_pcu_ctx, &gprs_log_info);
223 log_set_use_color(osmo_stderr_target, 0);
224 log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
225 log_set_log_level(osmo_stderr_target, LOGL_DEBUG);
226 log_set_print_category_hex(osmo_stderr_target, 0);
227 log_set_print_category(osmo_stderr_target, 0);
228 log_parse_category_mask(osmo_stderr_target, "DPCU,1:DRLCMAC,1:DRLCMACUL,1");
229
230 the_pcu = gprs_pcu_alloc(tall_pcu_ctx);
231
232 test_reserve_multiple();
Pau Espin Pedrol95f8fa12021-03-12 17:50:10 +0100233 test_fn_wrap_around();
Pau Espin Pedrol582a15e2021-03-12 15:40:48 +0100234
235 talloc_free(the_pcu);
236 return EXIT_SUCCESS;
237}
238
239/*
240 * stubs that should not be reached
241 */
242int16_t spoof_mnc = 0, spoof_mcc = 0;
243bool spoof_mnc_3_digits = false;
244extern "C" {
245 void l1if_pdch_req() {
246 abort();
247 } void l1if_connect_pdch() {
248 abort();
249 }
250 void l1if_close_pdch() {
251 abort();
252 }
253 void l1if_open_pdch() {
254 abort();
255 }
256}