Move out of alloc_algo code modifying the data model
This way the alloc_algo() becomes idempotent, simplifying implementation
of new alloc_algos as well as rolling back if allocation fails (for
instance because some resource is exhausted at the time).
For now the code applying the results is moved to tbf::alloc_algo(), but
it will eventually get out of tbf code, so that the MS object is
responsible for running it. As a result, there's no even need to create
TBF object before trying to allocate resources, which will help furher in
rollback operations described above.
Change-Id: I5ffd00f5f80bde4b73b78db44896f65e70e12b20
diff --git a/src/alloc_algo.cpp b/src/alloc_algo.cpp
index bc44cbf..c026590 100644
--- a/src/alloc_algo.cpp
+++ b/src/alloc_algo.cpp
@@ -214,29 +214,6 @@
return min_ts;
}
-static void attach_tbf_to_pdch(struct gprs_rlcmac_pdch *pdch,
- struct gprs_rlcmac_tbf *tbf)
-{
- if (tbf->pdch[pdch->ts_no])
- tbf->pdch[pdch->ts_no]->detach_tbf(tbf);
-
- tbf->pdch[pdch->ts_no] = pdch;
- pdch->attach_tbf(tbf);
-}
-
-static void assign_uplink_tbf_usf(struct gprs_rlcmac_pdch *pdch, struct gprs_rlcmac_ul_tbf *tbf, uint8_t tfi, int8_t usf)
-{
- tbf->m_tfi = tfi;
- tbf->m_usf[pdch->ts_no] = usf;
- attach_tbf_to_pdch(pdch, tbf);
-}
-
-static void assign_dlink_tbf(struct gprs_rlcmac_pdch *pdch, struct gprs_rlcmac_dl_tbf *tbf, uint8_t tfi)
-{
- tbf->m_tfi = tfi;
- attach_tbf_to_pdch(pdch, tbf);
-}
-
static int find_trx(const struct alloc_resources_req *req)
{
unsigned trx_no;
@@ -331,11 +308,12 @@
* Assign single slot for uplink and downlink
*
* \param[in] req Contains all the requested params
+ * \param[out] res The resolution/response for the allocation request
* \returns negative error code or 0 on success
*/
-int alloc_algorithm_a(const struct alloc_resources_req *req)
+int alloc_algorithm_a(const struct alloc_resources_req *req,
+ struct alloc_resources_res *res)
{
- struct gprs_rlcmac_pdch *pdch;
int ts = -1;
uint8_t ul_slots, dl_slots;
int trx_no;
@@ -388,26 +366,15 @@
return -EBUSY;
}
- pdch = &trx->pdch[ts];
+ res->trx = trx;
+ res->first_common_ts = &trx->pdch[ts];
+ res->reserved_ul_slots = 1 << ts;
+ res->reserved_dl_slots = 1 << ts;
+ res->ass_slots_mask = 1 << ts;
+ res->upgrade_to_multislot = false;
+ res->tfi = tfi;
+ res->usf[ts] = usf;
- /* The allocation will be successful, so the system state and tbf/ms
- * may be modified from now on. */
- if (req->direction == GPRS_RLCMAC_UL_TBF) {
- struct gprs_rlcmac_ul_tbf *ul_tbf = tbf_as_ul_tbf(req->tbf);
- LOGPSL(req, LOGL_DEBUG, "Assign uplink TS=%d TFI=%d USF=%d\n", ts, tfi, usf);
- assign_uplink_tbf_usf(pdch, ul_tbf, tfi, usf);
- } else {
- struct gprs_rlcmac_dl_tbf *dl_tbf = tbf_as_dl_tbf(req->tbf);
- LOGPSL(req, LOGL_DEBUG, "Assign downlink TS=%d TFI=%d\n", ts, tfi);
- assign_dlink_tbf(pdch, dl_tbf, tfi);
- }
-
- req->tbf->trx = trx;
- /* the only one TS is the common TS */
- ms_set_reserved_slots(req->ms, trx, 1 << ts, 1 << ts);
- ms_set_first_common_ts(req->ms, pdch);
-
- req->tbf->upgrade_to_multislot = false;
bts_do_rate_ctr_inc(req->bts, CTR_TBF_ALLOC_ALGO_A);
return 0;
}
@@ -766,76 +733,17 @@
return ul_slots;
}
-/*! Update MS' reserved timeslots
- *
- * \param[in,out] trx Pointer to TRX struct
- * \param[in,out] ms_ Pointer to MS object
- * \param[in] tbf_ Pointer to TBF struct
- * \param[in] res_ul_slots Newly reserved UL slots
- * \param[in] res_dl_slots Newly reserved DL slots
- */
-static void update_ms_reserved_slots(gprs_rlcmac_trx *trx, GprsMs *ms, uint8_t res_ul_slots, uint8_t res_dl_slots)
-{
- if (res_ul_slots == ms_reserved_ul_slots(ms) && res_dl_slots == ms_reserved_dl_slots(ms))
- return;
-
- /* The reserved slots have changed, update the MS */
- ms_set_reserved_slots(ms, trx, res_ul_slots, res_dl_slots);
-}
-
-/*! Assign given UL timeslots to UL TBF
- *
- * \param[in,out] ul_tbf Pointer to UL TBF struct
- * \param[in,out] trx Pointer to TRX object
- * \param[in] ul_slots Set of slots to be assigned
- * \param[in] tfi selected TFI
- * \param[in] usf selected USF
- */
-static void assign_ul_tbf_slots(struct gprs_rlcmac_ul_tbf *ul_tbf, gprs_rlcmac_trx *trx, uint8_t ul_slots, int tfi,
- int *usf)
-{
- uint8_t ts;
-
- for (ts = 0; ts < 8; ts++) {
- if (!(ul_slots & (1 << ts)))
- continue;
-
- OSMO_ASSERT(usf[ts] >= 0);
-
- LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning UL TS %u\n", ts);
- assign_uplink_tbf_usf(&trx->pdch[ts], ul_tbf, tfi, usf[ts]);
- }
-}
-
-/*! Assign given DL timeslots to DL TBF
- *
- * \param[in,out] dl_tbf Pointer to DL TBF struct
- * \param[in,out] trx Pointer to TRX object
- * \param[in] ul_slots Set of slots to be assigned
- * \param[in] tfi selected TFI
- */
-static void assign_dl_tbf_slots(struct gprs_rlcmac_dl_tbf *dl_tbf, gprs_rlcmac_trx *trx, uint8_t dl_slots, int tfi)
-{
- uint8_t ts;
-
- for (ts = 0; ts < 8; ts++) {
- if (!(dl_slots & (1 << ts)))
- continue;
-
- LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning DL TS %u\n", ts);
- assign_dlink_tbf(&trx->pdch[ts], dl_tbf, tfi);
- }
-}
-
/*! Slot Allocation: Algorithm B
*
* Assign as many downlink slots as possible.
* Assign one uplink slot. (With free USF)
*
* \param[in] req Contains all the requested params
+ * \param[out] res The resolution/response for the allocation request
* \returns negative error code or 0 on success
*/
-int alloc_algorithm_b(const struct alloc_resources_req *req)
+int alloc_algorithm_b(const struct alloc_resources_req *req,
+ struct alloc_resources_res *res)
{
uint8_t dl_slots;
uint8_t ul_slots;
@@ -845,15 +753,18 @@
uint8_t slotcount = 0;
uint8_t reserve_count = 0, trx_no;
int first_ts;
- int usf[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
int rc;
int tfi;
+ unsigned int i;
gprs_rlcmac_trx *trx;
char slot_info[9] = { 0 };
struct gprs_rlcmac_pdch *first_common_ts = ms_first_common_ts(req->ms);
LOGPAL(req, "B", LOGL_DEBUG, "Alloc start\n");
+ for (i = 0; i < ARRAY_SIZE(res->usf); i++)
+ res->usf[i] = -1;
+
/* Step 1: Get current state from the MS object */
reserved_dl_slots = ms_reserved_dl_slots(req->ms);
@@ -889,7 +800,7 @@
dl_slots = rc;
count_slots(dl_slots, reserved_dl_slots, &slotcount, &reserve_count);
} else {
- rc = allocate_usf(trx, rc, dl_slots, usf);
+ rc = allocate_usf(trx, rc, dl_slots, &res->usf[0]);
if (rc < 0)
return rc;
@@ -912,30 +823,27 @@
}
first_common_ts = &trx->pdch[first_common_tn];
+ res->trx = trx;
+ res->first_common_ts = first_common_ts;
+ res->reserved_ul_slots = reserved_ul_slots;
+ res->reserved_dl_slots = reserved_dl_slots;
+ res->tfi = tfi;
+ /* res->usf is already filled in above */
if (req->single && slotcount) {
- req->tbf->upgrade_to_multislot = (reserve_count > slotcount);
+ res->upgrade_to_multislot = (reserve_count > slotcount);
LOGPAL(req, "B", LOGL_INFO, "using single slot at TS %d\n", first_ts);
} else {
- req->tbf->upgrade_to_multislot = false;
+ res->upgrade_to_multislot = false;
LOGPAL(req, "B", LOGL_INFO, "using %d slots\n", slotcount);
}
ts_format(slot_info, dl_slots, ul_slots);
LOGP(DRLCMAC, LOGL_DEBUG, "- Available DL/UL slots: (TS=0)\"%s\"(TS=7)\n", slot_info);
- /* The allocation will be successful, so the system state and tbf/ms
- * may be modified from now on. */
-
- /* Step 4: Update MS and TBF and really allocate the resources */
-
- update_ms_reserved_slots(trx, req->ms, reserved_ul_slots, reserved_dl_slots);
- ms_set_first_common_ts(req->ms, first_common_ts);
- req->tbf->trx = trx;
-
if (req->direction == GPRS_RLCMAC_DL_TBF)
- assign_dl_tbf_slots(tbf_as_dl_tbf(req->tbf), trx, dl_slots, tfi);
+ res->ass_slots_mask = dl_slots;
else
- assign_ul_tbf_slots(tbf_as_ul_tbf(req->tbf), trx, ul_slots, tfi, usf);
+ res->ass_slots_mask = ul_slots;
bts_do_rate_ctr_inc(req->bts, CTR_TBF_ALLOC_ALGO_B);
@@ -951,9 +859,11 @@
* goal is to provide the highest possible bandwidth per MS.
*
* \param[in] req Contains all the requested params
+ * \param[out] res The resolution/response for the allocation request
* \returns negative error code or 0 on success
*/
-int alloc_algorithm_dynamic(const struct alloc_resources_req *req)
+int alloc_algorithm_dynamic(const struct alloc_resources_req *req,
+ struct alloc_resources_res *res)
{
int rc;
@@ -965,7 +875,7 @@
}
if (!req->bts->multislot_disabled) {
- rc = alloc_algorithm_b(req);
+ rc = alloc_algorithm_b(req, res);
if (rc >= 0)
return rc;
@@ -974,7 +884,7 @@
req->bts->multislot_disabled = 1;
}
- return alloc_algorithm_a(req);
+ return alloc_algorithm_a(req, res);
}
int gprs_alloc_max_dl_slots_per_ms(const struct gprs_rlcmac_bts *bts, uint8_t ms_class)
diff --git a/src/alloc_algo.h b/src/alloc_algo.h
index f55f278..7fbe945 100644
--- a/src/alloc_algo.h
+++ b/src/alloc_algo.h
@@ -32,23 +32,34 @@
/* BTS where to allocate resources */
struct gprs_rlcmac_bts *bts;
/* MS for which to allocate resources */
- struct GprsMs *ms;
+ const struct GprsMs *ms;
/* Direction of the TBF for which we are allocating resources */
enum gprs_rlcmac_tbf_direction direction;
/* Whether to allocate only a single (1) TS */
bool single;
/* Whether to allocate on a specific TRX (>=0) or not (-1) */
int8_t use_trx;
- /* FIXME: this will be removed in the future, tbf struct will be filled
- * in by caller of alloc_algorithm(). */
- struct gprs_rlcmac_tbf *tbf;
};
-int alloc_algorithm_a(const struct alloc_resources_req *req);
+struct alloc_resources_res {
+ struct gprs_rlcmac_trx *trx;
+ struct gprs_rlcmac_pdch *first_common_ts;
+ uint8_t reserved_ul_slots;
+ uint8_t reserved_dl_slots;
+ uint8_t ass_slots_mask;
+ bool upgrade_to_multislot;
+ uint8_t tfi;
+ int usf[8];
+};
-int alloc_algorithm_b(const struct alloc_resources_req *req);
+int alloc_algorithm_a(const struct alloc_resources_req *req,
+ struct alloc_resources_res *res);
-int alloc_algorithm_dynamic(const struct alloc_resources_req *req);
+int alloc_algorithm_b(const struct alloc_resources_req *req,
+ struct alloc_resources_res *res);
+
+int alloc_algorithm_dynamic(const struct alloc_resources_req *req,
+ struct alloc_resources_res *res);
int gprs_alloc_max_dl_slots_per_ms(const struct gprs_rlcmac_bts *bts, uint8_t ms_class);
#ifdef __cplusplus
diff --git a/src/gprs_pcu.h b/src/gprs_pcu.h
index b4c9f7d..956f0e7 100644
--- a/src/gprs_pcu.h
+++ b/src/gprs_pcu.h
@@ -67,8 +67,10 @@
struct GprsMs;
struct gprs_rlcmac_tbf;
struct alloc_resources_req;
+struct alloc_resources_res;
-typedef int (*alloc_algorithm_func_t)(const struct alloc_resources_req *req);
+typedef int (*alloc_algorithm_func_t)(const struct alloc_resources_req *req,
+ struct alloc_resources_res *res);
struct gprs_pcu {
diff --git a/src/tbf.cpp b/src/tbf.cpp
index 0b6fe58..921611d 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -572,6 +572,33 @@
}
}
+int gprs_rlcmac_tbf::alloc_algorithm(const struct alloc_resources_req *req)
+{
+ int rc;
+
+ /* select algorithm */
+ struct alloc_resources_res res = {};
+ rc = the_pcu->alloc_algorithm(req, &res);
+ if (rc < 0)
+ return rc;
+
+ /* The allocation will be successful, so the system state and tbf/ms
+ * may be modified from now on. */
+
+ /* Update MS, really allocate the resources */
+ if (res.reserved_ul_slots != ms_reserved_ul_slots(req->ms) ||
+ res.reserved_dl_slots != ms_reserved_dl_slots(req->ms)) {
+ /* The reserved slots have changed, update the MS */
+ ms_set_reserved_slots(ms(), res.trx, res.reserved_ul_slots, res.reserved_dl_slots);
+ }
+ ms_set_first_common_ts(ms(), res.first_common_ts);
+
+ /* Assign TRX,TS,TFI,USF to TBF: */
+ this->apply_allocated_resources(&res);
+
+ return 0;
+}
+
int gprs_rlcmac_tbf::setup(int8_t use_trx, bool single_slot)
{
int rc;
@@ -581,11 +608,10 @@
.direction = this->direction,
.single = single_slot,
.use_trx = use_trx,
- .tbf = this,
};
/* select algorithm */
- rc = the_pcu->alloc_algorithm(&req);
+ rc = this->alloc_algorithm(&req);
/* if no resource */
if (rc < 0) {
LOGPTBF(this, LOGL_NOTICE,
diff --git a/src/tbf.h b/src/tbf.h
index 3f58cd2..ba2a755 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -27,6 +27,7 @@
struct bssgp_bvc_ctx;
struct gprs_rlcmac_bts;
+struct alloc_resources_req;
#endif
@@ -162,6 +163,7 @@
virtual ~gprs_rlcmac_tbf();
virtual gprs_rlc_window *window() = 0;
+ virtual void apply_allocated_resources(const struct alloc_resources_res *res) = 0;
int setup(int8_t use_trx, bool single_slot);
bool state_is(enum tbf_fsm_states rhs) const;
@@ -212,6 +214,8 @@
/* attempt to make things a bit more fair */
void rotate_in_list();
+ int alloc_algorithm(const struct alloc_resources_req *req);
+
enum gprs_rlcmac_tbf_direction direction;
struct gprs_rlcmac_trx *trx;
struct gprs_rlcmac_pdch *control_ts; /* timeslot control messages and polling */
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index cb01222..4af9ae6 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -418,6 +418,28 @@
return create_dl_acked_block(fn, pdch, bsn, bsn2);
}
+void gprs_rlcmac_dl_tbf::apply_allocated_resources(const struct alloc_resources_res *res)
+{
+ uint8_t ts;
+
+ this->trx = res->trx;
+ this->upgrade_to_multislot = res->upgrade_to_multislot;
+
+ for (ts = 0; ts < ARRAY_SIZE(trx->pdch); ts++) {
+ struct gprs_rlcmac_pdch *pdch = &trx->pdch[ts];
+ OSMO_ASSERT(!this->pdch[pdch->ts_no]);
+ if (!(res->ass_slots_mask & (1 << ts)))
+ continue;
+ LOGPTBFDL(this, LOGL_DEBUG, "Assigning TS=%u TFI=%d\n",
+ ts, res->tfi);
+
+ this->m_tfi = res->tfi;
+
+ this->pdch[pdch->ts_no] = pdch;
+ pdch->attach_tbf(this);
+ }
+}
+
/* old_tbf (UL TBF or DL TBF) will send a Pkt Dl Ass on PACCH to assign tbf.
* Note: It is possible that "tbf == old_tbf" if the TBF is being updated. This can
* happen when we first assign over PCH (only single slot is possible) and we want
@@ -472,9 +494,8 @@
.direction = tbf_direction(tbf),
.single = false,
.use_trx = -1,
- .tbf = tbf,
};
- rc = the_pcu->alloc_algorithm(&req);
+ rc = dl_tbf->alloc_algorithm(&req);
/* if no resource */
if (rc < 0) {
LOGPTBFDL(dl_tbf, LOGL_ERROR, "No resources allocated during upgrade to multislot!\n");
diff --git a/src/tbf_dl.h b/src/tbf_dl.h
index 4fdfbed..90dfb12 100644
--- a/src/tbf_dl.h
+++ b/src/tbf_dl.h
@@ -46,6 +46,7 @@
gprs_rlcmac_dl_tbf(struct gprs_rlcmac_bts *bts, GprsMs *ms);
~gprs_rlcmac_dl_tbf();
gprs_rlc_window *window();
+ void apply_allocated_resources(const struct alloc_resources_res *res);
int rcvd_dl_ack(bool final_ack, unsigned first_bsn, struct bitvec *rbb);
struct msgb *create_dl_acked_block(uint32_t fn, const gprs_rlcmac_pdch *pdch,
diff --git a/src/tbf_ul.cpp b/src/tbf_ul.cpp
index 16ef304..47347f9 100644
--- a/src/tbf_ul.cpp
+++ b/src/tbf_ul.cpp
@@ -29,6 +29,7 @@
#include <gprs_ms.h>
#include <llc.h>
#include "pcu_utils.h"
+#include "alloc_algo.h"
extern "C" {
#include <osmocom/core/msgb.h>
@@ -704,6 +705,30 @@
return &m_window;
}
+void gprs_rlcmac_ul_tbf::apply_allocated_resources(const struct alloc_resources_res *res)
+{
+ uint8_t ts;
+
+ this->trx = res->trx;
+ this->upgrade_to_multislot = res->upgrade_to_multislot;
+
+ for (ts = 0; ts < ARRAY_SIZE(trx->pdch); ts++) {
+ struct gprs_rlcmac_pdch *pdch = &trx->pdch[ts];
+ OSMO_ASSERT(!this->pdch[pdch->ts_no]);
+ if (!(res->ass_slots_mask & (1 << ts)))
+ continue;
+ LOGPTBFUL(this, LOGL_DEBUG, "Assigning TS=%u TFI=%d USF=%u\n",
+ ts, res->tfi, res->usf[ts]);
+ OSMO_ASSERT(res->usf[ts] >= 0);
+
+ this->m_tfi = res->tfi;
+ this->m_usf[pdch->ts_no] = res->usf[ts];
+
+ this->pdch[pdch->ts_no] = pdch;
+ pdch->attach_tbf(this);
+ }
+}
+
void gprs_rlcmac_ul_tbf::usf_timeout()
{
if (n_inc(N3101))
diff --git a/src/tbf_ul.h b/src/tbf_ul.h
index aa54c8f..5ef8465 100644
--- a/src/tbf_ul.h
+++ b/src/tbf_ul.h
@@ -60,6 +60,7 @@
gprs_rlcmac_ul_tbf(struct gprs_rlcmac_bts *bts, GprsMs *ms);
~gprs_rlcmac_ul_tbf();
gprs_rlc_window *window();
+ void apply_allocated_resources(const struct alloc_resources_res *res);
/* blocks were acked */
int rcv_data_block_acknowledged(
const struct gprs_rlc_data_info *rlc,