From a47f3654f8c347838b46de3e01d5a4dad9d46af5 Mon Sep 17 00:00:00 2001
From: Xenofon Foukas <x.foukas@sms.ed.ac.uk>
Date: Tue, 12 Apr 2016 13:00:20 +0100
Subject: [PATCH] Added basic support for policy reconfiguration using yaml
 parser

---
 openair2/ENB_APP/enb_agent_common.c           |  37 +-
 openair2/ENB_APP/enb_agent_common.h           |   3 +
 openair2/ENB_APP/enb_agent_common_internal.c  | 400 ++++++++++++++++++
 openair2/ENB_APP/enb_agent_common_internal.h  |  64 +++
 openair2/ENB_APP/enb_agent_handler.c          |   3 +-
 openair2/ENB_APP/enb_agent_mac.c              |   4 +
 openair2/ENB_APP/enb_agent_mac_defs.h         |   2 +
 openair2/ENB_APP/enb_agent_mac_internal.c     | 235 ++++++++++
 openair2/ENB_APP/enb_agent_mac_internal.h     |  15 +-
 .../MAC/eNB_agent_scheduler_dlsch_ue_remote.c |  18 +
 10 files changed, 758 insertions(+), 23 deletions(-)
 create mode 100644 openair2/ENB_APP/enb_agent_common_internal.c
 create mode 100644 openair2/ENB_APP/enb_agent_common_internal.h

diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c
index f06599e258..e21c180cec 100644
--- a/openair2/ENB_APP/enb_agent_common.c
+++ b/openair2/ENB_APP/enb_agent_common.c
@@ -35,10 +35,10 @@
  */
 
 #include<stdio.h>
-#include <dlfcn.h>
 #include <time.h>
 
 #include "enb_agent_common.h"
+#include "enb_agent_common_internal.h"
 #include "enb_agent_extern.h"
 #include "PHY/extern.h"
 #include "log.h"
@@ -403,7 +403,6 @@ int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__Pro
 
   uint32_t delegation_type = control_delegation_msg->delegation_type;
 
-  void *lib;
   int i;
 
   struct timespec vartime = timer_start();
@@ -411,7 +410,7 @@ int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__Pro
   //Write the payload lib into a file in the cache and load the lib
   char lib_name[120];
   char target[512];
-  snprintf(lib_name, sizeof(lib_name), "/delegation_lib_%d.so", control_delegation_msg->header->xid);
+  snprintf(lib_name, sizeof(lib_name), "/%s.so", control_delegation_msg->name);
   strcpy(target, local_cache);
   strcat(target, lib_name);
 
@@ -419,25 +418,7 @@ int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__Pro
   f = fopen(target, "wb");
   fwrite(control_delegation_msg->payload.data, control_delegation_msg->payload.len, 1, f);
   fclose(f);
-  lib = dlopen(target, RTLD_NOW);
-  if (lib == NULL) {
-    goto error;
-  }
 
-  i = 0;
-  //Check functions that need to be delegated
-  
-  //DL UE scheduler delegation
-  if (delegation_type & PROTOCOL__PRP_CONTROL_DELEGATION_TYPE__PRCDT_MAC_DL_UE_SCHEDULER) {  
-    void *loaded_scheduler = dlsym(lib, control_delegation_msg->name[i]);
-    i++;
-    if (loaded_scheduler) {
-      if (mac_agent_registered[mod_id]) {
-	agent_mac_xface[mod_id]->enb_agent_schedule_ue_spec = loaded_scheduler;
-	LOG_D(ENB_APP,"Delegated control for DL UE scheduler successfully\n");
-      }
-    }
-  }
   long time_elapsed_nanos = timer_end(vartime);
   *msg = NULL;
   return 0;
@@ -450,6 +431,20 @@ int enb_agent_destroy_control_delegation(Protocol__ProgranMessage *msg) {
   /*TODO: Dealocate memory for a dynamically allocated control delegation message*/
 }
 
+int enb_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) {
+  Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params;
+  Protocol__PrpAgentReconfiguration *agent_reconfiguration_msg = input->agent_reconfiguration_msg;
+
+  apply_reconfiguration_policy(mod_id, agent_reconfiguration_msg->policy, strlen(agent_reconfiguration_msg->policy));
+
+  *msg = NULL;
+  return 0;
+}
+
+int enb_agent_destroy_agent_reconfiguration(Protocol__ProgranMessage *msg) {
+  /*TODO: Dealocate memory for a dynamically allocated agent reconfiguration message*/
+}
+
 /*
  * get generic info from RAN
  */
diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h
index 9b483ce4a0..18c9129989 100644
--- a/openair2/ENB_APP/enb_agent_common.h
+++ b/openair2/ENB_APP/enb_agent_common.h
@@ -114,6 +114,9 @@ int enb_agent_destroy_ue_state_change(Protocol__ProgranMessage *msg);
 int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg);
 int enb_agent_destroy_control_delegation(Protocol__ProgranMessage *msg);
 
+int enb_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg);
+int enb_agent_destroy_agent_reconfiguration(Protocol__ProgranMessage *msg);
+
 Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, 
 						    uint8_t *data, 
 						    uint32_t size);
diff --git a/openair2/ENB_APP/enb_agent_common_internal.c b/openair2/ENB_APP/enb_agent_common_internal.c
new file mode 100644
index 0000000000..ca61a96609
--- /dev/null
+++ b/openair2/ENB_APP/enb_agent_common_internal.c
@@ -0,0 +1,400 @@
+/*******************************************************************************
+    OpenAirInterface
+    Copyright(c) 1999 - 2014 Eurecom
+
+    OpenAirInterface is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+
+    OpenAirInterface is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenAirInterface.The full GNU General Public License is
+   included in this distribution in the file called "COPYING". If not,
+   see <http://www.gnu.org/licenses/>.
+
+  Contact Information
+  OpenAirInterface Admin: openair_admin@eurecom.fr
+  OpenAirInterface Tech : openair_tech@eurecom.fr
+  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
+
+  Address      : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
+
+ *******************************************************************************/
+
+/*! \file enb_agent_common_internal.c
+ * \brief internal functions for common message primitves and utilities 
+ * \author Xenofon Foukas
+ * \date 2016
+ * \version 0.1
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "enb_agent_common_internal.h"
+#include "enb_agent_mac_internal.h"
+
+int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy_length) {
+
+  yaml_parser_t parser;
+  yaml_event_t event;
+
+  int done = 0;
+  int mapping_started = 0;
+
+  LOG_I(ENB_APP, "Time to apply a new policy \n");
+
+  yaml_parser_initialize(&parser);
+
+  yaml_parser_set_input_string(&parser, policy, strlen(policy));
+
+  while (!done) {
+    if (!yaml_parser_parse(&parser, &event))
+      goto error;
+ 
+    switch (event.type) {
+    case YAML_STREAM_START_EVENT:
+    case YAML_STREAM_END_EVENT:
+    case YAML_DOCUMENT_START_EVENT:
+    case YAML_DOCUMENT_END_EVENT:
+      break;
+    case YAML_MAPPING_START_EVENT:
+      mapping_started = 1;
+      break;
+    case YAML_MAPPING_END_EVENT:
+      mapping_started = 0;
+      break;
+    case YAML_SCALAR_EVENT:
+      // Check the system name and call the proper handler
+      if (strcmp(event.data.scalar.value, "mac") == 0) {
+	LOG_D(ENB_APP, "This is intended for the mac system\n");
+	// Call the mac handler
+	if (parse_mac_config(mod_id, &parser) == -1) {
+	  goto error;
+	}
+      } else if (strcmp(event.data.scalar.value, "rlc") == 0) {
+	// Call the RLC handler
+	LOG_D(ENB_APP, "This is intended for the rlc system\n");
+	// TODO : Just skip it for now
+	if (skip_system_section(&parser) == -1) {
+	  goto error;
+	}
+      } else if (strcmp(event.data.scalar.value, "pdcp") == 0) {
+	// Call the PDCP handler
+	LOG_D(ENB_APP, "This is intended for the pdcp system\n");
+	// TODO : Just skip it for now
+	if (skip_system_section(&parser) == -1) {
+	  goto error;
+	}
+      } else if (strcmp(event.data.scalar.value, "rrc") == 0) {
+	// Call the RRC handler
+	LOG_D(ENB_APP, "This is intended for the rrc system\n");
+	// TODO : Just skip it for now
+	if (skip_system_section(&parser) == -1) {
+	  goto error;
+	}
+      } else {
+	goto error;
+      }
+      break;
+    default:
+      // We are not expecting to find any other type of event at this level
+      // of the hierarchy
+      yaml_event_delete(&event);
+      goto error;
+    }
+    
+    done = (event.type == YAML_STREAM_END_EVENT);
+
+    yaml_event_delete(&event);
+  }
+
+  return 0;
+
+ error:
+  yaml_parser_delete(&parser);
+  return -1;
+
+}
+
+int skip_system_section(yaml_parser_t *parser) {
+  yaml_event_t event;
+  
+  int done = 0;
+
+  int sequence_started = 0;
+  int mapping_started = 0;
+
+  while (!done) {
+    if (!yaml_parser_parse(parser, &event))
+      goto error;
+   
+    switch (event.type) {
+      
+      case YAML_SEQUENCE_START_EVENT:
+      LOG_D(ENB_APP, "A sequence just started as expected\n");
+      sequence_started = 1;
+      break;
+    case YAML_SEQUENCE_END_EVENT:
+      LOG_D(ENB_APP, "A sequence ended\n");
+      sequence_started = 0;
+      break;
+    case YAML_MAPPING_START_EVENT:
+      if (!sequence_started) {
+	goto error;
+      }
+      LOG_D(ENB_APP, "A mapping started\n");
+      mapping_started = 1;
+      break;
+    case YAML_MAPPING_END_EVENT:
+      if (!mapping_started) {
+	goto error;
+      }
+      LOG_D(ENB_APP, "A mapping ended\n");
+      mapping_started = 0;
+      break;
+    case YAML_SCALAR_EVENT:
+      if (!mapping_started) {
+	goto error;
+      }
+      // Entered a subsystem section. Let's skip it
+      if (skip_subsystem_section(parser) == -1) {
+	goto error;
+      }
+    }
+    
+    done = (event.type == YAML_SEQUENCE_END_EVENT);
+
+    yaml_event_delete(&event);
+    
+  }
+
+  return 0;
+
+ error:
+  yaml_event_delete(&event);
+  return -1;
+}
+
+int skip_subsystem_section(yaml_parser_t *parser) {
+  
+  yaml_event_t event;
+
+  int done = 0;
+  int mapping_started = 0;
+
+  while (!done) {
+    if (!yaml_parser_parse(parser, &event))
+      goto error;
+
+    switch (event.type) {
+    case YAML_MAPPING_START_EVENT:
+      LOG_D(ENB_APP, "The mapping of the subsystem started\n");
+      mapping_started = 1;
+      break;
+    case YAML_MAPPING_END_EVENT:
+      LOG_D(ENB_APP, "The mapping of the subsystem ended\n");
+      mapping_started = 0;
+      break;
+    case YAML_SCALAR_EVENT:
+      if (!mapping_started) {
+	goto error;
+      }
+      // Check what key needs to be set
+      if (strcmp(event.data.scalar.value, "behavior") == 0) {
+	LOG_D(ENB_APP, "Skipping the behavior attribute\n");
+	yaml_event_delete(&event);
+	if (!yaml_parser_parse(parser, &event)) {
+	  goto error;
+	}
+	if (event.type == YAML_SCALAR_EVENT) {
+	  break;
+	} else {
+	  goto error;
+	}
+      } else if (strcmp(event.data.scalar.value, "parameters") == 0) {
+	LOG_D(ENB_APP, "Skipping the parameters for this subsystem\n");
+	if (skip_subsystem_parameters_config(parser) == -1) {
+	  goto error;
+	}
+      }
+      break;
+    default:
+      goto error;
+    }
+    
+    done = (event.type == YAML_MAPPING_END_EVENT);
+    yaml_event_delete(&event);
+  }
+
+  return 0;
+
+ error:
+  yaml_event_delete(&event);
+  return -1;
+}
+
+int skip_subsystem_parameters_config(yaml_parser_t *parser) {
+  yaml_event_t event;
+  
+  void *param;
+  
+  int done = 0;
+  int mapping_started = 0;
+
+  while (!done) {
+    
+    if (!yaml_parser_parse(parser, &event))
+      goto error;
+
+    switch (event.type) {
+      // We are expecting a mapping of parameters
+    case YAML_MAPPING_START_EVENT:
+      LOG_D(ENB_APP, "The mapping of the parameters started\n");
+      mapping_started = 1;
+      break;
+    case YAML_MAPPING_END_EVENT:
+      LOG_D(ENB_APP, "The mapping of the parameters ended\n");
+      mapping_started = 0;
+      break;
+    case YAML_SCALAR_EVENT:
+      if (!mapping_started) {
+	goto error;
+      }
+      // Check what key needs to be set
+      LOG_D(ENB_APP, "Skipping parameter %s\n", event.data.scalar.value);
+      if (skip_parameter_modification(parser) == -1 ) {
+	goto error;
+      }
+      break;
+    default:
+      goto error;
+    }
+
+    done = (event.type == YAML_MAPPING_END_EVENT);
+    yaml_event_delete(&event);
+  }
+
+  return 0;
+  
+ error:
+  yaml_event_delete(&event);
+  return -1;
+}
+
+
+int skip_parameter_modification(yaml_parser_t *parser) {
+  yaml_event_t event;
+  
+  int done = 0;
+  int is_array = 0;
+  int i = 0;
+
+  while (!done) {
+    if (!yaml_parser_parse(parser, &event)) {
+      goto error;
+    }
+    
+    // Expecting either a scalar or a sequence
+    switch (event.type) {
+    case YAML_SEQUENCE_START_EVENT:
+      is_array = 1;
+      break;
+    case YAML_SCALAR_EVENT:
+      if ((strcmp(event.data.scalar.tag, YAML_INT_TAG) == 0) ||
+	  (strcmp(event.data.scalar.tag, YAML_FLOAT_TAG) == 0) ||
+	  (strcmp(event.data.scalar.tag, YAML_STR_TAG) == 0) ||
+	  (strcmp(event.data.scalar.tag, YAML_BOOL_TAG) == 0)) {
+	// Do nothing
+      } else {
+	// No other type is supported at the moment, so it should be considered an error
+	// if we reach here
+	goto error;
+      }
+      if (is_array) {
+	i++;
+      } else {
+	done = 1;
+      }
+      break;
+    case YAML_SEQUENCE_END_EVENT:
+      done = 1;
+      break;
+    default:
+      goto error;
+    }
+    yaml_event_delete(&event);
+  }
+
+  return 0;
+
+ error:
+  yaml_event_delete(&event);
+  return -1;
+}
+
+int apply_parameter_modification(void *parameter, yaml_parser_t *parser) {
+  yaml_event_t event;
+  
+  int done = 0;
+  int is_array = 0;
+  int i = 0;
+
+  char *endptr;
+
+  while (!done) {
+    if (!yaml_parser_parse(parser, &event)) {
+      goto error;
+    }
+    
+    // Expecting either a scalar or a sequence
+    switch (event.type) {
+    case YAML_SEQUENCE_START_EVENT:
+      is_array = 1;
+      break;
+    case YAML_SCALAR_EVENT:
+      if (strcmp(event.data.scalar.tag, YAML_INT_TAG) == 0) {
+	((int *) parameter)[i] = strtol(event.data.scalar.value, &endptr, 10);
+      } else if (strcmp(event.data.scalar.tag, YAML_FLOAT_TAG) == 0) {
+	((float *) parameter)[i] = strtof(event.data.scalar.value, &endptr);
+      } else if (strcmp(event.data.scalar.tag, YAML_STR_TAG) == 0) {
+	strncpy(&((char *) parameter)[i], event.data.scalar.value, event.data.scalar.length);
+      } else if (strcmp(event.data.scalar.tag, YAML_BOOL_TAG) == 0) {
+	if (strcmp(event.data.scalar.value, "true") == 0) {
+	  ((int *) parameter)[i] = 1;
+	} else {
+	  ((int *) parameter)[i] = 0;
+	}
+      } else {
+	// No other type is supported at the moment, so it should be considered an error
+	// if we reach here
+	goto error;
+      }
+      if (is_array) {
+	i++;
+      } else {
+	done = 1;
+      }
+      break;
+    case YAML_SEQUENCE_END_EVENT:
+      done = 1;
+      break;
+    default:
+      goto error;
+    }
+    yaml_event_delete(&event);
+  }
+
+  return 0;
+
+ error:
+  yaml_event_delete(&event);
+  return -1;
+  
+}
diff --git a/openair2/ENB_APP/enb_agent_common_internal.h b/openair2/ENB_APP/enb_agent_common_internal.h
new file mode 100644
index 0000000000..30fd51c5c8
--- /dev/null
+++ b/openair2/ENB_APP/enb_agent_common_internal.h
@@ -0,0 +1,64 @@
+/*******************************************************************************
+    OpenAirInterface
+    Copyright(c) 1999 - 2014 Eurecom
+
+    OpenAirInterface is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+
+    OpenAirInterface is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenAirInterface.The full GNU General Public License is
+   included in this distribution in the file called "COPYING". If not,
+   see <http://www.gnu.org/licenses/>.
+
+  Contact Information
+  OpenAirInterface Admin: openair_admin@eurecom.fr
+  OpenAirInterface Tech : openair_tech@eurecom.fr
+  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
+
+  Address      : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
+
+ *******************************************************************************/
+
+/*! \file enb_agent_common_internal.h
+ * \brief internal agent functions for common message primitves and utilities
+ * \author Xenofon Foukas
+ * \date 2016
+ * \version 0.1
+ */
+
+#ifndef ENB_AGENT_COMMON_INTERNAL_H_
+#define ENB_AGENT_COMMON_INTERNAL_H_
+
+#include <yaml.h>
+
+#include "enb_agent_defs.h"
+
+int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy_length);
+
+int apply_parameter_modification(void *parameter, yaml_parser_t *parser);
+
+// This can be used when parsing for a specific system that is not yet implmeneted
+// in order to skip its configuration, without affecting the rest
+int skip_system_section(yaml_parser_t *parser);
+
+// This can be used when parsing for a specific subsystem that is not yet implmeneted
+// in order to skip its configuration, without affecting the rest
+int skip_subsystem_section(yaml_parser_t *parser);
+
+// This can be used when parsing for the parameters of a specific subsystem 
+//that is not yet implmeneted in order to skip its configuration, without affecting the rest
+int skip_subsystem_parameters_config(yaml_parser_t *parser);
+
+// This can be used when configuring the parameters of a specific subsystem 
+//that is not yet implmeneted in order to skip its configuration, without affecting the rest
+int skip_parameter_modification(yaml_parser_t *parser);
+
+#endif
diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c
index 721b3678f8..da53343818 100644
--- a/openair2/ENB_APP/enb_agent_handler.c
+++ b/openair2/ENB_APP/enb_agent_handler.c
@@ -58,7 +58,7 @@ enb_agent_message_decoded_callback agent_messages_callback[][3] = {
   {enb_agent_mac_handle_dl_mac_config, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG*/
   {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG*/
   {enb_agent_control_delegation, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_CONTROL_DELEGATION_MSG*/
-
+  {enb_agent_reconfiguration, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_AGENT_RECONFIGURATION_MSG*/
 };
 
 enb_agent_message_destruction_callback message_destruction_callback[] = {
@@ -78,6 +78,7 @@ enb_agent_message_destruction_callback message_destruction_callback[] = {
   enb_agent_mac_destroy_dl_config,
   enb_agent_destroy_ue_state_change,
   enb_agent_destroy_control_delegation,
+  enb_agent_destroy_agent_reconfiguration,
 };
 
 static const char *enb_agent_direction2String[] = {
diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c
index fb9ae7322f..744768135e 100644
--- a/openair2/ENB_APP/enb_agent_mac.c
+++ b/openair2/ENB_APP/enb_agent_mac.c
@@ -1391,6 +1391,8 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) {
   xface->enb_agent_schedule_ue_spec = schedule_ue_spec_remote;
   xface->enb_agent_get_pending_dl_mac_config = enb_agent_get_pending_dl_mac_config;
   xface->enb_agent_notify_ue_state_change = enb_agent_ue_state_change;
+  
+  xface->dl_scheduler_loaded_lib = NULL;
 
   mac_agent_registered[mod_id] = 1;
   agent_mac_xface[mod_id] = xface;
@@ -1408,6 +1410,8 @@ int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) {
   xface->enb_agent_get_pending_dl_mac_config = NULL;
   xface->enb_agent_notify_ue_state_change = NULL;
 
+  xface->dl_scheduler_loaded_lib = NULL;
+
   mac_agent_registered[mod_id] = 0;
   agent_mac_xface[mod_id] = NULL;
 
diff --git a/openair2/ENB_APP/enb_agent_mac_defs.h b/openair2/ENB_APP/enb_agent_mac_defs.h
index c5a3204f0c..1511ee7262 100644
--- a/openair2/ENB_APP/enb_agent_mac_defs.h
+++ b/openair2/ENB_APP/enb_agent_mac_defs.h
@@ -74,6 +74,8 @@ typedef struct {
   void (*enb_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti,
 					   uint32_t state_change);
   
+  
+  void *dl_scheduler_loaded_lib;
   /*TODO: Fill in with the rest of the MAC layer technology specific callbacks (UL/DL scheduling, RACH info etc)*/
 
 } AGENT_MAC_xface;
diff --git a/openair2/ENB_APP/enb_agent_mac_internal.c b/openair2/ENB_APP/enb_agent_mac_internal.c
index c3cc584bcd..aa7482bd90 100644
--- a/openair2/ENB_APP/enb_agent_mac_internal.c
+++ b/openair2/ENB_APP/enb_agent_mac_internal.c
@@ -34,6 +34,9 @@
  * \version 0.1
  */
 
+#include <string.h>
+#include <dlfcn.h>
+
 #include "enb_agent_mac_internal.h"
 
 Protocol__ProgranMessage * enb_agent_generate_diff_mac_stats_report(Protocol__ProgranMessage *new_message,
@@ -558,3 +561,235 @@ Protocol__PrpNoiseInterferenceReport * copy_noise_inter_report(Protocol__PrpNois
  error:
   return NULL;
 }
+
+
+int parse_mac_config(mid_t mod_id, yaml_parser_t *parser) {
+  
+  yaml_event_t event;
+  
+  int done = 0;
+
+  int sequence_started = 0;
+  int mapping_started = 0;
+
+  while (!done) {
+
+    if (!yaml_parser_parse(parser, &event))
+      goto error;
+   
+    switch (event.type) {
+    case YAML_SEQUENCE_START_EVENT:
+      LOG_I(ENB_APP, "A sequence just started as expected\n");
+      sequence_started = 1;
+      break;
+    case YAML_SEQUENCE_END_EVENT:
+      LOG_I(ENB_APP, "A sequence ended\n");
+      sequence_started = 0;
+      break;
+    case YAML_MAPPING_START_EVENT:
+      if (!sequence_started) {
+	goto error;
+      }
+      LOG_I(ENB_APP, "A mapping started\n");
+      mapping_started = 1;
+      break;
+    case YAML_MAPPING_END_EVENT:
+      if (!mapping_started) {
+	goto error;
+      }
+      LOG_I(ENB_APP, "A mapping ended\n");
+      mapping_started = 0;
+      break;
+    case YAML_SCALAR_EVENT:
+      if (!mapping_started) {
+	goto error;
+      }
+      // Check the types of subsystems offered and handle their values accordingly
+      if (strcmp(event.data.scalar.value, "dl_scheduler") == 0) {
+	LOG_I(ENB_APP, "This is for the dl_scheduler subsystem\n");
+	// Call the proper handler
+	if (parse_dl_scheduler_config(mod_id, parser) == -1) {
+	  LOG_I(ENB_APP, "An error occured\n");
+	  goto error;
+	}
+      } else if (strcmp(event.data.scalar.value, "ul_scheduler") == 0) {
+	// Call the proper handler
+	LOG_I(ENB_APP, "This is for the ul_scheduler subsystem\n");
+	goto error;
+	// TODO
+      } else if (strcmp(event.data.scalar.value, "ra_scheduler") == 0) {
+	// Call the proper handler
+	// TODO
+      } else if (strcmp(event.data.scalar.value, "page_scheduler") == 0) {
+	// Call the proper handler
+	// TODO
+      } else {
+	// Unknown subsystem
+	goto error;
+      }
+      break;
+    default: // We expect nothing else at this level of the hierarchy
+      goto error;
+    }
+   
+    done = (event.type == YAML_SEQUENCE_END_EVENT);
+
+    yaml_event_delete(&event);
+ 
+  }
+  
+  return 0;
+
+  error:
+  yaml_event_delete(&event);
+  return -1;
+
+}
+
+int parse_dl_scheduler_config(mid_t mod_id, yaml_parser_t *parser) {
+  
+  yaml_event_t event;
+
+  int done = 0;
+  int mapping_started = 0;
+
+  while (!done) {
+    
+    if (!yaml_parser_parse(parser, &event))
+      goto error;
+
+    switch (event.type) {
+      // We are expecting a mapping (behavior and parameters)
+    case YAML_MAPPING_START_EVENT:
+      LOG_D(ENB_APP, "The mapping of the subsystem started\n");
+      mapping_started = 1;
+      break;
+    case YAML_MAPPING_END_EVENT:
+      LOG_D(ENB_APP, "The mapping of the subsystem ended\n");
+      mapping_started = 0;
+      break;
+    case YAML_SCALAR_EVENT:
+      if (!mapping_started) {
+	goto error;
+      }
+      // Check what key needs to be set
+      if (strcmp(event.data.scalar.value, "behavior") == 0) {
+	LOG_D(ENB_APP, "Time to set the behavior attribute\n");
+	yaml_event_delete(&event);
+	if (!yaml_parser_parse(parser, &event)) {
+	  goto error;
+	}
+	if (event.type == YAML_SCALAR_EVENT) {
+	  if (load_dl_scheduler_function(mod_id, event.data.scalar.value) == -1) {
+	    goto error;
+	  }
+	} else {
+	  goto error;
+	}
+      } else if (strcmp(event.data.scalar.value, "parameters") == 0) {
+	LOG_D(ENB_APP, "Now it is time to set the parameters for this subsystem\n");
+	if (parse_dl_scheduler_parameters(mod_id, parser) == -1) {
+	  goto error;
+	}
+      }
+      break;
+    default:
+      goto error;
+    }
+
+    done = (event.type == YAML_MAPPING_END_EVENT);
+    yaml_event_delete(&event);
+  }
+
+  return 0;
+
+ error:
+  yaml_event_delete(&event);
+  return -1;
+}
+
+int parse_dl_scheduler_parameters(mid_t mod_id, yaml_parser_t *parser) {
+  yaml_event_t event;
+  
+  void *param;
+  
+  int done = 0;
+  int mapping_started = 0;
+
+  while (!done) {
+    
+    if (!yaml_parser_parse(parser, &event))
+      goto error;
+
+    switch (event.type) {
+      // We are expecting a mapping of parameters
+    case YAML_MAPPING_START_EVENT:
+      LOG_D(ENB_APP, "The mapping of the parameters started\n");
+      mapping_started = 1;
+      break;
+    case YAML_MAPPING_END_EVENT:
+      LOG_D(ENB_APP, "The mapping of the parameters ended\n");
+      mapping_started = 0;
+      break;
+    case YAML_SCALAR_EVENT:
+      if (!mapping_started) {
+	goto error;
+      }
+      // Check what key needs to be set
+      if (mac_agent_registered[mod_id]) {
+	LOG_D(ENB_APP, "Setting parameter %s\n", event.data.scalar.value);
+	param = dlsym(agent_mac_xface[mod_id]->dl_scheduler_loaded_lib,
+		      event.data.scalar.value);
+	if (param == NULL) {
+	  goto error;
+	}
+	apply_parameter_modification(param, parser);
+      } else {
+	goto error;
+      }
+      break;
+    default:
+      goto error;
+    }
+
+    done = (event.type == YAML_MAPPING_END_EVENT);
+    yaml_event_delete(&event);
+  }
+
+  return 0;
+  
+ error:
+  yaml_event_delete(&event);
+  return -1;
+}
+
+int load_dl_scheduler_function(mid_t mod_id, const char *function_name) {
+  void *lib;
+
+  char lib_name[120];
+  char target[512];
+  sprintf(lib_name, sizeof(lib_name), "/%s.so", function_name);
+  strcpy(target, local_cache);
+  strcat(target, lib_name);
+
+  lib = dlopen(target, RTLD_NOW);
+  if (lib == NULL) {
+    goto error;
+  }
+  
+  void *loaded_scheduler = dlsym(lib, function_name);
+  if (loaded_scheduler) {
+    if (mac_agent_registered[mod_id]) {
+      agent_mac_xface[mod_id]->enb_agent_schedule_ue_spec = loaded_scheduler;
+      dlclose(agent_mac_xface[mod_id]->dl_scheduler_loaded_lib);
+      agent_mac_xface[mod_id]->dl_scheduler_loaded_lib = lib;
+      LOG_D(ENB_APP, "Delegated control for DL UE scheduler succesfully\n");
+    }
+  }
+
+  return 0;
+
+ error:
+  return -1;
+  
+}
diff --git a/openair2/ENB_APP/enb_agent_mac_internal.h b/openair2/ENB_APP/enb_agent_mac_internal.h
index 394d3e7730..4a76f0ed38 100644
--- a/openair2/ENB_APP/enb_agent_mac_internal.h
+++ b/openair2/ENB_APP/enb_agent_mac_internal.h
@@ -39,9 +39,11 @@
 
 #include <pthread.h>
 
+#include <yaml.h>
+
 #include "enb_agent_mac.h"
 #include "enb_agent_common.h"
-
+#include "enb_agent_defs.h"
 
 /*This will be used for producing continuous status updates for the MAC
  *Needs to be thread-safe
@@ -98,4 +100,15 @@ int compare_ue_stats_reports(Protocol__PrpUeStatsReport *rep1,
 int compare_cell_stats_reports(Protocol__PrpCellStatsReport *rep1,
 			    Protocol__PrpCellStatsReport *rep2);
 
+
+/* Functions for parsing the MAC agent policy reconfiguration command */
+
+int parse_mac_config(mid_t mod_id, yaml_parser_t *parser);
+
+int parse_dl_scheduler_config(mid_t mod_id, yaml_parser_t *parser);
+
+int parse_dl_scheduler_parameters(mid_t mod_id, yaml_parser_t *parser);
+
+int load_dl_scheduler_function(mid_t mod_id, const char *function_name);
+
 #endif /*ENB_AGENT_MAC_INTERNAL_H_*/
diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c
index ad8b130584..d8d2373332 100644
--- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c
+++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c
@@ -37,6 +37,8 @@
 
  */
 
+#include "enb_agent_common_internal.h"
+
 #include "eNB_agent_scheduler_dlsch_ue_remote.h"
 
 #include "LAYER2/MAC/defs.h"
@@ -46,9 +48,25 @@ struct DlMacConfigHead queue_head;
 
 int queue_initialized = 0;
 
+//uint32_t skip_subframe = 1;
+//uint32_t period = 10;
+//uint32_t sched [] = {1, 2, 3};
+
 void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe,
 			     int *mbsfn_flag, Protocol__ProgranMessage **dl_info) {
 
+  
+  //if ((subframe == skip_subframe) && (frame % period == 0)) {
+  //  LOG_I(MAC, "Will skip subframe %d %d\n", subframe, frame);
+  //  for (int i = 0; i < 3; i++) {
+  //    LOG_I(MAC, "%d\n", sched[i]);
+  //  }
+  //}
+
+  /* if (frame == 500 && subframe == 1) { */
+  /*   char policy[] = "rrc: \n - ul_scheduler: \n    behavior : tester_function\n    parameters:\n      period: !!int 3\nmac: \n - dl_scheduler: \n    parameters: \n      period : !!int 40\n      skip_subframe : !!int 3\n      sched : [!!int 4, !!int 5, !!int 6]"; */
+  /*   apply_reconfiguration_policy(mod_id, policy, strlen(policy)); */
+  /* } */
 
   eNB_MAC_INST *eNB;
 
-- 
GitLab