mirror of
https://dev.iopsys.eu/bbf/bbfdm.git
synced 2026-03-13 20:50:19 +01:00
Optimize ram usage by combining dm-services
This commit is contained in:
parent
20378e5cc4
commit
bd67afba66
19 changed files with 846 additions and 62 deletions
|
|
@ -6,6 +6,10 @@ ADD_DEFINITIONS(-fstrict-aliasing -Wall -Wextra -Werror -Wformat -Wformat-signed
|
|||
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SOURCE_DIR}")
|
||||
|
||||
if (BBFDM_DM_SERVICE_RAM_OPTIMIZED)
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DBBFDM_DM_SERVICE_RAM_OPTIMIZED")
|
||||
endif()
|
||||
|
||||
FILE(GLOB BBF_SOURCES *.c)
|
||||
ADD_EXECUTABLE(bbfdmd ${BBF_SOURCES})
|
||||
TARGET_LINK_LIBRARIES(bbfdmd ubus ubox blobmsg_json json-c bbfdm-api-v2)
|
||||
|
|
|
|||
|
|
@ -468,11 +468,19 @@ int main(int argc, char **argv)
|
|||
uloop_init();
|
||||
ubus_add_uloop(&g_ubus_ctx);
|
||||
|
||||
#ifdef BBFDM_DM_SERVICE_RAM_OPTIMIZED
|
||||
err = register_suppress_services(&g_ubus_ctx);
|
||||
if (err) {
|
||||
BBFDM_ERR("Failed to load micro-services");
|
||||
goto end;
|
||||
}
|
||||
#else
|
||||
err = register_services(&g_ubus_ctx);
|
||||
if (err) {
|
||||
BBFDM_ERR("Failed to load micro-services");
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
|
||||
err = ubus_add_object(&g_ubus_ctx, &bbfdm_object);
|
||||
if (err != UBUS_STATUS_OK) {
|
||||
|
|
|
|||
|
|
@ -229,6 +229,445 @@ static int compare(const struct dirent **a, const struct dirent **b)
|
|||
return strcasecmp((*a)->d_name, (*b)->d_name); // If lengths are equal, sort alphabetically
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char **paths;
|
||||
char **filenames;
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
} file_list_t;
|
||||
|
||||
static int file_list_init(file_list_t *fl, size_t capacity)
|
||||
{
|
||||
fl->paths = calloc(capacity, sizeof(char *));
|
||||
fl->filenames = calloc(capacity, sizeof(char *));
|
||||
if (!fl->paths || !fl->filenames) {
|
||||
BBFDM_FREE(fl->paths);
|
||||
BBFDM_FREE(fl->filenames);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fl->count = 0;
|
||||
fl->capacity = capacity;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int file_list_push(file_list_t *fl, const char *file_path, const char *filename)
|
||||
{
|
||||
if (fl->count >= fl->capacity) {
|
||||
BBFDM_ERR("file_list_push: capacity exhausted (%zu)", fl->capacity);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fl->paths[fl->count] = strdup(file_path);
|
||||
fl->filenames[fl->count] = strdup(filename);
|
||||
if (!fl->paths[fl->count] || !fl->filenames[fl->count]) {
|
||||
BBFDM_FREE(fl->paths[fl->count]);
|
||||
BBFDM_FREE(fl->filenames[fl->count]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fl->count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void file_list_free(file_list_t *fl)
|
||||
{
|
||||
for (size_t i = 0; i < fl->count; i++) {
|
||||
BBFDM_FREE(fl->paths[i]);
|
||||
BBFDM_FREE(fl->filenames[i]);
|
||||
}
|
||||
|
||||
BBFDM_FREE(fl->paths);
|
||||
BBFDM_FREE(fl->filenames);
|
||||
memset(fl, 0, sizeof(*fl));
|
||||
}
|
||||
|
||||
static bool peek_is_unified(const char *file_path)
|
||||
{
|
||||
json_object *json_root = json_object_from_file(file_path);
|
||||
if (!json_root)
|
||||
return false;
|
||||
|
||||
json_object *daemon_config = NULL;
|
||||
json_object_object_get_ex(json_root, "daemon", &daemon_config);
|
||||
if (!daemon_config) {
|
||||
json_object_put(json_root);
|
||||
return false;
|
||||
}
|
||||
|
||||
json_object *unified_jobj = NULL;
|
||||
json_object_object_get_ex(daemon_config, "unified_daemon", &unified_jobj);
|
||||
bool is_unified = unified_jobj ? json_object_get_boolean(unified_jobj) : false;
|
||||
|
||||
json_object_put(json_root);
|
||||
return is_unified;
|
||||
}
|
||||
|
||||
static void fill_from_services(json_object *services_arr, const char *source_name, service_object_t *objects,
|
||||
size_t *num_objs, size_t total_capacity)
|
||||
{
|
||||
size_t _len = json_object_array_length(services_arr);
|
||||
for (size_t _j = 0; _j < _len; _j++) {
|
||||
json_object *_svc = json_object_array_get_idx(services_arr, _j);
|
||||
json_object *_pdm = NULL, *_obj = NULL, *_proto = NULL;
|
||||
const char *_pdm_str, *_obj_str;
|
||||
|
||||
json_object_object_get_ex(_svc, "parent_dm", &_pdm);
|
||||
json_object_object_get_ex(_svc, "object", &_obj);
|
||||
json_object_object_get_ex(_svc, "proto", &_proto);
|
||||
|
||||
_pdm_str = _pdm ? json_object_get_string(_pdm) : "";
|
||||
_obj_str = _obj ? json_object_get_string(_obj) : "";
|
||||
|
||||
memset(objects[*num_objs].parent_path, 0, sizeof(objects[*num_objs].parent_path));
|
||||
memset(objects[*num_objs].object_name, 0, sizeof(objects[*num_objs].object_name));
|
||||
|
||||
strncpy(objects[*num_objs].parent_path, _pdm_str, sizeof(objects[*num_objs].parent_path) - 1);
|
||||
strncpy(objects[*num_objs].object_name, _obj_str, sizeof(objects[*num_objs].object_name) - 1);
|
||||
if (!strlen(objects[*num_objs].parent_path) || !strlen(objects[*num_objs].object_name)) {
|
||||
BBFDM_WARNING("Skip empty parent_dm/object in %s", source_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
objects[*num_objs].protocol = get_proto_type(_proto ? json_object_get_string(_proto) : "");
|
||||
|
||||
(*num_objs)++;
|
||||
if (*num_objs >= total_capacity) {
|
||||
BBFDM_WARNING("Reached object capacity in %s", source_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void load_non_unified_services(struct ubus_context *ubus_ctx, file_list_t *fl)
|
||||
{
|
||||
if (fl->count == 0)
|
||||
return;
|
||||
|
||||
/* Locate core.json in the list and move it to index 0 */
|
||||
size_t core_idx = fl->count;
|
||||
for (size_t i = 0; i < fl->count; i++) {
|
||||
if (strcmp(fl->filenames[i], "core.json") == 0) {
|
||||
core_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (core_idx == fl->count) {
|
||||
BBFDM_ERR("core.json not found in non-unified service list – aborting");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Swap core.json to position 0 so the loop below handles it first. */
|
||||
if (core_idx != 0) {
|
||||
char *tmp_path = fl->paths[0];
|
||||
fl->paths[0] = fl->paths[core_idx];
|
||||
fl->paths[core_idx] = tmp_path;
|
||||
|
||||
char *tmp_name = fl->filenames[0];
|
||||
fl->filenames[0] = fl->filenames[core_idx];
|
||||
fl->filenames[core_idx] = tmp_name;
|
||||
}
|
||||
|
||||
/* Load core.json – derive the shared service configuration */
|
||||
json_object *core_root = json_object_from_file(fl->paths[0]);
|
||||
if (!core_root) {
|
||||
BBFDM_ERR("Failed to read core.json: %s", fl->paths[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
json_object *core_daemon = NULL;
|
||||
json_object_object_get_ex(core_root, "daemon", &core_daemon);
|
||||
if (!core_daemon) {
|
||||
BBFDM_ERR("core.json missing 'daemon' object");
|
||||
json_object_put(core_root);
|
||||
return;
|
||||
}
|
||||
|
||||
json_object *enable_jobj = NULL;
|
||||
json_object_object_get_ex(core_daemon, "enable", &enable_jobj);
|
||||
bool enable = enable_jobj ? json_object_get_boolean(enable_jobj) : false;
|
||||
if (!enable) {
|
||||
BBFDM_INFO("core service is disabled, Skipping service");
|
||||
json_object_put(core_root);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Service name is derived from core.json's filename. */
|
||||
char service_name[MAX_PATH_LENGTH] = {0};
|
||||
const char *core_fname = fl->filenames[0];
|
||||
snprintf(service_name, sizeof(service_name), "%s.%.*s", BBFDM_UBUS_OBJECT, (int)(strlen(core_fname) - 5), core_fname);
|
||||
|
||||
struct blob_buf *service_schema = NULL;
|
||||
fill_service_schema(ubus_ctx, 2000, service_name, &service_schema);
|
||||
|
||||
json_object *proto_jobj = NULL;
|
||||
json_object_object_get_ex(core_daemon, "proto", &proto_jobj);
|
||||
int service_proto = get_proto_type(proto_jobj ? json_object_get_string(proto_jobj) : "");
|
||||
|
||||
json_object *timeout_jobj = NULL;
|
||||
json_object_object_get_ex(core_daemon, "timeout", &timeout_jobj);
|
||||
int service_timeout = timeout_jobj ? json_object_get_int(timeout_jobj) : SERVICE_CALL_TIMEOUT;
|
||||
|
||||
/* count the total number of service objects across
|
||||
* core.json + all enabled peer files so we can allocate once. */
|
||||
size_t total_capacity = 0;
|
||||
|
||||
/* Count objects in core.json's services array */
|
||||
json_object *core_services = NULL;
|
||||
json_object_object_get_ex(core_daemon, "services", &core_services);
|
||||
if (core_services && json_object_get_type(core_services) == json_type_array)
|
||||
total_capacity += json_object_array_length(core_services);
|
||||
|
||||
/* Count objects from every other enabled file */
|
||||
json_object **peer_roots = calloc(fl->count, sizeof(json_object *)); /* index 0 unused */
|
||||
if (!peer_roots) {
|
||||
BBFDM_ERR("Failed to allocate peer_roots");
|
||||
json_object_put(core_root);
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < fl->count; i++) {
|
||||
json_object *peer_root = json_object_from_file(fl->paths[i]);
|
||||
if (!peer_root) {
|
||||
BBFDM_WARNING("Failed to read JSON: %s – skipping", fl->paths[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
json_object *peer_daemon = NULL;
|
||||
json_object_object_get_ex(peer_root, "daemon", &peer_daemon);
|
||||
if (!peer_daemon) {
|
||||
json_object_put(peer_root);
|
||||
continue;
|
||||
}
|
||||
|
||||
json_object *enable_jobj = NULL;
|
||||
json_object_object_get_ex(peer_daemon, "enable", &enable_jobj);
|
||||
bool enabled = enable_jobj ? json_object_get_boolean(enable_jobj) : false;
|
||||
if (!enabled) {
|
||||
BBFDM_INFO("Service '%s' is disabled – skipping", fl->filenames[i]);
|
||||
json_object_put(peer_root);
|
||||
continue;
|
||||
}
|
||||
|
||||
json_object *peer_services = NULL;
|
||||
json_object_object_get_ex(peer_daemon, "services", &peer_services);
|
||||
if (peer_services && json_object_get_type(peer_services) == json_type_array)
|
||||
total_capacity += json_object_array_length(peer_services);
|
||||
|
||||
peer_roots[i] = peer_root; /* retain for the fill pass below */
|
||||
}
|
||||
|
||||
if (total_capacity == 0) {
|
||||
BBFDM_WARNING("No service objects found across non-unified files – skipping");
|
||||
for (size_t i = 1; i < fl->count; i++) {
|
||||
if (peer_roots[i])
|
||||
json_object_put(peer_roots[i]);
|
||||
}
|
||||
|
||||
BBFDM_FREE(peer_roots);
|
||||
json_object_put(core_root);
|
||||
return;
|
||||
}
|
||||
|
||||
service_object_t *objects = calloc(total_capacity, sizeof(service_object_t));
|
||||
if (!objects) {
|
||||
BBFDM_ERR("Failed to allocate service objects");
|
||||
for (size_t i = 1; i < fl->count; i++) {
|
||||
if (peer_roots[i])
|
||||
json_object_put(peer_roots[i]);
|
||||
}
|
||||
|
||||
BBFDM_FREE(peer_roots);
|
||||
json_object_put(core_root);
|
||||
return;
|
||||
}
|
||||
|
||||
/* fill the objects array */
|
||||
size_t num_objs = 0;
|
||||
|
||||
/* core.json objects */
|
||||
if (core_services && json_object_get_type(core_services) == json_type_array)
|
||||
fill_from_services(core_services, "core.json", objects, &num_objs, total_capacity);
|
||||
|
||||
/* peer files */
|
||||
for (size_t i = 1; i < fl->count; i++) {
|
||||
if (!peer_roots[i])
|
||||
continue;
|
||||
|
||||
json_object *peer_daemon = NULL;
|
||||
json_object_object_get_ex(peer_roots[i], "daemon", &peer_daemon);
|
||||
|
||||
json_object *peer_services = NULL;
|
||||
json_object_object_get_ex(peer_daemon, "services", &peer_services);
|
||||
|
||||
if (peer_services && json_object_get_type(peer_services) == json_type_array)
|
||||
fill_from_services(peer_services, fl->filenames[i], objects, &num_objs, total_capacity);
|
||||
|
||||
json_object_put(peer_roots[i]);
|
||||
}
|
||||
|
||||
BBFDM_FREE(peer_roots);
|
||||
json_object_put(core_root);
|
||||
|
||||
/* Register the single merged service entry */
|
||||
BBFDM_INFO("Registering non-unified service [%s :: %zu objects]", service_name, num_objs);
|
||||
add_service_to_list(service_name, service_schema, service_proto, service_timeout, objects, num_objs, false);
|
||||
}
|
||||
|
||||
static int load_unified_service(struct ubus_context *ubus_ctx, const char *filename, const char *file_path)
|
||||
{
|
||||
size_t num_objs = 0;
|
||||
|
||||
if (!filename || !file_path) {
|
||||
BBFDM_ERR("Invalid filename or file path");
|
||||
return -1;
|
||||
}
|
||||
|
||||
json_object *json_root = json_object_from_file(file_path);
|
||||
if (!json_root) {
|
||||
BBFDM_ERR("Failed to read JSON file: %s", file_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
json_object *daemon_config = NULL;
|
||||
json_object_object_get_ex(json_root, "daemon", &daemon_config);
|
||||
if (!daemon_config) {
|
||||
BBFDM_ERR("Failed to find daemon object in: %s", file_path);
|
||||
json_object_put(json_root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
json_object *enable_jobj = NULL;
|
||||
json_object_object_get_ex(daemon_config, "enable", &enable_jobj);
|
||||
bool enable = enable_jobj ? json_object_get_boolean(enable_jobj) : false;
|
||||
if (!enable) {
|
||||
BBFDM_INFO("Unified service '%s' is disabled – skipping", filename);
|
||||
json_object_put(json_root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char service_name[MAX_PATH_LENGTH] = {0};
|
||||
snprintf(service_name, sizeof(service_name), "%s.%.*s", BBFDM_UBUS_OBJECT, (int)(strlen(filename) - 5), filename);
|
||||
|
||||
struct blob_buf *service_schema = NULL;
|
||||
fill_service_schema(ubus_ctx, 2000, service_name, &service_schema);
|
||||
|
||||
json_object *proto_jobj = NULL;
|
||||
json_object_object_get_ex(daemon_config, "proto", &proto_jobj);
|
||||
int service_proto = get_proto_type(proto_jobj ? json_object_get_string(proto_jobj) : "");
|
||||
|
||||
json_object *timeout_jobj = NULL;
|
||||
json_object_object_get_ex(daemon_config, "timeout", &timeout_jobj);
|
||||
int service_timeout = timeout_jobj ? json_object_get_int(timeout_jobj) : SERVICE_CALL_TIMEOUT;
|
||||
|
||||
json_object *services_array = NULL;
|
||||
if (!json_object_object_get_ex(daemon_config, "services", &services_array) ||
|
||||
json_object_get_type(services_array) != json_type_array) {
|
||||
BBFDM_WARNING("No valid 'services' array in: %s", filename);
|
||||
json_object_put(json_root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t service_count = json_object_array_length(services_array);
|
||||
if (service_count == 0) {
|
||||
BBFDM_WARNING("Empty 'services' array in unified service '%s'", service_name);
|
||||
json_object_put(json_root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
service_object_t *objects = calloc(service_count, sizeof(service_object_t));
|
||||
if (!objects) {
|
||||
BBFDM_ERR("Failed to allocate memory");
|
||||
json_object_put(json_root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < service_count; i++) {
|
||||
json_object *service_obj = json_object_array_get_idx(services_array, i);
|
||||
json_object *parent_dm = NULL, *object = NULL, *proto = NULL;
|
||||
|
||||
json_object_object_get_ex(service_obj, "parent_dm", &parent_dm);
|
||||
json_object_object_get_ex(service_obj, "object", &object);
|
||||
json_object_object_get_ex(service_obj, "proto", &proto);
|
||||
|
||||
snprintf(objects[num_objs].parent_path, sizeof(objects[num_objs].parent_path), "%s", parent_dm ? json_object_get_string(parent_dm) : "");
|
||||
snprintf(objects[num_objs].object_name, sizeof(objects[num_objs].object_name), "%s", object ? json_object_get_string(object) : "");
|
||||
|
||||
if (!strlen(objects[num_objs].parent_path) || !strlen(objects[num_objs].object_name)) {
|
||||
BBFDM_WARNING("Skip empty parent_dm/object in '%s'", service_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
objects[num_objs].protocol = get_proto_type(proto ? json_object_get_string(proto) : "");
|
||||
num_objs++;
|
||||
}
|
||||
|
||||
BBFDM_INFO("Registering unified service [%s :: %zu objects]", service_name, num_objs);
|
||||
add_service_to_list(service_name, service_schema, service_proto, service_timeout, objects, num_objs, true);
|
||||
|
||||
json_object_put(json_root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int register_suppress_services(struct ubus_context *ubus_ctx)
|
||||
{
|
||||
struct dirent **namelist = NULL;
|
||||
file_list_t non_unified_list = {0};
|
||||
file_list_t unified_list = {0};
|
||||
|
||||
int num_files = scandir(BBFDM_MICROSERVICE_INPUT_PATH, &namelist, filter, compare);
|
||||
if (num_files < 0) {
|
||||
BBFDM_ERR("scandir failed on: %s", BBFDM_MICROSERVICE_INPUT_PATH);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (file_list_init(&non_unified_list, (size_t)num_files) < 0 || file_list_init(&unified_list, (size_t)num_files) < 0) {
|
||||
BBFDM_ERR("Failed to allocate categorisation lists");
|
||||
for (int i = 0; i < num_files; i++)
|
||||
BBFDM_FREE(namelist[i]);
|
||||
|
||||
BBFDM_FREE(namelist);
|
||||
|
||||
file_list_free(&non_unified_list);
|
||||
file_list_free(&unified_list);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* categorise every valid JSON file */
|
||||
for (int i = 0; i < num_files; i++) {
|
||||
char file_path[512] = {0};
|
||||
snprintf(file_path, sizeof(file_path), "%s/%s", BBFDM_MICROSERVICE_INPUT_PATH, namelist[i]->d_name);
|
||||
|
||||
if (!bbfdm_file_exists(file_path) || !bbfdm_is_regular_file(file_path)) {
|
||||
BBFDM_FREE(namelist[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool is_unified = peek_is_unified(file_path);
|
||||
file_list_t *target = is_unified ? &unified_list : &non_unified_list;
|
||||
|
||||
if (file_list_push(target, file_path, namelist[i]->d_name) < 0)
|
||||
BBFDM_ERR("Failed to push '%s' into categorisation list", namelist[i]->d_name);
|
||||
|
||||
BBFDM_FREE(namelist[i]);
|
||||
}
|
||||
BBFDM_FREE(namelist);
|
||||
|
||||
/* handle all non-unified files as a single merged service */
|
||||
load_non_unified_services(ubus_ctx, &non_unified_list);
|
||||
|
||||
/* handle each unified file as its own independent service */
|
||||
for (size_t i = 0; i < unified_list.count; i++) {
|
||||
if (load_unified_service(ubus_ctx, unified_list.filenames[i], unified_list.paths[i]))
|
||||
BBFDM_ERR("Failed to load unified service: %s", unified_list.filenames[i]);
|
||||
}
|
||||
|
||||
file_list_free(&non_unified_list);
|
||||
file_list_free(&unified_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int register_services(struct ubus_context *ubus_ctx)
|
||||
{
|
||||
struct dirent **namelist;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ typedef struct service_entry {
|
|||
} service_entry_t;
|
||||
|
||||
int register_services(struct ubus_context *ctx);
|
||||
int register_suppress_services(struct ubus_context *ubus_ctx);
|
||||
void unregister_services(void);
|
||||
void list_registered_services(struct blob_buf *bb);
|
||||
void fill_service_schema(struct ubus_context *ubus_ctx, int ubus_timeout, const char *service_name, struct blob_buf **service_schema);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ static void usage(char *prog)
|
|||
fprintf(stderr, " -m <ms name> micro-service name\n");
|
||||
fprintf(stderr, " -l <loglevel> log verbosity value as per standard syslog\n");
|
||||
fprintf(stderr, " -d Display the schema data model supported by micro-service\n");
|
||||
fprintf(stderr, " -s Reduce memory usage of dm-services\n");
|
||||
fprintf(stderr, " -h Display this help\n");
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
|
@ -31,10 +32,11 @@ int main(int argc, char **argv)
|
|||
char proc_name[64] = {0};
|
||||
int log_level = LOG_ERR;
|
||||
int err = 0, ch, dm_type = 0;
|
||||
bool suppress = false;
|
||||
|
||||
memset(&bbfdm_ctx, 0, sizeof(struct bbfdm_context));
|
||||
|
||||
while ((ch = getopt(argc, argv, "hdl:m:")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "hdsl:m:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'm':
|
||||
bbfdm_ubus_set_service_name(&bbfdm_ctx, optarg);
|
||||
|
|
@ -49,6 +51,9 @@ int main(int argc, char **argv)
|
|||
case 'd':
|
||||
dm_type++;
|
||||
break;
|
||||
case 's':
|
||||
suppress = true;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
|
|
@ -63,7 +68,10 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
if (dm_type > 0) {
|
||||
int res = bbfdm_print_data_model_schema(&bbfdm_ctx, dm_type);
|
||||
int res = 0;
|
||||
if (suppress == false) {
|
||||
res = bbfdm_print_data_model_schema(&bbfdm_ctx, dm_type);
|
||||
}
|
||||
exit(res);
|
||||
}
|
||||
openlog(bbfdm_ctx.config.service_name, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
|
||||
|
|
@ -71,9 +79,15 @@ int main(int argc, char **argv)
|
|||
bbfdm_ubus_set_log_level(log_level);
|
||||
bbfdm_ubus_load_data_model(NULL);
|
||||
|
||||
err = bbfdm_ubus_register_init(&bbfdm_ctx);
|
||||
if (err != 0)
|
||||
goto exit;
|
||||
if (suppress == false) {
|
||||
err = bbfdm_ubus_register_init(&bbfdm_ctx);
|
||||
if (err != 0)
|
||||
goto exit;
|
||||
} else {
|
||||
err = bbfdm_ubus_register_suppress_init(&bbfdm_ctx);
|
||||
if (err != 0)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Create process name using service name and prefix "dm_"
|
||||
snprintf(proc_name, sizeof(proc_name), "dm_%s", bbfdm_ctx.config.service_name);
|
||||
|
|
|
|||
|
|
@ -40,3 +40,8 @@ FILE(GLOB libbbfdm-api_include_headers include/*.h)
|
|||
INSTALL(FILES ${libbbfdm-api_include_headers}
|
||||
DESTINATION usr/include
|
||||
)
|
||||
|
||||
FILE(GLOB libbbfdm-api_plugin_headers plugin/*.h)
|
||||
INSTALL(FILES ${libbbfdm-api_plugin_headers}
|
||||
DESTINATION usr/include/libbbfdm-api/legacy/plugin
|
||||
)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,25 @@
|
|||
#include "dmmem.h"
|
||||
#include "dmapi.h"
|
||||
|
||||
typedef struct bbfdm_config {
|
||||
struct list_head apply_handlers;
|
||||
char service_name[32]; // Service name for micro-service identification
|
||||
char in_name[128]; // Service plugin path
|
||||
char in_plugin_dir[128]; // Service extra/internal plugin directory path
|
||||
char out_name[128]; // Ubus name to use
|
||||
} bbfdm_config_t;
|
||||
|
||||
struct bbfdm_context {
|
||||
bbfdm_config_t config;
|
||||
struct ubus_event_handler apply_event;
|
||||
struct ubus_context *ubus_ctx;
|
||||
struct ubus_object ubus_obj;
|
||||
struct list_head event_handlers;
|
||||
struct list_head changed_uci;
|
||||
bool internal_ubus_ctx;
|
||||
char uci_change_proto[10];
|
||||
};
|
||||
|
||||
int get_number_of_entries(struct dmctx *ctx, void *data, char *instance, int (*browseinstobj)(struct dmctx *ctx, struct dmnode *node, void *data, char *instance)); // To be removed later!!!!!!!!!!!!
|
||||
|
||||
char *handle_instance(struct dmctx *dmctx, DMNODE *parent_node, struct uci_section *s, const char *inst_opt, const char *alias_opt);
|
||||
|
|
|
|||
|
|
@ -243,18 +243,18 @@ int bbf_entry_method(struct dmctx *ctx, int cmd)
|
|||
return bbf_fault_map(ctx, fault);
|
||||
}
|
||||
|
||||
void bbf_global_init(DMOBJ *dm_entryobj, const char *plugin_path)
|
||||
void bbf_global_init(DMOBJ *dm_entryobj, struct bbfdm_context *daemon_ctx, const char *plugin_path)
|
||||
{
|
||||
bbfdm_ensure_folder_exists(DATA_MODEL_DB_PATH);
|
||||
|
||||
dm_dynamic_initmem(&global_memhead);
|
||||
dm_ubus_cache_init();
|
||||
load_plugins(dm_entryobj, plugin_path);
|
||||
load_plugins(dm_entryobj, daemon_ctx, plugin_path);
|
||||
}
|
||||
|
||||
void bbf_global_clean(DMOBJ *dm_entryobj)
|
||||
void bbf_global_clean(DMOBJ *dm_entryobj, struct bbfdm_context *daemon_ctx)
|
||||
{
|
||||
free_plugins(dm_entryobj);
|
||||
free_plugins(dm_entryobj, daemon_ctx);
|
||||
dm_ubus_cache_free();
|
||||
dm_dynamic_cleanmem(&global_memhead);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ int bbf_fault_map(struct dmctx *ctx, int fault);
|
|||
|
||||
int bbf_entry_method(struct dmctx *ctx, int cmd);
|
||||
|
||||
void bbf_global_init(DMOBJ *dm_entryobj, const char *plugin_path);
|
||||
void bbf_global_clean(DMOBJ *dm_entryobj);
|
||||
void bbf_global_init(DMOBJ *dm_entryobj, struct bbfdm_context *daemon_ctx, const char *plugin_path);
|
||||
void bbf_global_clean(DMOBJ *dm_entryobj, struct bbfdm_context *daemon_ctx);
|
||||
|
||||
int dm_validate_allowed_objects(struct dmctx *ctx, struct dm_reference *reference, char *objects[]);
|
||||
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ static void dm_check_dynamic_obj(struct list_head *mem_list, DMNODE *parent_node
|
|||
|
||||
if (parent_node->obj) {
|
||||
if (parent_node->obj->nextdynamicobj) {
|
||||
for (int i = 0; i < __INDX_DYNAMIC_MAX - 1; i++) {
|
||||
for (int i = 0; i < __INDX_DYNAMIC_MAX; i++) {
|
||||
struct dm_dynamic_obj *next_dyn_array = parent_node->obj->nextdynamicobj + i;
|
||||
if (next_dyn_array->nextobj) {
|
||||
for (int j = 0; next_dyn_array->nextobj[j]; j++) {
|
||||
|
|
@ -231,7 +231,7 @@ static int compare(const struct dirent **a, const struct dirent **b)
|
|||
return strcasecmp((*a)->d_name, (*b)->d_name);
|
||||
}
|
||||
|
||||
void load_plugins(DMOBJ *dm_entryobj, const char *plugin_path)
|
||||
void load_plugins(DMOBJ *dm_entryobj, struct bbfdm_context *daemon_ctx, const char *plugin_path)
|
||||
{
|
||||
struct dirent **namelist;
|
||||
|
||||
|
|
@ -253,7 +253,7 @@ void load_plugins(DMOBJ *dm_entryobj, const char *plugin_path)
|
|||
if (DM_LSTRSTR(namelist[i]->d_name, ".json")) {
|
||||
load_json_plugins(dm_entryobj, file_path);
|
||||
} else if (DM_LSTRSTR(namelist[i]->d_name, ".so")) {
|
||||
load_dotso_plugins(dm_entryobj, file_path);
|
||||
load_dotso_plugins(dm_entryobj, daemon_ctx, file_path);
|
||||
}
|
||||
|
||||
FREE(namelist[i]);
|
||||
|
|
@ -262,10 +262,10 @@ void load_plugins(DMOBJ *dm_entryobj, const char *plugin_path)
|
|||
FREE(namelist);
|
||||
}
|
||||
|
||||
void free_plugins(DMOBJ *dm_entryobj)
|
||||
void free_plugins(DMOBJ *dm_entryobj, struct bbfdm_context *daemon_ctx)
|
||||
{
|
||||
free_all_dynamic_nodes(dm_entryobj);
|
||||
|
||||
free_json_plugins();
|
||||
free_dotso_plugins();
|
||||
free_dotso_plugins(daemon_ctx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
#ifndef __DMPLUGIN_H__
|
||||
#define __DMPLUGIN_H__
|
||||
|
||||
#include "dmbbf.h"
|
||||
|
||||
DMOBJ *find_entry_obj(DMOBJ *entryobj, const char *obj_path);
|
||||
|
||||
void disable_entry_obj(DMOBJ *entryobj, const char *obj_path, const char *parent_obj, const char *plugin_path);
|
||||
|
|
@ -21,7 +23,7 @@ int get_entry_leaf_idx(DMLEAF *entryleaf);
|
|||
int get_obj_idx(DMOBJ **entryobj);
|
||||
int get_leaf_idx(DMLEAF **entryleaf);
|
||||
|
||||
void load_plugins(DMOBJ *dm_entryobj, const char *plugin_path);
|
||||
void free_plugins(DMOBJ *dm_entryobj);
|
||||
void load_plugins(DMOBJ *dm_entryobj, struct bbfdm_context *daemon_ctx, const char *plugin_path);
|
||||
void free_plugins(DMOBJ *dm_entryobj, struct bbfdm_context *daemon_ctx);
|
||||
|
||||
#endif //__DMPLUGIN_H__
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ static void add_list_loaded_libraries(struct list_head *library_list, void *libr
|
|||
lib->library = library;
|
||||
}
|
||||
|
||||
static void free_all_list_open_library(struct list_head *library_list)
|
||||
static void free_all_list_open_library(struct list_head *library_list, struct bbfdm_context *daemon_ctx)
|
||||
{
|
||||
struct loaded_library *lib = NULL, *tmp = NULL;
|
||||
|
||||
|
|
@ -40,6 +40,19 @@ static void free_all_list_open_library(struct list_head *library_list)
|
|||
list_del(&lib->list);
|
||||
|
||||
if (lib->library) {
|
||||
DM_MAP_OBJ *dynamic_obj = NULL;
|
||||
|
||||
//Dynamic Object
|
||||
*(void **) (&dynamic_obj) = dlsym(lib->library, "tDynamicObj");
|
||||
|
||||
if (dynamic_obj) {
|
||||
// Clean module
|
||||
for (int i = 0; dynamic_obj[i].path; i++) {
|
||||
if (dynamic_obj[i].clean_module)
|
||||
dynamic_obj[i].clean_module(daemon_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
dlclose(lib->library);
|
||||
lib->library = NULL;
|
||||
}
|
||||
|
|
@ -60,7 +73,7 @@ static void dotso_plugin_disable_requested_entries(DMOBJ *entryobj, DMOBJ *reque
|
|||
disable_entry_leaf(entryobj, requested_leaf->parameter, parent_obj, plugin_path);
|
||||
}
|
||||
|
||||
int load_dotso_plugins(DMOBJ *entryobj, const char *plugin_path)
|
||||
int load_dotso_plugins(DMOBJ *entryobj, struct bbfdm_context *daemon_ctx, const char *plugin_path)
|
||||
{
|
||||
void *handle = dlopen(plugin_path, RTLD_NOW|RTLD_LOCAL);
|
||||
if (!handle) {
|
||||
|
|
@ -130,15 +143,38 @@ int load_dotso_plugins(DMOBJ *entryobj, const char *plugin_path)
|
|||
}
|
||||
|
||||
if (dynamic_obj[i].init_module)
|
||||
dynamic_obj[i].init_module(NULL);
|
||||
dynamic_obj[i].init_module(daemon_ctx);
|
||||
}
|
||||
add_list_loaded_libraries(&loaded_library_list, handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int free_dotso_plugins(void)
|
||||
int free_dotso_plugins(struct bbfdm_context *daemon_ctx)
|
||||
{
|
||||
free_all_list_open_library(&loaded_library_list);
|
||||
free_all_list_open_library(&loaded_library_list, daemon_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void perform_dotso_plugin_sync(struct bbfdm_context *bbfdm_ctx)
|
||||
{
|
||||
struct loaded_library *lib = NULL;
|
||||
struct list_head *library_list = &loaded_library_list;
|
||||
|
||||
list_for_each_entry(lib, library_list, list) {
|
||||
if (lib->library) {
|
||||
DM_MAP_OBJ *dynamic_obj = NULL;
|
||||
|
||||
//Dynamic Object
|
||||
*(void **) (&dynamic_obj) = dlsym(lib->library, "tDynamicObj");
|
||||
|
||||
if (dynamic_obj) {
|
||||
// Clean module
|
||||
for (int i = 0; dynamic_obj[i].path; i++) {
|
||||
if (dynamic_obj[i].uci_sync_handler)
|
||||
dynamic_obj[i].uci_sync_handler(bbfdm_ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@
|
|||
|
||||
#include "../dmcommon.h"
|
||||
|
||||
int load_dotso_plugins(DMOBJ *entryobj, const char *path);
|
||||
int free_dotso_plugins(void);
|
||||
int load_dotso_plugins(DMOBJ *entryobj, struct bbfdm_context *daemon_ctx, const char *path);
|
||||
int free_dotso_plugins(struct bbfdm_context *daemon_ctx);
|
||||
void perform_dotso_plugin_sync(struct bbfdm_context *bbfdm_ctx);
|
||||
|
||||
#endif //__DOTSO_PLUGIN_H__
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
// Global variables
|
||||
static void *deamon_lib_handle = NULL;
|
||||
static uint8_t s_log_level = 0xff;
|
||||
struct list_head supp_modules;
|
||||
|
||||
static void bbfdm_ctx_init(struct bbfdm_context *bbfdm_ctx)
|
||||
{
|
||||
|
|
@ -46,7 +47,7 @@ static void bbfdm_ctx_init(struct bbfdm_context *bbfdm_ctx)
|
|||
|
||||
static void bbfdm_ctx_cleanup(struct bbfdm_context *u)
|
||||
{
|
||||
bbf_global_clean(DEAMON_DM_ROOT_OBJ);
|
||||
bbf_global_clean(DEAMON_DM_ROOT_OBJ, u);
|
||||
|
||||
/* DotSo Plugin */
|
||||
bbfdm_free_dotso_plugin(u, &deamon_lib_handle);
|
||||
|
|
@ -659,21 +660,13 @@ static void free_changed_uci(struct bbfdm_context *bbfdm_ctx)
|
|||
}
|
||||
}
|
||||
|
||||
static int load_apply_handlers_from_file(bbfdm_config_t *config)
|
||||
static int read_apply_handlers_config(const char *serv_config, bbfdm_config_t *config, bool suppress)
|
||||
{
|
||||
char serv_config[MAX_DM_PATH] = {0};
|
||||
|
||||
if (config == NULL) {
|
||||
BBF_ERR("bbfdm_config is null");
|
||||
if (DM_STRLEN(serv_config) == 0) {
|
||||
BBF_ERR("No json file name received");
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(serv_config, sizeof(serv_config), "%s/%s.json", BBFDM_SERVICE_CONFIG_PATH, config->service_name);
|
||||
if (!bbfdm_file_exists(serv_config) || !bbfdm_is_regular_file(serv_config)) {
|
||||
BBF_ERR("Config file %s not exists for service %s", serv_config, config->service_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
json_object *json_root = json_object_from_file(serv_config);
|
||||
if (!json_root) {
|
||||
BBF_ERR("Failed to read json file %s", serv_config);
|
||||
|
|
@ -688,6 +681,56 @@ static int load_apply_handlers_from_file(bbfdm_config_t *config)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (suppress == true) {
|
||||
json_object *unified_daemon = NULL;
|
||||
|
||||
json_object_object_get_ex(daemon_config, "unified_daemon", &unified_daemon);
|
||||
if (!unified_daemon) {
|
||||
json_object_put(json_root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool is_unified = json_object_get_boolean(unified_daemon);
|
||||
if (is_unified == true) {
|
||||
json_object_put(json_root);
|
||||
return 0;
|
||||
} else {
|
||||
char *tmp = strrchr(serv_config, '/');
|
||||
if (tmp == NULL) {
|
||||
BBFDM_ERR("Failed to extract service name for %s", serv_config);
|
||||
json_object_put(json_root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *serv = tmp + 1;
|
||||
char serv_name[64] = {0};
|
||||
|
||||
snprintf(serv_name, sizeof(serv_name), "%s", serv);
|
||||
|
||||
int len = strlen(serv_name);
|
||||
tmp = serv_name + len - 5;
|
||||
if (strcmp(tmp, ".json") != 0) {
|
||||
BBFDM_ERR("Service file %s is not ending with .json", serv_config);
|
||||
json_object_put(json_root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*tmp = '\0';
|
||||
|
||||
// store this service name
|
||||
struct supp_module_node *supp_node = (struct supp_module_node *)calloc(1, sizeof(struct supp_module_node));
|
||||
if (supp_node == NULL) {
|
||||
BBFDM_ERR("Failed to allocate memory for service file %s", serv_config);
|
||||
json_object_put(json_root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&supp_node->list);
|
||||
list_add_tail(&supp_node->list, &supp_modules);
|
||||
supp_node->service = strdup(serv_name);
|
||||
}
|
||||
}
|
||||
|
||||
json_object *apply_handler = NULL;
|
||||
json_object_object_get_ex(daemon_config, "apply_handler", &apply_handler);
|
||||
if (!apply_handler) {
|
||||
|
|
@ -756,6 +799,60 @@ static int load_apply_handlers_from_file(bbfdm_config_t *config)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int load_apply_handlers_from_file(bbfdm_config_t *config, bool suppress)
|
||||
{
|
||||
char serv_config[MAX_DM_PATH] = {0};
|
||||
|
||||
if (config == NULL) {
|
||||
BBF_ERR("bbfdm_config is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(serv_config, sizeof(serv_config), "%s/%s.json", BBFDM_SERVICE_CONFIG_PATH, config->service_name);
|
||||
if (!bbfdm_file_exists(serv_config) || !bbfdm_is_regular_file(serv_config)) {
|
||||
BBF_ERR("Config file %s not exists for service %s", serv_config, config->service_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (read_apply_handlers_config(serv_config, config, suppress) != 0) {
|
||||
BBF_ERR("Failed to read apply handlers for service file %s", serv_config);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (suppress == true) {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
dir = opendir(BBFDM_SERVICE_CONFIG_PATH);
|
||||
if (!dir) {
|
||||
BBF_ERR("Failed to open service directory %s", BBFDM_SERVICE_CONFIG_PATH);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
/* Match only regular files ending in .json */
|
||||
char plug_config[MAX_DM_PATH] = {0};
|
||||
|
||||
size_t len = strlen(entry->d_name);
|
||||
if (len < 5 || strcmp(entry->d_name + len - 5, ".json") != 0)
|
||||
continue;
|
||||
|
||||
snprintf(plug_config, sizeof(plug_config), "%s/%s", BBFDM_SERVICE_CONFIG_PATH, entry->d_name);
|
||||
if (!bbfdm_is_regular_file(plug_config) || DM_STRCMP(serv_config, plug_config) == 0)
|
||||
continue;
|
||||
|
||||
if (read_apply_handlers_config(plug_config, config, suppress) != 0) {
|
||||
BBF_ERR("Failed to read apply handlers for service file %s", plug_config);
|
||||
closedir(dir);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_micro_service_config(bbfdm_config_t *config)
|
||||
{
|
||||
char opt_val[MAX_DM_PATH] = {0};
|
||||
|
|
@ -765,7 +862,7 @@ static int load_micro_service_config(bbfdm_config_t *config)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (load_apply_handlers_from_file(config) != 0) {
|
||||
if (load_apply_handlers_from_file(config, false) != 0) {
|
||||
BBF_ERR("Failed to load handlers from service file");
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -794,6 +891,103 @@ static int load_micro_service_config(bbfdm_config_t *config)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int load_micro_service_suppress_config(bbfdm_config_t *config)
|
||||
{
|
||||
char opt_val[MAX_DM_PATH] = {0};
|
||||
|
||||
if (!config || strlen(config->service_name) == 0) {
|
||||
BBF_ERR("Invalid input options for service name");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (load_apply_handlers_from_file(config, true) != 0) {
|
||||
BBF_ERR("Failed to load handlers from service file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (INTERNAL_ROOT_TREE == NULL) {
|
||||
// This API will only be called with micro-services started with '-m' option
|
||||
|
||||
snprintf(opt_val, MAX_DM_PATH, "%s/%s.so", BBFDM_DEFAULT_MICROSERVICE_MODULE_PATH, config->service_name);
|
||||
if (!file_exists(opt_val)) {
|
||||
snprintf(opt_val, MAX_DM_PATH, "%s/%s.json", BBFDM_DEFAULT_MICROSERVICE_MODULE_PATH, config->service_name);
|
||||
}
|
||||
|
||||
if (!file_exists(opt_val)) {
|
||||
BBF_ERR("Failed to load service plugin %s opt_val=%s", config->service_name, opt_val);
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpyt(config->in_name, opt_val, sizeof(config->in_name));
|
||||
}
|
||||
|
||||
snprintf(opt_val, MAX_DM_PATH, "%s/%s", BBFDM_DEFAULT_MICROSERVICE_MODULE_PATH, config->service_name);
|
||||
if (folder_exists(opt_val)) {
|
||||
strncpyt(config->in_plugin_dir, opt_val, sizeof(config->in_plugin_dir));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_micro_service_suppress_data_model(struct bbfdm_context *daemon_ctx)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (INTERNAL_ROOT_TREE) {
|
||||
BBF_INFO("Loading Data Model Internal plugin (%s)", daemon_ctx->config.service_name);
|
||||
err = bbfdm_load_internal_plugin(daemon_ctx, INTERNAL_ROOT_TREE, &DEAMON_DM_ROOT_OBJ);
|
||||
} else {
|
||||
BBF_INFO("Loading Data Model External plugin (%s)", daemon_ctx->config.service_name);
|
||||
err = bbfdm_load_external_plugin(daemon_ctx, &deamon_lib_handle, &DEAMON_DM_ROOT_OBJ);
|
||||
}
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
BBF_INFO("Loading sub-modules %s", daemon_ctx->config.in_plugin_dir);
|
||||
bbf_global_init(DEAMON_DM_ROOT_OBJ, daemon_ctx, daemon_ctx->config.in_plugin_dir);
|
||||
|
||||
// Load suppressed dm
|
||||
struct supp_module_node *node = NULL;
|
||||
list_for_each_entry(node, &supp_modules, list) {
|
||||
if (DM_STRCMP(daemon_ctx->config.service_name, node->service) == 0) {
|
||||
// Base service dmtree is already loaded so skip it
|
||||
continue;
|
||||
}
|
||||
|
||||
char opt_val[MAX_DM_PATH] = {0};
|
||||
|
||||
snprintf(opt_val, MAX_DM_PATH, "%s/%s.so", BBFDM_DEFAULT_MICROSERVICE_MODULE_PATH, node->service);
|
||||
if (!file_exists(opt_val)) {
|
||||
snprintf(opt_val, MAX_DM_PATH, "%s/%s.json", BBFDM_DEFAULT_MICROSERVICE_MODULE_PATH, node->service);
|
||||
}
|
||||
|
||||
if (!file_exists(opt_val)) {
|
||||
BBF_ERR("Failed to load service plugin %s opt_val=%s", node->service, opt_val);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DM_LSTRSTR(opt_val, ".json")) {
|
||||
load_json_plugins(DEAMON_DM_ROOT_OBJ, opt_val);
|
||||
} else if (DM_LSTRSTR(opt_val, ".so")) {
|
||||
load_dotso_plugins(DEAMON_DM_ROOT_OBJ, daemon_ctx, opt_val);
|
||||
}
|
||||
|
||||
char supp_plug_dir[MAX_DM_PATH] = {0};
|
||||
snprintf(supp_plug_dir, MAX_DM_PATH, "%s/%s", BBFDM_DEFAULT_MICROSERVICE_MODULE_PATH, node->service);
|
||||
if (folder_exists(supp_plug_dir)) {
|
||||
load_plugins(DEAMON_DM_ROOT_OBJ, daemon_ctx, supp_plug_dir);
|
||||
}
|
||||
}
|
||||
|
||||
if (DM_STRLEN(daemon_ctx->config.out_name) == 0) {
|
||||
BBF_ERR("output name not defined");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_micro_service_data_model(struct bbfdm_context *daemon_ctx)
|
||||
{
|
||||
int err = 0;
|
||||
|
|
@ -810,7 +1004,7 @@ static int load_micro_service_data_model(struct bbfdm_context *daemon_ctx)
|
|||
return err;
|
||||
|
||||
BBF_INFO("Loading sub-modules %s", daemon_ctx->config.in_plugin_dir);
|
||||
bbf_global_init(DEAMON_DM_ROOT_OBJ, daemon_ctx->config.in_plugin_dir);
|
||||
bbf_global_init(DEAMON_DM_ROOT_OBJ, daemon_ctx, daemon_ctx->config.in_plugin_dir);
|
||||
|
||||
if (DM_STRLEN(daemon_ctx->config.out_name) == 0) {
|
||||
BBF_ERR("output name not defined");
|
||||
|
|
@ -897,6 +1091,9 @@ static void perform_uci_sync_op(struct bbfdm_context *bbfdm_ctx)
|
|||
}
|
||||
}
|
||||
|
||||
// Now execute sync handlers of loaded plugins
|
||||
perform_dotso_plugin_sync(bbfdm_ctx);
|
||||
|
||||
free_changed_uci(bbfdm_ctx);
|
||||
|
||||
if (bbfdm_refresh_references(BBFDM_BOTH, bbfdm_ctx->config.out_name)) {
|
||||
|
|
@ -1056,6 +1253,66 @@ int bbfdm_ubus_register_init(struct bbfdm_context *bbfdm_ctx)
|
|||
return register_events_to_ubus(bbfdm_ctx->ubus_ctx, &bbfdm_ctx->event_handlers);
|
||||
}
|
||||
|
||||
int bbfdm_ubus_register_suppress_init(struct bbfdm_context *bbfdm_ctx)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
// Set the logmask with default, if not already set by api
|
||||
if (s_log_level == 0xff) {
|
||||
BBF_INFO("Log level not set, setting default value %d", LOG_ERR);
|
||||
bbfdm_ubus_set_log_level(LOG_ERR);
|
||||
}
|
||||
|
||||
if (bbfdm_ctx->ubus_ctx == NULL) {
|
||||
err = bbfdm_ubus_init(bbfdm_ctx);
|
||||
if (err) {
|
||||
BBF_ERR("Failed to initialize ubus_ctx internally");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
bbfdm_ctx_init(bbfdm_ctx);
|
||||
|
||||
INIT_LIST_HEAD(&supp_modules);
|
||||
|
||||
err = load_micro_service_suppress_config(&bbfdm_ctx->config);
|
||||
if (err) {
|
||||
BBF_ERR("Failed to load micro-service config");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = load_micro_service_suppress_data_model(bbfdm_ctx);
|
||||
if (err) {
|
||||
BBF_ERR("Failed to load micro-service data model");
|
||||
return err;
|
||||
}
|
||||
|
||||
struct supp_module_node *node = NULL, *tmp = NULL;
|
||||
list_for_each_entry_safe(node, tmp, &supp_modules, list) {
|
||||
list_del(&node->list);
|
||||
BBFDM_FREE(node->service);
|
||||
BBFDM_FREE(node);
|
||||
}
|
||||
|
||||
err = regiter_ubus_object(bbfdm_ctx);
|
||||
if (err != UBUS_STATUS_OK)
|
||||
return -1;
|
||||
|
||||
err = bbfdm_refresh_references(BBFDM_BOTH, bbfdm_ctx->config.out_name);
|
||||
if (err) {
|
||||
BBF_ERR("Failed to refresh instance data base");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = register_bbfdm_apply_event(bbfdm_ctx);
|
||||
if (err) {
|
||||
BBF_ERR("Failed to register bbfdm apply event");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return register_events_to_ubus(bbfdm_ctx->ubus_ctx, &bbfdm_ctx->event_handlers);
|
||||
}
|
||||
|
||||
int bbfdm_ubus_register_free(struct bbfdm_context *bbfdm_ctx)
|
||||
{
|
||||
if (bbfdm_ctx->ubus_ctx) {
|
||||
|
|
|
|||
|
|
@ -6,9 +6,17 @@
|
|||
#include <libubox/list.h>
|
||||
|
||||
#include "libbbfdm-api/legacy/dmbbf.h"
|
||||
#include "libbbfdm-api/legacy/dmplugin.h"
|
||||
#include "libbbfdm-api/legacy/plugin/json_plugin.h"
|
||||
#include "libbbfdm-api/legacy/plugin/dotso_plugin.h"
|
||||
|
||||
#define BBFDM_DEFAULT_UBUS_OBJ "bbfdm"
|
||||
|
||||
struct supp_module_node {
|
||||
char *service;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct bbfdm_async_req {
|
||||
struct ubus_context *ctx;
|
||||
struct ubus_request_data req;
|
||||
|
|
@ -21,25 +29,6 @@ struct apply_handler_node {
|
|||
struct list_head list;
|
||||
};
|
||||
|
||||
typedef struct bbfdm_config {
|
||||
struct list_head apply_handlers;
|
||||
char service_name[32]; // Service name for micro-service identification
|
||||
char in_name[128]; // Service plugin path
|
||||
char in_plugin_dir[128]; // Service extra/internal plugin directory path
|
||||
char out_name[128]; // Ubus name to use
|
||||
} bbfdm_config_t;
|
||||
|
||||
struct bbfdm_context {
|
||||
bbfdm_config_t config;
|
||||
struct ubus_event_handler apply_event;
|
||||
struct ubus_context *ubus_ctx;
|
||||
struct ubus_object ubus_obj;
|
||||
struct list_head event_handlers;
|
||||
struct list_head changed_uci;
|
||||
bool internal_ubus_ctx;
|
||||
char uci_change_proto[10];
|
||||
};
|
||||
|
||||
typedef struct bbfdm_data {
|
||||
struct ubus_context *ctx;
|
||||
struct ubus_object *obj;
|
||||
|
|
@ -50,6 +39,7 @@ typedef struct bbfdm_data {
|
|||
} bbfdm_data_t;
|
||||
|
||||
int bbfdm_ubus_register_init(struct bbfdm_context *bbfdm_ctx);
|
||||
int bbfdm_ubus_register_suppress_init(struct bbfdm_context *bbfdm_ctx);
|
||||
int bbfdm_ubus_register_free(struct bbfdm_context *bbfdm_ctx);
|
||||
|
||||
__attribute__((deprecated("Use bbfdm_ubus_register_init() instead of bbfdm_ubus_regiter_init()")))
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@ PROJECT(libbbfdm)
|
|||
ADD_DEFINITIONS(-Wall -Werror -g3 -D_GNU_SOURCE -DBBF_VENDOR_PREFIX="${BBF_VENDOR_PREFIX}")
|
||||
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SOURCE_DIR} -I${CMAKE_CURRENT_SOURCE_DIR} -I${CMAKE_SOURCE_DIR}/libbbfdm-api/version-2")
|
||||
|
||||
if (BBFDM_DM_SERVICE_RAM_OPTIMIZED)
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DBBFDM_DM_SERVICE_RAM_OPTIMIZED")
|
||||
endif()
|
||||
|
||||
FILE(GLOB BBF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.c)
|
||||
|
||||
ADD_LIBRARY(core SHARED ${BBF_SOURCES})
|
||||
|
|
|
|||
|
|
@ -126,6 +126,9 @@ DMOBJ tDMRootObj[] = {
|
|||
{"LANConfigSecurity", &DMREAD, NULL, NULL, "file:/etc/config/users", NULL, NULL, NULL, NULL, tLANConfigSecurityParams, NULL, BBFDM_BOTH},
|
||||
{"Schedules", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tSchedulesObj, tSchedulesParams, NULL, BBFDM_BOTH},
|
||||
{"Security", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tSecurityObj, tSecurityParams, NULL, BBFDM_CWMP},
|
||||
#ifdef BBFDM_DM_SERVICE_RAM_OPTIMIZED
|
||||
{"Services", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, BBFDM_BOTH},
|
||||
#endif
|
||||
{0}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -42,13 +42,13 @@ static int teardown_commit(void **state)
|
|||
|
||||
static int group_init(void **state)
|
||||
{
|
||||
bbf_global_init(TR181_ROOT_TREE, "/usr/share/bbfdm/micro_services/core");
|
||||
bbf_global_init(TR181_ROOT_TREE, NULL, "/usr/share/bbfdm/micro_services/core");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int group_teardown(void **state)
|
||||
{
|
||||
bbf_global_clean(TR181_ROOT_TREE);
|
||||
bbf_global_clean(TR181_ROOT_TREE, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,13 +54,13 @@ static int teardown_revert(void **state)
|
|||
|
||||
static int group_init(void **state)
|
||||
{
|
||||
bbf_global_init(TR181_ROOT_TREE, "/usr/share/bbfdm/micro_services/core");
|
||||
bbf_global_init(TR181_ROOT_TREE, NULL, "/usr/share/bbfdm/micro_services/core");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int group_teardown(void **state)
|
||||
{
|
||||
bbf_global_clean(TR181_ROOT_TREE);
|
||||
bbf_global_clean(TR181_ROOT_TREE, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue