Commit 21f66094 authored by Robert Schmidt's avatar Robert Schmidt

FlexRAN: move slice param verification to agent

- until now, on every iteration, the scheduler checked for changed parameter
  (and verified some)
- this functionality moves to the FlexRAN Agent, which verifies all parameters
  * individually, e.g. Max MCS <= 28 for DL
  * group-based, e.g. the sum of slice percentages is <= 100
- slice configuration changes are only applied if all verifications pass
- it is assumed in the scheduler, that configuration passed from outside is
  correct and can be used "as-is"

fix accounting setting
parent 6b3dd871
......@@ -870,6 +870,7 @@ add_library(FLEXRAN_AGENT
${OPENAIR2_DIR}/ENB_APP/flexran_agent_net_comm.c
${OPENAIR2_DIR}/ENB_APP/flexran_agent_async.c
${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c
${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_slice_verification.c
)
set(FLEXRAN_AGENT_LIB FLEXRAN_AGENT)
#include_directories(${OPENAIR2_DIR}/ENB_APP)
......
......@@ -31,6 +31,7 @@
#include "flexran_agent_common_internal.h"
#include "flexran_agent_mac_internal.h"
#include "flexran_agent_mac_slice_verification.h"
/* from flexran_agent_mac.c */
extern Protocol__FlexSliceConfig *slice_config[NUM_MAX_ENB];
......@@ -1141,107 +1142,203 @@ void overwrite_slice_config_ul(Protocol__FlexUlSlice *exist, Protocol__FlexUlSli
}
}
void prepare_update_slice_config_dl(mid_t mod_id, Protocol__FlexDlSlice *dls)
void fill_dl_slice(mid_t mod_id, Protocol__FlexDlSlice *s)
{
if (!dls->has_id) {
LOG_E(FLEXRAN_AGENT, "[%d] Incoming DL slice configuration has no ID\n", mod_id);
return;
}
/* a percentage of zero will be interpreted as removal command */
if (sc_update[mod_id]->n_dl >= MAX_NUM_SLICES
&& (!dls->has_percentage || dls->percentage > 0)) {
LOG_E(FLEXRAN_AGENT, "[%d] Cannot create more than %ld slices in DL\n",
mod_id, sc_update[mod_id]->n_dl);
return;
}
if (sc_update[mod_id]->n_dl == 1 && dls->has_percentage && dls->percentage == 0) {
LOG_E(FLEXRAN_AGENT, "[%d] Cannot delete last slice ID %d in DL\n",
mod_id, sc_update[mod_id]->dl[0]->id);
return;
}
/* TODO fill the slice depending on the chosen label */
/* for now, we fill it up with the information from slice 0 */
/* assume there is an ID (will be checked later) */
if (!s->has_label) {
s->has_label = 1;
s->label = sc_update[mod_id]->dl[0]->label;
}
if (!s->has_percentage) {
s->has_percentage = 1;
s->percentage = sc_update[mod_id]->dl[0]->percentage;
}
if (!s->has_isolation) {
s->has_isolation = 1;
s->isolation = sc_update[mod_id]->dl[0]->isolation;
}
if (!s->has_priority) {
s->has_priority = 1;
s->priority = sc_update[mod_id]->dl[0]->priority;
}
if (!s->has_position_low) {
s->has_position_low = 1;
s->position_low = sc_update[mod_id]->dl[0]->position_low;
}
if (!s->has_position_high) {
s->has_position_high = 1;
s->position_high = sc_update[mod_id]->dl[0]->position_high;
}
if (!s->has_maxmcs) {
s->has_maxmcs = 1;
s->maxmcs = sc_update[mod_id]->dl[0]->maxmcs;
}
if (s->n_sorting == 0) {
s->n_sorting = sc_update[0]->dl[0]->n_sorting;
/* TODO Dangerous? */
s->sorting = sc_update[0]->dl[0]->sorting;
}
if (!s->has_accounting) {
/* TODO Dangerous? */
s->accounting = sc_update[0]->dl[0]->accounting;
}
/* scheduler name not set, cannot be changed for the moment */
}
Protocol__FlexDlSlice *to = NULL;
Protocol__FlexDlSlice *get_existing_dl_slice(mid_t mod_id, int id)
{
for (int i = 0; i < sc_update[mod_id]->n_dl; ++i) {
if (dls->id == sc_update[mod_id]->dl[i]->id) {
to = sc_update[mod_id]->dl[i];
break;
if (id == sc_update[mod_id]->dl[i]->id) {
return sc_update[mod_id]->dl[i];
}
}
return NULL;
}
/* create new slice -> read contents from existing slice config index 0 */
if (!to) {
LOG_I(FLEXRAN_AGENT,
"[%d] Creating DL slice with ID %d, taking default values from DL slice 0\n",
mod_id, dls->id);
to = sc_update[mod_id]->dl[sc_update[mod_id]->n_dl];
sc_update[mod_id]->n_dl++;
memcpy(to, slice_config[mod_id]->dl[0], sizeof(*to));
to->id = dls->id;
}
overwrite_slice_config_dl(to, dls);
Protocol__FlexDlSlice *create_new_dl_slice(mid_t mod_id, int id)
{
LOG_I(FLEXRAN_AGENT,
"[%d] Creating DL slice with ID %d, taking default values from DL slice 0\n",
mod_id, id);
Protocol__FlexDlSlice *to = sc_update[mod_id]->dl[sc_update[mod_id]->n_dl];
sc_update[mod_id]->n_dl++;
AssertFatal(sc_update[mod_id]->n_dl <= MAX_NUM_SLICES,
"cannot create more than MAX_NUM_SLICES\n");
to->id = id;
return to;
}
void prepare_update_slice_config_ul(mid_t mod_id, Protocol__FlexUlSlice *uls)
void fill_ul_slice(mid_t mod_id, Protocol__FlexUlSlice *s)
{
if (!uls->has_id) {
LOG_E(FLEXRAN_AGENT, "[%d] Incoming UL slice configuration has no ID\n", mod_id);
return;
}
/* a percentage of zero will be interpreted as removal command */
if (sc_update[mod_id]->n_ul >= MAX_NUM_SLICES
&& (!uls->has_percentage || uls->percentage > 0)) {
LOG_E(FLEXRAN_AGENT, "[%d] Cannot create more than %ld slices in UL\n",
mod_id, sc_update[mod_id]->n_ul);
return;
}
if (sc_update[mod_id]->n_ul == 1 && uls->has_percentage && uls->percentage == 0) {
LOG_E(FLEXRAN_AGENT, "[%d] Cannot delete last slice ID %d in UL\n",
mod_id, sc_update[mod_id]->ul[0]->id);
return;
}
/* TODO fill the slice depending on the chosen label */
/* for now, we fill it up with the information from slice 0 */
/* assume there is an ID (will be checked later) */
if (!s->has_label) {
s->has_label = 1;
s->label = sc_update[mod_id]->ul[0]->label;
}
if (!s->has_percentage) {
s->has_percentage = 1;
s->percentage = sc_update[mod_id]->ul[0]->percentage;
}
if (!s->has_isolation) {
s->has_isolation = 1;
s->isolation = sc_update[mod_id]->ul[0]->isolation;
}
if (!s->has_priority) {
s->has_priority = 1;
s->priority = sc_update[mod_id]->ul[0]->priority;
}
if (!s->has_first_rb) {
s->has_first_rb = 1;
s->first_rb = sc_update[mod_id]->ul[0]->first_rb;
}
if (!s->has_maxmcs) {
s->has_maxmcs = 1;
s->maxmcs = sc_update[mod_id]->ul[0]->maxmcs;
}
if (s->n_sorting == 0) {
s->n_sorting = sc_update[0]->ul[0]->n_sorting;
/* TODO Dangerous? */
s->sorting = sc_update[0]->ul[0]->sorting;
}
if (!s->has_accounting) {
/* TODO Dangerous? */
s->accounting = sc_update[0]->ul[0]->accounting;
}
/* scheduler name not set, cannot be changed for the moment */
}
Protocol__FlexUlSlice *to = NULL;
Protocol__FlexUlSlice *get_existing_ul_slice(mid_t mod_id, int id)
{
for (int i = 0; i < sc_update[mod_id]->n_ul; ++i) {
if (uls->id == sc_update[mod_id]->ul[i]->id) {
to = sc_update[mod_id]->ul[i];
break;
if (id == sc_update[mod_id]->ul[i]->id) {
return sc_update[mod_id]->ul[i];
}
}
return NULL;
}
/* create new slice -> read contents from existing slice config index 0 */
if (!to) {
LOG_I(FLEXRAN_AGENT,
"[%d] Creating UL slice with ID %d, taking default values from UL slice 0\n",
mod_id, uls->id);
to = sc_update[mod_id]->ul[sc_update[mod_id]->n_ul];
sc_update[mod_id]->n_ul++;
memcpy(to, slice_config[mod_id]->ul[0], sizeof(*to));
to->id = uls->id;
}
overwrite_slice_config_ul(to, uls);
Protocol__FlexUlSlice *create_new_ul_slice(mid_t mod_id, int id)
{
LOG_I(FLEXRAN_AGENT,
"[%d] Creating UL slice with ID %d, taking default values from UL slice 0\n",
mod_id, id);
Protocol__FlexUlSlice *to = sc_update[mod_id]->ul[sc_update[mod_id]->n_ul];
sc_update[mod_id]->n_ul++;
AssertFatal(sc_update[mod_id]->n_ul <= MAX_NUM_SLICES,
"cannot create more than MAX_NUM_SLICES\n");
to->id = id;
return to;
}
void prepare_update_slice_config(mid_t mod_id, Protocol__FlexSliceConfig *slice)
void prepare_update_slice_config(mid_t mod_id, Protocol__FlexSliceConfig *sup)
{
int verified = 1;
if (!sc_update[mod_id]) {
LOG_E(FLEXRAN_AGENT, "Can not update slice policy (no existing slice profile)\n");
return;
}
pthread_mutex_lock(&sc_update_mtx);
if (slice->n_dl == 0)
if (sup->n_dl == 0) {
LOG_I(FLEXRAN_AGENT, "[%d] no DL slice configuration in flex_slice_config message\n", mod_id);
for (int i = 0; i < slice->n_dl; i++)
prepare_update_slice_config_dl(mod_id, slice->dl[i]);
} else {
/* verify slice parameters */
for (int i = 0; i < sup->n_dl; i++) {
fill_dl_slice(mod_id, sup->dl[i]);
verified = verified && flexran_verify_dl_slice(mod_id, sup->dl[i]);
if (!verified) break;
}
if (slice->n_ul == 0)
/* verify group-based parameters (e.g. sum percentage should not exceed
* 100%). Can be used to perform admission control */
verified = verified && flexran_verify_group_dl_slices(mod_id,
sc_update[mod_id]->dl, sc_update[mod_id]->n_dl, sup->dl, sup->n_dl);
if (verified) {
for (int i = 0; i < sup->n_dl; i++) {
/* if all verifications were successful, get existing slice for ID or
* create new one and overwrite with the update */
Protocol__FlexDlSlice *dls = get_existing_dl_slice(mod_id, sup->dl[i]->id);
if (!dls) dls = create_new_dl_slice(mod_id, sup->dl[i]->id);
overwrite_slice_config_dl(dls, sup->dl[i]);
}
} else {
LOG_E(FLEXRAN_AGENT, "[%d] DL slice verification failed, refusing application\n", mod_id);
}
}
verified = 1;
if (sup->n_ul == 0) {
LOG_I(FLEXRAN_AGENT, "[%d] no UL slice configuration in flex_slice_config message\n", mod_id);
for (int i = 0; i < slice->n_ul; i++)
prepare_update_slice_config_ul(mod_id, slice->ul[i]);
} else {
/* verify slice parameters */
for (int i = 0; i < sup->n_ul; i++) {
fill_ul_slice(mod_id, sup->ul[i]);
verified = verified && flexran_verify_ul_slice(mod_id, sup->ul[i]);
if (!verified) break;
}
/* verify group-based parameters (e.g. sum percentage should not exceed
* 100%). Can be used to perform admission control */
verified = verified && flexran_verify_group_ul_slices(mod_id,
sc_update[mod_id]->ul, sc_update[mod_id]->n_ul, sup->ul, sup->n_ul);
if (verified) {
for (int i = 0; i < sup->n_ul; i++) {
/* if all verifications were successful, get existing slice for ID or
* create new one and overwrite with the update */
Protocol__FlexUlSlice *uls = get_existing_ul_slice(mod_id, sup->ul[i]->id);
if (!uls) uls = create_new_ul_slice(mod_id, sup->ul[i]->id);
overwrite_slice_config_ul(uls, sup->ul[i]);
}
} else {
LOG_E(FLEXRAN_AGENT, "[%d] UL slice verification failed, refusing application\n", mod_id);
}
}
pthread_mutex_unlock(&sc_update_mtx);
/* perform the slice configuration reads a couple of times. If there are
......@@ -1299,11 +1396,6 @@ int apply_new_slice_dl_config(mid_t mod_id, Protocol__FlexDlSlice *oldc, Protoco
flexran_set_dl_slice_accounting_policy(mod_id, slice_idx, newc->accounting);
changes++;
}
if (strcmp(oldc->scheduler_name, newc->scheduler_name) != 0) {
LOG_E(FLEXRAN_AGENT, "[%d][DL slice %d] setting the DL scheduler is not supported, reverting\n",
mod_id, newc->id);
newc->scheduler_name = oldc->scheduler_name;
}
return changes;
}
......@@ -1365,11 +1457,6 @@ int apply_new_slice_ul_config(mid_t mod_id, Protocol__FlexUlSlice *oldc, Protoco
LOG_W(FLEXRAN_AGENT, "[%d][UL slice %d] setting the accounting is not supported\n",
mod_id, slice_idx);
}
if (strcmp(oldc->scheduler_name, newc->scheduler_name) != 0) {
LOG_E(FLEXRAN_AGENT, "[%d][UL slice %d] setting the UL scheduler is not supported, reverting\n",
mod_id, slice_idx);
newc->scheduler_name = oldc->scheduler_name;
}
return changes;
}
......
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file flexran_agent_mac_slice_verification.c
* \brief MAC Agent slice verification helper functions
* \author Robert Schmidt
* \date 2018
* \version 0.1
*/
#include "flexran_agent_mac_slice_verification.h"
/* overlap check for UL slices, helper type */
struct sregion_s {
int start;
int length;
};
/* forward declaration of locally-used verification functions */
int flexran_dl_slice_verify_pct(int pct);
int flexran_dl_slice_verify_priority(int prio);
int flexran_dl_slice_verify_position(int pos_low, int pos_high);
int flexran_dl_slice_verify_maxmcs(int maxmcs);
int flexran_ul_slice_verify_pct(int pct);
int flexran_ul_slice_verify_priority(int prio);
int flexran_ul_slice_verify_first_rb(int first_rb);
int flexran_ul_slice_verify_maxmcs(int maxmcs);
int check_ul_slice_overlap(mid_t mod_id, struct sregion_s *sr, int n);
int flexran_verify_dl_slice(mid_t mod_id, Protocol__FlexDlSlice *dls)
{
/* check mandatory parameters */
if (!dls->has_id) {
LOG_E(FLEXRAN_AGENT, "[%d] Incoming DL slice configuration has no ID\n", mod_id);
return 0;
}
/* verify parameters individualy */
/* label is enum */
if (!flexran_dl_slice_verify_pct(dls->percentage)) {
LOG_E(FLEXRAN_AGENT, "[%d] illegal DL slice percentage (%d)\n", mod_id, dls->percentage);
return 0;
}
/* isolation is a protobuf bool */
if (!flexran_dl_slice_verify_priority(dls->priority)) {
LOG_E(FLEXRAN_AGENT, "[%d] illegal DL slice priority (%d)\n", mod_id, dls->priority);
return 0;
}
if (!flexran_dl_slice_verify_position(dls->position_low, dls->position_high)) {
LOG_E(FLEXRAN_AGENT, "[%d] illegal DL slice position low (%d) and/or high (%d)\n",
mod_id, dls->position_low, dls->position_high);
return 0;
}
if (!flexran_dl_slice_verify_maxmcs(dls->maxmcs)) {
LOG_E(FLEXRAN_AGENT, "[%d] illegal DL slice max mcs %d\n", mod_id, dls->maxmcs);
return 0;
}
if (dls->n_sorting == 0) {
LOG_E(FLEXRAN_AGENT, "[%d] no sorting in DL slice", mod_id);
return 0;
}
if (!dls->sorting) {
LOG_E(FLEXRAN_AGENT, "[%d] no sorting found in DL slice\n", mod_id);
return 0;
}
/* sorting is an enum */
/* accounting is an enum */
if (dls->scheduler_name) {
LOG_E(FLEXRAN_AGENT, "[%d] setting the scheduler is not allowed\n", mod_id);
return 0;
}
return 1;
}
int flexran_verify_group_dl_slices(mid_t mod_id, Protocol__FlexDlSlice **existing,
int n_ex, Protocol__FlexDlSlice **update, int n_up)
{
int i, j, n;
int pct, pct_orig;
/* for every update, array points to existing slice, or NULL if update
* creates new slice */
Protocol__FlexDlSlice *s[n_up];
for (i = 0; i < n_up; i++) {
s[i] = NULL;
for (j = 0; j < n_ex; j++) {
if (existing[j]->id == update[i]->id)
s[i] = existing[j];
}
}
/* check that number of created and number of added slices in total matches
* [1,10] */
n = n_ex;
for (i = 0; i < n_up; i++) {
/* new slice */
if (!s[i]) n += 1;
/* slice will be deleted */
else if (s[i]->percentage == 0) n -= 1;
/* else "only" an update */
}
if (n < 1 || n > MAX_NUM_SLICES) {
LOG_E(FLEXRAN_AGENT, "[%d] Illegal number of resulting slices (%d -> %d)\n", mod_id, n_ex, n);
return 0;
}
/* check that the sum of all slices percentages (including removed/added
* slices) matches [1,100] */
pct = 0;
for (i = 0; i < n_ex; i++) {
pct += existing[i]->percentage;
}
pct_orig = pct;
for (i = 0; i < n_up; i++) {
/* if there is an existing slice, subtract its percentage and add the
* update's percentage */
if (s[i])
pct -= s[i]->percentage;
pct += update[i]->percentage;
}
if (pct < 1 || pct > 100) {
LOG_E(FLEXRAN_AGENT, "[%d] invalid total RB share (%d%% -> %d%%)\n", mod_id, pct_orig, pct);
return 0;
}
return 1;
}
int flexran_verify_ul_slice(mid_t mod_id, Protocol__FlexUlSlice *uls)
{
/* check mandatory parameters */
if (!uls->has_id) {
LOG_E(FLEXRAN_AGENT, "[%d] Incoming UL slice configuration has no ID\n", mod_id);
return 0;
}
/* verify parameters individually */
/* label is enum */
if (!flexran_ul_slice_verify_pct(uls->percentage)) {
LOG_E(FLEXRAN_AGENT, "[%d] illegal UL slice percentage (%d)\n", mod_id, uls->percentage);
return 0;
}
/* isolation is a protobuf bool */
if (!flexran_ul_slice_verify_priority(uls->priority)) {
LOG_E(FLEXRAN_AGENT, "[%d] illegal UL slice percentage (%d)\n", mod_id, uls->priority);
return 0;
}
if (!flexran_ul_slice_verify_first_rb(uls->first_rb)) {
LOG_E(FLEXRAN_AGENT, "[%d] illegal UL slice first RB (%d)\n", mod_id, uls->first_rb);
return 0;
}
if (!flexran_ul_slice_verify_maxmcs(uls->maxmcs)) {
LOG_E(FLEXRAN_AGENT, "[%d] illegal UL slice max mcs (%d)\n", mod_id, uls->maxmcs);
return 0;
}
if (uls->n_sorting == 0) {
LOG_E(FLEXRAN_AGENT, "[%d] no sorting in UL slice\n", mod_id);
return 0;
}
if (!uls->sorting) {
LOG_E(FLEXRAN_AGENT, "[%d] no sorting found in UL slice\n", mod_id);
return 0;
}
/* sorting is an enum */
/* accounting is an enum */
if (uls->scheduler_name) {
LOG_E(FLEXRAN_AGENT, "[%d] setting the scheduler is not allowed\n", mod_id);
return 0;
}
return 1;
}
int flexran_verify_group_ul_slices(mid_t mod_id, Protocol__FlexUlSlice **existing,
int n_ex, Protocol__FlexUlSlice **update, int n_up)
{
int i, j, n;
int pct, pct_orig;
/* for every update, array "s" points to existing slice, or NULL if update
* creates new slice; array "offs" gives the offset of this slice */
Protocol__FlexUlSlice *s[n_up];
int offs[n_up];
for (i = 0; i < n_up; i++) {
s[i] = NULL;
offs[i] = 0;
for (j = 0; j < n_ex; j++) {
if (existing[j]->id == update[i]->id) {
s[i] = existing[j];
offs[i] = j;
}
}
}
/* check that number of created and number of added slices in total matches
* [1,10] */
n = n_ex;
for (i = 0; i < n_up; i++) {
/* new slice */
if (!s[i]) n += 1;
/* slice will be deleted */
else if (s[i]->percentage == 0) n -= 1;
/* else "only" an update */
}
if (n < 1 || n > MAX_NUM_SLICES) {
LOG_E(FLEXRAN_AGENT, "[%d] Illegal number of resulting slices (%d -> %d)\n", mod_id, n_ex, n);
return 0;
}
/* check that the sum of all slices percentages (including removed/added
* slices) matches [1,100] */
pct = 0;
for (i = 0; i < n_ex; i++) {
pct += existing[i]->percentage;
}
pct_orig = pct;
for (i = 0; i < n_up; i++) {
/* if there is an existing slice, subtract its percentage and add the
* update's percentage */
if (s[i])
pct -= s[i]->percentage;
pct += update[i]->percentage;
}
if (pct < 1 || pct > 100) {
LOG_E(FLEXRAN_AGENT, "[%d] invalid total RB share (%d%% -> %d%%)\n", mod_id, pct_orig, pct);
return 0;
}
/* check that there is no overlap in slices resulting as the combination of
* first_rb and percentage */
struct sregion_s sregion[n];
const int N_RB = flexran_get_N_RB_UL(mod_id, 0); /* assume PCC */
int k = n_ex;
for (i = 0; i < n_ex; i++) {