diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c
index 549c7eaa2227e944a98747b6bcdd2f8a2ac73207..0c33026a38b39c1742210efdf6be8afe8b688217 100644
--- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c
+++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c
@@ -52,6 +52,16 @@ struct lfds700_misc_prng_state ps[NUM_MAX_ENB];
 struct lfds700_ringbuffer_element *dl_mac_config_array[NUM_MAX_ENB];
 struct lfds700_ringbuffer_state ringbuffer_state[NUM_MAX_ENB];
 
+/* the slice config as kept in the underlying system */
+Protocol__FlexSliceConfig *slice_config[NUM_MAX_ENB];
+/* a structure that keeps updates which will be reflected in slice_config later */
+Protocol__FlexSliceConfig *sc_update[NUM_MAX_ENB];
+/* indicates whether sc_update contains new data */
+int perform_slice_config_update_count = 1;
+/* queue of incoming new UE<>slice association commands */
+Protocol__FlexUeConfig *ue_slice_assoc_update[NUM_MAX_UE];
+int n_ue_slice_assoc_updates = 0;
+
 
 int flexran_agent_mac_stats_reply(mid_t mod_id,
           const report_config_t *report_config,
@@ -1372,8 +1382,141 @@ int flexran_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) {
   return 0;
 }
 
+void flexran_create_config_structures(mid_t mod_id)
+{
+  int i;
+  int n_dl = flexran_get_num_dl_slices(mod_id);
+  int m_ul = flexran_get_num_ul_slices(mod_id);
+  slice_config[mod_id] = flexran_agent_create_slice_config(n_dl, m_ul);
+  sc_update[mod_id] = flexran_agent_create_slice_config(n_dl, m_ul);
+  if (!slice_config[mod_id] || !sc_update[mod_id]) return;
+
+  for (i = 0; i < n_dl; i++) {
+    flexran_agent_read_slice_dl_config(mod_id, i, slice_config[mod_id]->dl[i]);
+    flexran_agent_read_slice_dl_config(mod_id, i, sc_update[mod_id]->dl[i]);
+  }
+  for (i = 0; i < m_ul; i++) {
+    flexran_agent_read_slice_ul_config(mod_id, i, slice_config[mod_id]->ul[i]);
+    flexran_agent_read_slice_ul_config(mod_id, i, sc_update[mod_id]->ul[i]);
+  }
+}
+
+void flexran_check_and_remove_slices(mid_t mod_id)
+{
+  int i;
+  Protocol__FlexDlSlice **dl = sc_update[mod_id]->dl;
+  size_t n_dl = sc_update[mod_id]->n_dl;
+  for (i = 0; i < n_dl; i++) {
+    /* remove slices whose percentage is zero */
+    if (dl[i]->percentage > 0) continue;
+    if (flexran_remove_dl_slice(mod_id, i) < 1) {
+      LOG_W(FLEXRAN_AGENT, "[%d] can not remove slice index %d ID %d\n",
+            mod_id, i, dl[i]->id);
+      continue;
+    }
+    LOG_I(FLEXRAN_AGENT, "[%d] removed slice index %d ID %d\n",
+          mod_id, i, dl[i]->id);
+    /* don't update slice_config, it will be read in below */
+    /* we need to memcpy the higher slice to the position we just deleted */
+    memcpy(dl[i], dl[n_dl-1], sizeof(*dl[n_dl-1]));
+    --sc_update[mod_id]->n_dl;
+  }
+  Protocol__FlexUlSlice **ul = sc_update[mod_id]->ul;
+  size_t n_ul = sc_update[mod_id]->n_ul;
+  for (i = 0; i < n_ul; i++) {
+    if (ul[i]->percentage > 0) continue;
+    if (flexran_remove_ul_slice(mod_id, i) < 1) {
+      LOG_W(FLEXRAN_AGENT, "[%d] can not remove slice index %d ID %d\n",
+            mod_id, i, ul[i]->id);
+      continue;
+    }
+    LOG_I(FLEXRAN_AGENT, "[%d] removed slice index %d ID %d\n",
+          mod_id, i, ul[i]->id);
+    /* see DL remarks */
+    memcpy(ul[i], ul[n_ul-1], sizeof(*ul[n_ul-1]));
+    --sc_update[mod_id]->n_ul;
+  }
+}
+
+void flexran_agent_slice_update(mid_t mod_id)
+{
+  int i;
+  int changes = 0;
+
+  if (perform_slice_config_update_count <= 0) return;
+  perform_slice_config_update_count--;
+
+  if (!slice_config[mod_id]) {
+    /* if the configuration does not exist for agent, create from eNB structure
+     * and exit */
+    flexran_create_config_structures(mod_id);
+    return;
+  }
+
+  /********* read existing config *********/
+  /* simply update slice_config all the time and write new config
+   * (apply_new_slice_dl_config() only updates if changes are necessary) */
+  slice_config[mod_id]->n_dl = flexran_get_num_dl_slices(mod_id);
+  slice_config[mod_id]->n_ul = flexran_get_num_ul_slices(mod_id);
+  for (i = 0; i < slice_config[mod_id]->n_dl; i++) {
+    flexran_agent_read_slice_dl_config(mod_id, i, slice_config[mod_id]->dl[i]);
+  }
+  for (i = 0; i < slice_config[mod_id]->n_ul; i++) {
+    flexran_agent_read_slice_ul_config(mod_id, i, slice_config[mod_id]->ul[i]);
+  }
 
+  /* in case we tried to add a slice and it failed (e.g. due to high sum
+   * percentage being too high), revert to the correct number of slices.
+   * Also, do not write if we try the last time */
+  if (perform_slice_config_update_count == 1) {
+    if (slice_config[mod_id]->n_dl != sc_update[mod_id]->n_dl) {
+      sc_update[mod_id]->n_dl = slice_config[mod_id]->n_dl;
+      LOG_W(FLEXRAN_AGENT, "[%d] reverting to original number of %ld DL slices\n",
+            mod_id, sc_update[mod_id]->n_dl);
+    }
+    if (slice_config[mod_id]->n_ul != sc_update[mod_id]->n_ul) {
+      sc_update[mod_id]->n_ul = slice_config[mod_id]->n_ul;
+      LOG_W(FLEXRAN_AGENT, "[%d] reverting to original number of %ld UL slices\n",
+            mod_id, sc_update[mod_id]->n_ul);
+    }
+    return;
+  }
 
+  /********* write new config *********/
+  /* check for removal (sc_update[X]->dl[Y].percentage == 0)
+   * and update sc_update & slice_config accordingly */
+  flexran_check_and_remove_slices(mod_id);
 
+  /* create new DL and UL slices if necessary */
+  for (i = slice_config[mod_id]->n_dl; i < sc_update[mod_id]->n_dl; i++) {
+    flexran_create_dl_slice(mod_id, sc_update[mod_id]->dl[i]->id, 0);
+    slice_config[mod_id]->n_dl = flexran_get_num_dl_slices(mod_id);
+    flexran_agent_read_slice_dl_config(mod_id, i, slice_config[mod_id]->dl[i]);
+  }
+  for (i = slice_config[mod_id]->n_ul; i < sc_update[mod_id]->n_ul; i++) {
+    flexran_create_ul_slice(mod_id, sc_update[mod_id]->ul[i]->id, 0);
+    slice_config[mod_id]->n_ul = flexran_get_num_ul_slices(mod_id);
+    flexran_agent_read_slice_ul_config(mod_id, i, slice_config[mod_id]->ul[i]);
+  }
+  for (i = 0; i < slice_config[mod_id]->n_dl; i++) {
+    changes += apply_new_slice_dl_config(mod_id,
+                                         slice_config[mod_id]->dl[i],
+                                         sc_update[mod_id]->dl[i]);
+  }
+  for (i = 0; i < slice_config[mod_id]->n_ul; i++) {
+    changes += apply_new_slice_ul_config(mod_id,
+                                         slice_config[mod_id]->ul[i],
+                                         sc_update[mod_id]->ul[i]);
+  }
+  if (n_ue_slice_assoc_updates > 0) {
+    changes += apply_ue_slice_assoc_update(mod_id);
+  }
+  if (changes > 0)
+    LOG_I(FLEXRAN_AGENT, "[%d] slice configuration: applied %d changes\n", mod_id, changes);
 
+}
 
+Protocol__FlexSliceConfig *flexran_agent_get_slice_config(mid_t mod_id)
+{
+  return slice_config[mod_id];
+}
diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h
index 03e7def95e04610e57503917c38dbafe9e6fb3d4..0d686a53eed6fa5c13fc39129e0aff4508b86056 100644
--- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h
+++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h
@@ -87,4 +87,14 @@ int flexran_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface);
 /*Unregister technology specific callbacks*/
 int flexran_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface*xface);
 
+/***************************************
+ * FlexRAN agent - slice configuration *
+ ***************************************/
+
+/* Inform controller about possibility to update slice configuration */
+void flexran_agent_slice_update(mid_t mod_id);
+
+/* return a pointer to the current config */
+Protocol__FlexSliceConfig *flexran_agent_get_slice_config(mid_t mod_id);
+
 #endif
diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c
index 2acee0686f62165881d256e96eb09500274d0a30..435e8da064d2180c99ea8119c9cfc3681f5e3353 100644
--- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c
+++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c
@@ -32,6 +32,13 @@
 #include "flexran_agent_common_internal.h"
 #include "flexran_agent_mac_internal.h"
 
+/* from flexran_agent_mac.c */
+extern Protocol__FlexSliceConfig *slice_config[NUM_MAX_ENB];
+extern Protocol__FlexSliceConfig *sc_update[NUM_MAX_ENB];
+extern int perform_slice_config_update_count;
+extern Protocol__FlexUeConfig *ue_slice_assoc_update[NUM_MAX_UE];
+extern int n_ue_slice_assoc_updates;
+
 Protocol__FlexranMessage * flexran_agent_generate_diff_mac_stats_report(Protocol__FlexranMessage *new_message,
 									Protocol__FlexranMessage *old_message) {
 
@@ -899,3 +906,519 @@ int load_dl_scheduler_function(mid_t mod_id, const char *function_name) {
   return -1;
   
 }
+
+Protocol__FlexSliceConfig *flexran_agent_create_slice_config(int n_dl, int m_ul)
+{
+  int i;
+  Protocol__FlexSliceConfig *fsc = malloc(sizeof(Protocol__FlexSliceConfig));
+  if (!fsc) return NULL;
+  protocol__flex_slice_config__init(fsc);
+
+  /* say there are n_dl slices but reserve memory for up to MAX_NUM_SLICES so
+   * we don't need to reserve again later */
+  fsc->n_dl = n_dl;
+  fsc->dl = calloc(MAX_NUM_SLICES, sizeof(Protocol__FlexDlSlice *));
+  if (!fsc->dl) fsc->n_dl = 0;
+  for (i = 0; i < MAX_NUM_SLICES; i++) {
+    fsc->dl[i] = malloc(sizeof(Protocol__FlexDlSlice));
+    if (!fsc->dl[i]) continue;
+    protocol__flex_dl_slice__init(fsc->dl[i]);
+  }
+
+  /* as above */
+  fsc->n_ul = m_ul;
+  fsc->ul = calloc(MAX_NUM_SLICES, sizeof(Protocol__FlexUlSlice *));
+  if (!fsc->ul) fsc->n_ul = 0;
+  for (i = 0; i < MAX_NUM_SLICES; i++) {
+    fsc->ul[i] = malloc(sizeof(Protocol__FlexUlSlice));
+    if (!fsc->ul[i]) continue;
+    protocol__flex_ul_slice__init(fsc->ul[i]);
+  }
+  return fsc;
+}
+
+void flexran_agent_read_slice_dl_config(mid_t mod_id, int slice_idx, Protocol__FlexDlSlice *dl_slice)
+{
+  dl_slice->id = flexran_get_dl_slice_id(mod_id, slice_idx);
+  dl_slice->has_id = 1;
+  /* read label from corresponding sc_update entry or give default */
+  dl_slice->label = PROTOCOL__FLEX_SLICE_LABEL__xMBB;
+  dl_slice->has_label = 1;
+  for (int i = 0; i < sc_update[mod_id]->n_dl; i++) {
+    if (sc_update[mod_id]->dl[i]->id == dl_slice->id
+        && sc_update[mod_id]->dl[i]->has_label) {
+      dl_slice->label = sc_update[mod_id]->dl[i]->label;
+      break;
+    }
+  }
+  dl_slice->percentage = flexran_get_dl_slice_percentage(mod_id, slice_idx);
+  dl_slice->has_percentage = 1;
+  dl_slice->isolation = flexran_get_dl_slice_isolation(mod_id, slice_idx);
+  dl_slice->has_isolation = 1;
+  dl_slice->priority = flexran_get_dl_slice_priority(mod_id, slice_idx);
+  dl_slice->has_priority = 1;
+  dl_slice->position_low = flexran_get_dl_slice_position_low(mod_id, slice_idx);
+  dl_slice->has_position_low = 1;
+  dl_slice->position_high = flexran_get_dl_slice_position_high(mod_id, slice_idx);
+  dl_slice->has_position_high = 1;
+  dl_slice->maxmcs = flexran_get_dl_slice_maxmcs(mod_id, slice_idx);
+  dl_slice->has_maxmcs = 1;
+  dl_slice->n_sorting = flexran_get_dl_slice_sorting(mod_id, slice_idx, &dl_slice->sorting);
+  if (dl_slice->n_sorting < 1) dl_slice->sorting = NULL;
+  dl_slice->accounting = flexran_get_dl_slice_accounting_policy(mod_id, slice_idx);
+  dl_slice->has_accounting = 1;
+  dl_slice->scheduler_name = flexran_get_dl_slice_scheduler_name(mod_id, slice_idx);
+}
+
+void flexran_agent_read_slice_ul_config(mid_t mod_id, int slice_idx, Protocol__FlexUlSlice *ul_slice)
+{
+  ul_slice->id = flexran_get_ul_slice_id(mod_id, slice_idx);
+  ul_slice->has_id = 1;
+  /* read label from corresponding sc_update entry or give default */
+  ul_slice->label = PROTOCOL__FLEX_SLICE_LABEL__xMBB;
+  ul_slice->has_label = 1;
+  for (int i = 0; i < sc_update[mod_id]->n_ul; i++) {
+    if (sc_update[mod_id]->ul[i]->id == ul_slice->id
+        && sc_update[mod_id]->ul[i]->has_label) {
+      ul_slice->label = sc_update[mod_id]->ul[i]->label;
+      break;
+    }
+  }
+  ul_slice->percentage = flexran_get_ul_slice_percentage(mod_id, slice_idx);
+  ul_slice->has_percentage = 1;
+  /*ul_slice->isolation = flexran_get_ul_slice_isolation(mod_id, slice_idx);*/
+  ul_slice->has_isolation = 0;
+  /*ul_slice->priority = flexran_get_ul_slice_priority(mod_id, slice_idx);*/
+  ul_slice->has_priority = 0;
+  ul_slice->first_rb = flexran_get_ul_slice_first_rb(mod_id, slice_idx);
+  ul_slice->has_first_rb = 1;
+  /*ul_slice-> = flexran_get_ul_slice_length_rb(mod_id, slice_idx);
+  ul_slice->has_length_rb = 0;*/
+  ul_slice->maxmcs = flexran_get_ul_slice_maxmcs(mod_id, slice_idx);
+  ul_slice->has_maxmcs = 1;
+  ul_slice->n_sorting = 0;
+  /*if (ul_slice->sorting) {
+    free(ul_slice->sorting);
+    ul_slice->sorting = NULL;
+  }
+  ul_slice->n_sorting = flexran_get_ul_slice_sorting(mod_id, slice_idx, &ul_slice->sorting);
+  if (ul_slice->n_sorting < 1) ul_slice->sorting = NULL;*/
+  /*ul_slice->accounting = flexran_get_ul_slice_accounting_policy(mod_id, slice_idx);*/
+  ul_slice->has_accounting = 0;
+  ul_slice->scheduler_name = flexran_get_ul_slice_scheduler_name(mod_id, slice_idx);
+}
+
+void overwrite_slice_config_dl(Protocol__FlexDlSlice *exist, Protocol__FlexDlSlice *update)
+{
+  if (update->has_label && update->label != exist->label) {
+    LOG_I(FLEXRAN_AGENT, "[DL slice %d] update label: %d -> %d\n",
+          update->id, exist->label, update->label);
+    exist->label = update->label;
+  }
+  if (update->has_percentage && update->percentage != exist->percentage) {
+    LOG_I(FLEXRAN_AGENT, "[DL slice %d] update percentage: %d -> %d\n",
+          update->id, exist->percentage, update->percentage);
+    exist->percentage = update->percentage;
+  }
+  if (update->has_isolation && update->isolation != exist->isolation) {
+    LOG_I(FLEXRAN_AGENT, "[DL slice %d] update isolation: %d -> %d\n",
+          update->id, exist->isolation, update->isolation);
+    exist->isolation = update->isolation;
+  }
+  if (update->has_priority && update->priority != exist->priority) {
+    LOG_I(FLEXRAN_AGENT, "[DL slice %d] update priority: %d -> %d\n",
+          update->id, exist->priority, update->priority);
+    exist->priority = update->priority;
+  }
+  if (update->has_position_low && update->position_low != exist->position_low) {
+    LOG_I(FLEXRAN_AGENT, "[DL slice %d] update position_low: %d -> %d\n",
+          update->id, exist->position_low, update->position_low);
+    exist->position_low = update->position_low;
+  }
+  if (update->has_position_high && update->position_high != exist->position_high) {
+    LOG_I(FLEXRAN_AGENT, "[DL slice %d] update position_high: %d -> %d\n",
+          update->id, exist->position_high, update->position_high);
+    exist->position_high = update->position_high;
+  }
+  if (update->has_maxmcs && update->maxmcs != exist->maxmcs) {
+    LOG_I(FLEXRAN_AGENT, "[DL slice %d] update maxmcs: %d -> %d\n",
+          update->id, exist->maxmcs, update->maxmcs);
+    exist->maxmcs = update->maxmcs;
+  }
+  int sorting_update = 0;
+  int n = min(exist->n_sorting, update->n_sorting);
+  /* check whether something has changed. If update->n_sorting is 0,
+   * sorting_update will remain false, so no update will be done */
+  int i = 0;
+  while(i < n && !sorting_update) {
+    sorting_update = sorting_update || (update->sorting[i] != exist->sorting[i]);
+    i++;
+  }
+  if (sorting_update) {
+    LOG_I(FLEXRAN_AGENT, "[DL slice %d] update sorting array\n", update->id);
+    if (exist->n_sorting != update->n_sorting)
+      LOG_W(FLEXRAN_AGENT, "[slice %d] only writing %d elements\n",
+          update->id, n);
+    for (int i = 0; i < n; i++)
+      exist->sorting[i] = update->sorting[i];
+  }
+  if (update->has_accounting && update->accounting != exist->accounting) {
+    LOG_I(FLEXRAN_AGENT, "[DL slice %d] update accounting: %d -> %d\n",
+          update->id, exist->accounting, update->accounting);
+    exist->accounting = update->accounting;
+  }
+  if (update->scheduler_name
+      && strcmp(update->scheduler_name, exist->scheduler_name) != 0) {
+    LOG_W(FLEXRAN_AGENT, "[DL slice %d] ignoring new scheduler name \"%s\"!\n",
+        update->id, update->scheduler_name);
+  }
+}
+
+void overwrite_slice_config_ul(Protocol__FlexUlSlice *exist, Protocol__FlexUlSlice *update)
+{
+  if (update->has_label && update->label != exist->label) {
+    LOG_I(FLEXRAN_AGENT, "[UL slice %d] update label: %d -> %d\n",
+          update->id, exist->label, update->label);
+    exist->label = update->label;
+  }
+  if (update->has_percentage && update->percentage != exist->percentage) {
+    LOG_I(FLEXRAN_AGENT, "[UL slice %d] update percentage: %d -> %d\n",
+          update->id, exist->percentage, update->percentage);
+    exist->percentage = update->percentage;
+  }
+  if (update->has_isolation && update->isolation != exist->isolation) {
+    LOG_I(FLEXRAN_AGENT, "[UL slice %d] update isolation: %d -> %d\n",
+          update->id, exist->isolation, update->isolation);
+    exist->isolation = update->isolation;
+  }
+  if (update->has_priority && update->priority != exist->priority) {
+    LOG_I(FLEXRAN_AGENT, "[UL slice %d] update priority: %d -> %d\n",
+          update->id, exist->priority, update->priority);
+    exist->priority = update->priority;
+  }
+  if (update->has_first_rb && update->first_rb != exist->first_rb) {
+    LOG_I(FLEXRAN_AGENT, "[UL slice %d] update first_rb: %d -> %d\n",
+	  update->id, exist->first_rb, update->first_rb);
+    exist->first_rb = update ->first_rb;
+  }
+  /*if (update->has_length_rb && update->lenght_rb != exist->lenght_rb) {
+    LOG_I(FLEXRAN_AGENT, "[UL slice %d] update lenght_rb: %d -> %d\n",
+          update->id, exist->lenght_rb, update->lenght_rb);
+    exist->lenght_rb = update->lenght_rb;
+  }*/
+  if (update->has_maxmcs && update->maxmcs != exist->maxmcs) {
+    LOG_I(FLEXRAN_AGENT, "[UL slice %d] update maxmcs: %d -> %d\n",
+          update->id, exist->maxmcs, update->maxmcs);
+    exist->maxmcs = update->maxmcs;
+  }
+  int sorting_update = 0;
+  int n = min(exist->n_sorting, update->n_sorting);
+  /* check whether something has changed. If update-> n_sorting is 0,
+   * sorting_update will remain false, so no update will be done */
+  int i = 0;
+  while (i < n && !sorting_update) {
+    sorting_update = sorting_update || (update->sorting[i] != exist->sorting[i]);
+    i++;
+  }
+  if (sorting_update) {
+    LOG_I(FLEXRAN_AGENT, "[UL slice %d] update sorting array\n", update->id);
+    if (exist->n_sorting != update->n_sorting)
+      LOG_W(FLEXRAN_AGENT, "[UL slice %d] only writing %d elements\n",
+          update->id, n);
+    for (i = 0; i < n; i++)
+      exist->sorting[i] = update->sorting[i];
+  }
+  if (update->has_accounting && update->accounting != exist->accounting) {
+    LOG_I(FLEXRAN_AGENT, "[UL slice %d] update accounting: %d -> %d\n",
+          update->id, exist->accounting, update->accounting);
+    exist->accounting = update->accounting;
+  }
+  if (update->scheduler_name
+      && strcmp(update->scheduler_name, exist->scheduler_name) != 0) {
+    LOG_W(FLEXRAN_AGENT, "[UL slice %d] ignoring new scheduler name \"%s\"!\n",
+        update->id, update->scheduler_name);
+  }
+}
+
+void prepare_update_slice_config_dl(mid_t mod_id, Protocol__FlexDlSlice *dls)
+{
+  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;
+  }
+
+  Protocol__FlexDlSlice *to = NULL;
+  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;
+    }
+  }
+
+  /* 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);
+}
+
+void prepare_update_slice_config_ul(mid_t mod_id, Protocol__FlexUlSlice *uls)
+{
+  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;
+  }
+
+  Protocol__FlexUlSlice *to = NULL;
+  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;
+    }
+  }
+
+  /* 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);
+}
+
+void prepare_update_slice_config(mid_t mod_id, Protocol__FlexSliceConfig *slice)
+{
+  if (!sc_update[mod_id]) {
+    LOG_E(FLEXRAN_AGENT, "Can not update slice policy (no existing slice profile)\n");
+    return;
+  }
+  if (slice->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]);
+
+  if (slice->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]);
+
+  /* perform the slice configuration reads a couple of times. If there are
+   * inconsistencies (i.e. the MAC refuses a configuration), we will have a
+   * couple of warnings because the current configuration and the one in
+   * sc_update will be diverged */
+  perform_slice_config_update_count = 3;
+}
+
+int apply_new_slice_dl_config(mid_t mod_id, Protocol__FlexDlSlice *oldc, Protocol__FlexDlSlice *newc)
+{
+  /* not setting the old configuration is intentional, as it will be picked up
+   * later when reading the configuration. There is thus a direct feedback
+   * whether it has been set. */
+  int changes = 0;
+  int n;
+  int slice_idx = flexran_find_dl_slice(mod_id, newc->id);
+  if (slice_idx < 0) {
+    LOG_W(FLEXRAN_AGENT, "cannot find index for slice ID %d\n", newc->id);
+    return 0;
+  }
+  if (oldc->percentage != newc->percentage) {
+    flexran_set_dl_slice_percentage(mod_id, slice_idx, newc->percentage);
+    changes++;
+  }
+  if (oldc->isolation != newc->isolation) {
+    flexran_set_dl_slice_isolation(mod_id, slice_idx, newc->isolation);
+    changes++;
+  }
+  if (oldc->priority != newc->priority) {
+    flexran_set_dl_slice_priority(mod_id, slice_idx, newc->priority);
+    changes++;
+  }
+  if (oldc->position_low != newc->position_low) {
+    flexran_set_dl_slice_position_low(mod_id, slice_idx, newc->position_low);
+    changes++;
+  }
+  if (oldc->position_high != newc->position_high) {
+    flexran_set_dl_slice_position_high(mod_id, slice_idx, newc->position_high);
+    changes++;
+  }
+  if (oldc->maxmcs != newc->maxmcs) {
+    flexran_set_dl_slice_maxmcs(mod_id, slice_idx, newc->maxmcs);
+    changes++;
+  }
+  n = min(oldc->n_sorting, newc->n_sorting);
+  for (int i = 0; i < n; i++) {
+    if (oldc->sorting[i] != newc->sorting[i]) {
+      flexran_set_dl_slice_sorting(mod_id, slice_idx, newc->sorting, n);
+      changes++;
+      break;
+    }
+  }
+  if (oldc->accounting != newc->accounting) {
+    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;
+}
+
+int apply_new_slice_ul_config(mid_t mod_id, Protocol__FlexUlSlice *oldc, Protocol__FlexUlSlice *newc)
+{
+  /* not setting the old configuration is intentional, as it will be picked up
+   * later when reading the configuration. There is thus a direct feedback
+   * whether it has been set. */
+  int changes = 0;
+  int n;
+  int slice_idx = flexran_find_ul_slice(mod_id, newc->id);
+  if (slice_idx < 0) {
+    LOG_W(FLEXRAN_AGENT, "cannot find index for slice ID %d\n", newc->id);
+    return 0;
+  }
+  if (oldc->percentage != newc->percentage) {
+    flexran_set_ul_slice_percentage(mod_id, slice_idx, newc->percentage);
+    changes++;
+  }
+  if (oldc->isolation != newc->isolation) {
+    /*flexran_set_ul_slice_isolation(mod_id, slice_idx, newc->isolation);
+     *changes++;*/
+    LOG_W(FLEXRAN_AGENT, "[%d][UL slice %d] setting isolation is not supported\n",
+          mod_id, slice_idx);
+  }
+  if (oldc->priority != newc->priority) {
+    /*flexran_set_ul_slice_priority(mod_id, slice_idx, newc->priority);
+     *changes++;*/
+    LOG_W(FLEXRAN_AGENT, "[%d][UL slice %d] setting the priority is not supported\n",
+          mod_id, slice_idx);
+  }
+  if (oldc->first_rb != newc->first_rb) {
+    flexran_set_ul_slice_first_rb(mod_id, slice_idx, newc->first_rb);
+    changes++;
+  }
+  /*if (oldc->length_rb != newc->length_rb) {
+    flexran_set_ul_slice_length_rb(mod_id, slice_idx, newc->length_rb);
+    changes++;
+    LOG_W(FLEXRAN_AGENT, "[%d][UL slice %d] setting length_rb is not supported\n",
+          mod_id, slice_idx);
+  }*/
+  if (oldc->maxmcs != newc->maxmcs) {
+    flexran_set_ul_slice_maxmcs(mod_id, slice_idx, newc->maxmcs);
+    changes++;
+  }
+  n = min(oldc->n_sorting, newc->n_sorting);
+  for (int i = 0; i < n; i++) {
+    if (oldc->sorting[i] != newc->sorting[i]) {
+      /*flexran_set_ul_slice_sorting(mod_id, slice_idx, newc->sorting, n);
+      changes++;*/
+      LOG_W(FLEXRAN_AGENT, "[%d][UL slice %d] setting the sorting is not supported\n",
+          mod_id, slice_idx);
+      break;
+    }
+  }
+  if (oldc->accounting != newc->accounting) {
+    /*flexran_set_ul_slice_accounting_policy(mod_id, slice_idx, newc->accounting);
+     *changes++;*/
+    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;
+}
+
+void prepare_ue_slice_assoc_update(mid_t mod_id, Protocol__FlexUeConfig *ue_config)
+{
+  if (n_ue_slice_assoc_updates == NUM_MAX_UE) {
+    LOG_E(FLEXRAN_AGENT,
+          "[%d] can not handle flex_ue_config message, buffer is full; try again later\n",
+          mod_id);
+    return;
+  }
+  if (!ue_config->has_rnti) {
+    LOG_E(FLEXRAN_AGENT,
+          "[%d] cannot update UE to slice association, no RNTI in flex_ue_config message\n",
+          mod_id);
+    return;
+  }
+  if (ue_config->has_dl_slice_id)
+    LOG_I(FLEXRAN_AGENT, "[%d] associating UE RNTI %#x to DL slice ID %d\n",
+          mod_id, ue_config->rnti, ue_config->dl_slice_id);
+  if (ue_config->has_ul_slice_id)
+    LOG_I(FLEXRAN_AGENT, "[%d] associating UE RNTI %#x to UL slice ID %d\n",
+          mod_id, ue_config->rnti, ue_config->ul_slice_id);
+  ue_slice_assoc_update[n_ue_slice_assoc_updates++] = ue_config;
+  perform_slice_config_update_count = 2;
+}
+
+int apply_ue_slice_assoc_update(mid_t mod_id)
+{
+  int i;
+  int changes = 0;
+  /* TODO should lock structure */
+  for (i = 0; i < n_ue_slice_assoc_updates; i++) {
+    int ue_id = find_UE_id(mod_id, ue_slice_assoc_update[i]->rnti);
+    if (ue_slice_assoc_update[i]->has_dl_slice_id) {
+      int slice_idx = flexran_find_dl_slice(mod_id, ue_slice_assoc_update[i]->dl_slice_id);
+      if (flexran_dl_slice_exists(mod_id, slice_idx)) {
+        flexran_set_ue_dl_slice_idx(mod_id, ue_id, slice_idx);
+        changes++;
+      } else {
+        LOG_W(FLEXRAN_AGENT, "[%d] DL slice %d does not exist, refusing change\n",
+              mod_id, ue_slice_assoc_update[i]->dl_slice_id);
+      }
+    }
+    if (ue_slice_assoc_update[i]->has_ul_slice_id) {
+      int slice_idx = flexran_find_ul_slice(mod_id, ue_slice_assoc_update[i]->ul_slice_id);
+      if (flexran_ul_slice_exists(mod_id, slice_idx)) {
+        flexran_set_ue_ul_slice_idx(mod_id, ue_id, slice_idx);
+        changes++;
+      } else {
+        LOG_W(FLEXRAN_AGENT, "[%d] UL slice %d does not exist, refusing change\n",
+              mod_id, ue_slice_assoc_update[i]->ul_slice_id);
+      }
+    }
+  }
+  n_ue_slice_assoc_updates = 0;
+  return changes;
+}
diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h
index f69e2cde4098ad5d035a522c9815632bffb37312..2f8f3f8258fb9c48d072be47f999d8a520daf8ab 100644
--- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h
+++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h
@@ -107,4 +107,37 @@ int parse_ul_scheduler_parameters(mid_t mod_id, yaml_parser_t *parser);
 
 int load_dl_scheduler_function(mid_t mod_id, const char *function_name);
 
+/*** Functions for handling a slice config ***/
+
+/* allocate memory for a Protocol__FlexSliceConfig structure with n_dl DL slice
+ * configs and m_ul UL slice configs */
+Protocol__FlexSliceConfig *flexran_agent_create_slice_config(int n_dl, int m_ul);
+
+/* read the DL slice config via the RAN into a given Protocol__FlexDlSlice
+ * struct */
+void flexran_agent_read_slice_dl_config(mid_t mod_id, int slice_idx, Protocol__FlexDlSlice *dl_slice);
+
+/* read the UL slice config via the RAN into a given Protocol__FlexUlSlice
+ * struct */
+void flexran_agent_read_slice_ul_config(mid_t mod_id, int slice_idx, Protocol__FlexUlSlice *ul_slice);
+
+/* reads content of slice over the sc_update structure, so that it can be
+ * applied later by performing a diff between slice_config and sc_update */
+void prepare_update_slice_config(mid_t mod_id, Protocol__FlexSliceConfig *slice);
+
+/* apply new configuration of slice in DL if there are changes between the
+ * parameters. Returns the number of changed parameters. */
+int apply_new_slice_dl_config(mid_t mod_id, Protocol__FlexDlSlice *oldc, Protocol__FlexDlSlice *newc);
+
+/* apply new configuration of slice in UL if there are changes between the
+ * parameters. Returns the number of changed parameters. */
+int apply_new_slice_ul_config(mid_t mod_id, Protocol__FlexUlSlice *oldc, Protocol__FlexUlSlice *newc);
+
+/* inserts a new ue_config into the structure keeping ue to slice association
+ * updates and marks so it can be applied */
+void prepare_ue_slice_assoc_update(mid_t mod_id, Protocol__FlexUeConfig *ue_config);
+
+/* apply a new association between a UE and a slice (both DL and UL) */
+int apply_ue_slice_assoc_update(mid_t mod_id);
+
 #endif /*FLEXRAN_AGENT_MAC_INTERNAL_H_*/
diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c
index a2988f26d8c27b34265fe94635d625e2858935c0..4dbf3cf36f57d2c700463d071b02d805bb61a704 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler.c
@@ -703,6 +703,10 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP,
       allocate_CCEs(module_idP, CC_id, frameP, subframeP, 2);
   }
 
+  if (mac_agent_registered[module_idP] && subframeP == 9) {
+    flexran_agent_slice_update(module_idP);
+  }
+
   stop_meas(&RC.mac[module_idP]->eNB_scheduler);
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME