bbfdm: Add support to expose DotSO and JSON plugins

This commit is contained in:
Amin Ben Romdhane 2023-05-07 22:08:52 +02:00
parent 8d332f9efa
commit bd07a43337
26 changed files with 435 additions and 89 deletions

View file

@ -83,8 +83,9 @@ Below is an example of json file:
}
}
```
> NOTE1: `bbfdmd` CLI mode is an experimentation feature and it can be updated later.
> NOTE: If `-I` option is not passed when starting `bbfdmd`, so configuration options will be loaded from the default [INPUT.JSON](../../json/input.json) located in '/etc/bbfdm/input.json'.
> NOTE2: If `-I` option is not passed when starting `bbfdmd`, so configuration options will be loaded from the default [INPUT.JSON](../../json/input.json) located in '/etc/bbfdm/input.json'.
* To see a list of arguments supported by `bbfdmd` use:

View file

@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.0)
PROJECT(bbfdmd)
ADD_DEFINITIONS(-fstrict-aliasing -Wall -Wextra -Werror -Wformat -Wformat-signedness -fPIC -D_GNU_SOURCE)
ADD_DEFINITIONS(-DBBF_VENDOR_PREFIX="${BBF_VENDOR_PREFIX}")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SOURCE_DIR}")
@ -12,6 +13,6 @@ ENDIF()
FILE(GLOB BBF_SOURCES *.c)
ADD_EXECUTABLE(bbfdmd ${BBF_SOURCES})
TARGET_LINK_LIBRARIES(bbfdmd ubus ubox blobmsg_json bbfdm-api bbfdm)
TARGET_LINK_LIBRARIES(bbfdmd ubus ubox blobmsg_json dl bbfdm-api)
INSTALL(TARGETS bbfdmd DESTINATION usr/sbin)
INSTALL(FILES ../../json/input.json DESTINATION etc/bbfdm)

View file

@ -39,10 +39,15 @@
#include "events.h"
#include "pretty_print.h"
#include "get_helper.h"
#include "plugin.h"
#include "cli.h"
#include "libbbfdm-api/dmentry.h"
#include "libbbfdm-api/dmjson.h"
extern struct list_head loaded_json_files;
extern struct list_head json_list;
extern struct list_head json_memhead;
#define USP_SUBPROCESS_DEPTH (2)
#define BBF_SCHEMA_UPDATE_TIMEOUT (60 * 1000)
#define BBF_INSTANCES_UPDATE_TIMEOUT (25 * 1000)
@ -52,6 +57,10 @@
// Global variables
static unsigned int g_refresh_time = BBF_INSTANCES_UPDATE_TIMEOUT;
static int g_subprocess_level = USP_SUBPROCESS_DEPTH;
static void *deamon_lib_handle = NULL;
char UBUS_METHOD_NAME[32] = "bbfdm";
bool enable_plugins = true;
static void sig_handler(int sig)
{
@ -84,7 +93,8 @@ static void usp_cleanup(struct usp_context *u)
{
free_path_list(&u->instances);
free_path_list(&u->old_instances);
bbf_global_clean(DM_ROOT_OBJ);
bbf_global_clean(DEAMON_DM_ROOT_OBJ);
free_dotso_plugin(deamon_lib_handle);
}
static bool is_sync_operate_cmd(usp_data_t *data __attribute__((unused)))
@ -134,6 +144,8 @@ static void fill_optional_data(usp_data_t *data, struct blob_attr *msg)
data->is_raw = is_str_eq(blobmsg_get_string(attr), "raw") ? true : false;
}
data->bbf_ctx.enable_plugins = enable_plugins;
DEBUG("Proto:|%s|, Inst Mode:|%s|, Tran-id:|%d|, Format:|%s|",
(data->bbf_ctx.dm_type == BBFDM_BOTH) ? "both" : (data->bbf_ctx.dm_type == BBFDM_CWMP) ? "cwmp" : "usp",
(data->bbf_ctx.instance_mode == 0) ? "Number" : "Alias",
@ -919,7 +931,11 @@ static int usp_notify_event(struct ubus_context *ctx, struct ubus_object *obj,
INFO("ubus method|%s|, name|%s|", method, obj->name);
event_name = blobmsg_get_string(tb[BBF_NOTIFY_NAME]);
if (is_registered_event(event_name)) {
ubus_send_event(ctx, BBF_EVENT, msg);
char method_name[40] = {0};
snprintf(method_name, sizeof(method_name), "%s.%s", UBUS_METHOD_NAME, BBF_EVENT);
ubus_send_event(ctx, method_name, msg);
} else {
WARNING("Event %s not registered", event_name);
}
@ -939,10 +955,10 @@ static struct ubus_method bbf_methods[] = {
UBUS_METHOD("notify_event", usp_notify_event, dm_notify_event_policy),
};
static struct ubus_object_type bbf_type = UBUS_OBJECT_TYPE(METHOD_NAME, bbf_methods);
static struct ubus_object_type bbf_type = UBUS_OBJECT_TYPE(UBUS_METHOD_NAME, bbf_methods);
static struct ubus_object bbf_object = {
.name = METHOD_NAME,
.name = UBUS_METHOD_NAME,
.type = &bbf_type,
.methods = bbf_methods,
.n_methods = ARRAY_SIZE(bbf_methods)
@ -974,7 +990,7 @@ static void periodic_schema_updater(struct uloop_timeout *t)
INFO("Schema update available");
blob_buf_init(&bb, 0);
blobmsg_add_string(&bb, "action", "schema_update_available");
ubus_notify(&u->ubus_ctx, &bbf_object, METHOD_NAME, bb.head, 1000);
ubus_notify(&u->ubus_ctx, &bbf_object, UBUS_METHOD_NAME, bb.head, 1000);
blob_buf_free(&bb);
}
@ -988,6 +1004,7 @@ static void broadcast_add_del_event(struct list_head *inst, bool is_add)
struct ubus_context ctx;
struct blob_buf bb;
struct pathNode *ptr;
char method_name[40];
void *a;
int ret;
@ -1011,10 +1028,12 @@ static void broadcast_add_del_event(struct list_head *inst, bool is_add)
}
blobmsg_close_array(&bb, a);
snprintf(method_name, sizeof(method_name), "%s.%s", UBUS_METHOD_NAME, is_add ? BBF_ADD_EVENT : BBF_DEL_EVENT);
if (is_add)
ubus_send_event(&ctx, BBF_ADD_EVENT, bb.head);
ubus_send_event(&ctx, method_name, bb.head);
else
ubus_send_event(&ctx, BBF_DEL_EVENT, bb.head);
ubus_send_event(&ctx, method_name, bb.head);
blob_buf_free(&bb);
ubus_shutdown(&ctx);
@ -1025,6 +1044,7 @@ static void update_instances_list(struct list_head *inst)
struct dmctx bbf_ctx = {
.in_param = ROOT_NODE,
.nextlevel = false,
.enable_plugins = enable_plugins,
.instance_mode = INSTANCE_MODE_NUMBER,
.dm_type = BBFDM_USP
};
@ -1165,43 +1185,79 @@ static void periodic_instance_updater(struct uloop_timeout *t)
fork_instance_checker(u);
}
static int bbfdm_load_config(const char *json_path)
static int bbfdm_load_deamon_config(const char *json_path)
{
json_object *json_obj = NULL;
char *opt_val = NULL;
int err = 0;
if (!json_path || !strlen(json_path))
return -1;
json_obj = json_object_from_file(json_path);
json_object *json_obj = json_object_from_file(json_path);
if (!json_obj)
return -1;
opt_val = dmjson_get_value(json_obj, 3, "daemon", "config", "loglevel");
json_object *deamon_obj = dmjson_get_obj(json_obj, 1, "daemon");
if (!deamon_obj) {
err = -1;
goto exit;
}
opt_val = dmjson_get_value(deamon_obj, 2, "config", "loglevel");
if (opt_val && strlen(opt_val)) {
uint8_t log_level = (uint8_t) strtoul(opt_val, NULL, 10);
set_debug_level(log_level);
}
opt_val = dmjson_get_value(json_obj, 3, "daemon", "config", "refresh_time");
opt_val = dmjson_get_value(deamon_obj, 2, "config", "refresh_time");
if (opt_val && strlen(opt_val)) {
unsigned int refresh_time = (unsigned int) strtoul(opt_val, NULL, 10);
g_refresh_time = refresh_time * 1000;
}
opt_val = dmjson_get_value(json_obj, 3, "daemon", "config", "transaction_timeout");
opt_val = dmjson_get_value(deamon_obj, 2, "config", "transaction_timeout");
if (opt_val && strlen(opt_val)) {
int trans_timeout = (int) strtol(opt_val, NULL, 10);
configure_transaction_timeout(trans_timeout);
}
opt_val = dmjson_get_value(json_obj, 3, "daemon", "config", "subprocess_level");
opt_val = dmjson_get_value(deamon_obj, 2, "config", "subprocess_level");
if (opt_val && strlen(opt_val)) {
g_subprocess_level = (unsigned int) strtoul(opt_val, NULL, 10);
}
opt_val = dmjson_get_value(deamon_obj, 2, "config", "enable_plugins");
if (opt_val && strlen(opt_val)) {
enable_plugins = (unsigned int) strtoul(opt_val, NULL, 10);
}
opt_val = dmjson_get_value(deamon_obj, 2, "output", "name");
if (opt_val && strlen(opt_val)) {
strncpyt(UBUS_METHOD_NAME, opt_val, sizeof(UBUS_METHOD_NAME));
}
opt_val = dmjson_get_value(deamon_obj, 2, "input", "type");
if (opt_val && strlen(opt_val)) {
char *file_path = dmjson_get_value(deamon_obj, 2, "input", "name");
if (strcasecmp(opt_val, "JSON") == 0)
err= load_json_plugin(&loaded_json_files, &json_list, &json_memhead, file_path,
&DEAMON_DM_ROOT_OBJ);
else if (strcasecmp(opt_val, "DotSo") == 0)
err = load_dotso_plugin(&deamon_lib_handle, file_path,
&DEAMON_DM_ROOT_OBJ,
DEAMON_DM_VENDOR_EXTENSION,
&DEAMON_DM_VENDOR_EXTENSION_EXCLUDE);
else
err = -1;
} else {
err = -1;
}
exit:
json_object_put(json_obj);
return 0;
return err;
}
static int usp_init(struct usp_context *u)
@ -1236,7 +1292,7 @@ int main(int argc, char **argv)
}
}
err = bbfdm_load_config(input_json);
err = bbfdm_load_deamon_config(input_json);
if (err != UBUS_STATUS_OK) {
fprintf(stderr, "Failed to load bbfdm config from json file '%s'\n", input_json);
return -1;

View file

@ -24,21 +24,33 @@
#include <stdio.h>
#include "common.h"
#include "plugin.h"
#include "libbbfdm-api/dmapi.h"
#include "libbbfdm-api/dmjson.h"
#include "libbbfdm-api/dmentry.h"
extern struct list_head loaded_json_files;
extern struct list_head json_list;
extern struct list_head json_memhead;
#define UNUSED __attribute__((unused))
static DMOBJ *CLIENT_DM_ROOT_OBJ = NULL;
static DM_MAP_VENDOR *CLIENT_DM_VENDOR_EXTENSION[2] = {0};
static DM_MAP_VENDOR_EXCLUDE *CLIENT_DM_VENDOR_EXTENSION_EXCLUDE = NULL;
static void *client_lib_handle = NULL;
typedef struct {
struct dmctx bbf_ctx;
unsigned int instance_mode;
unsigned int proto;
char in_type[128];
char in_name[128];
char out_type[128];
char in_type[8];
char out_type[8];
char *cmd;
bool ubus_status;
bool enable_plugins;
} client_data_t;
typedef struct {
@ -284,6 +296,13 @@ static int bbfdm_load_client_config(const char *json_path, client_data_t *client
client_data->instance_mode = INSTANCE_MODE_NUMBER;
}
opt_val = dmjson_get_value(json_obj, 3, "client", "config", "enable_plugins");
if (opt_val && strlen(opt_val)) {
client_data->enable_plugins = (unsigned int) strtoul(opt_val, NULL, 10);
} else {
client_data->enable_plugins = false;
}
opt_val = dmjson_get_value(json_obj, 3, "client", "input", "type");
if (opt_val && strlen(opt_val)) {
snprintf(client_data->in_type, sizeof(client_data->in_type), "%s", opt_val);
@ -357,7 +376,7 @@ static int cli_exec_get(client_data_t *client_data, char *argv[])
{
int err = EXIT_SUCCESS;
if (strcasecmp(client_data->in_type, "DotSO") == 0)
if (strcasecmp(client_data->in_type, "DotSO") == 0 || strcasecmp(client_data->in_type, "JSON") == 0)
err = in_dotso_out_cli_exec_get(client_data, argv);
else if (strcasecmp(client_data->in_type, "UBUS") == 0)
err = in_ubus_out_cli_exec_get(client_data, argv);
@ -396,7 +415,7 @@ static int cli_exec_set(client_data_t *client_data, char *argv[])
{
int err = EXIT_SUCCESS;
if (strcasecmp(client_data->in_type, "DotSO") == 0)
if (strcasecmp(client_data->in_type, "DotSO") == 0 || strcasecmp(client_data->in_type, "JSON") == 0)
err = in_dotso_out_cli_exec_set(client_data, argv);
else if (strcasecmp(client_data->in_type, "UBUS") == 0)
err = in_ubus_out_cli_exec_set(client_data, argv);
@ -434,7 +453,7 @@ static int cli_exec_add(client_data_t *client_data, char *argv[])
{
int err = EXIT_SUCCESS;
if (strcasecmp(client_data->in_type, "DotSO") == 0)
if (strcasecmp(client_data->in_type, "DotSO") == 0 || strcasecmp(client_data->in_type, "JSON") == 0)
err = in_dotso_out_cli_exec_add(client_data, argv);
else if (strcasecmp(client_data->in_type, "UBUS") == 0)
err = in_ubus_out_cli_exec_add(client_data, argv);
@ -472,7 +491,7 @@ static int cli_exec_del(client_data_t *client_data, char *argv[])
{
int err = EXIT_SUCCESS;
if (strcasecmp(client_data->in_type, "DotSO") == 0)
if (strcasecmp(client_data->in_type, "DotSO") == 0 || strcasecmp(client_data->in_type, "JSON") == 0)
err = in_dotso_out_cli_exec_del(client_data, argv);
else if (strcasecmp(client_data->in_type, "UBUS") == 0)
err = in_ubus_out_cli_exec_del(client_data, argv);
@ -513,7 +532,7 @@ static int cli_exec_instances(client_data_t *client_data, char *argv[])
{
int err = EXIT_SUCCESS;
if (strcasecmp(client_data->in_type, "DotSO") == 0)
if (strcasecmp(client_data->in_type, "DotSO") == 0 || strcasecmp(client_data->in_type, "JSON") == 0)
err = in_dotso_out_cli_exec_instances(client_data, argv);
else if (strcasecmp(client_data->in_type, "UBUS") == 0)
err = in_ubus_out_cli_exec_instances(client_data, argv);
@ -595,7 +614,7 @@ static int cli_exec_schema(client_data_t *client_data, char *argv[])
{
int err = EXIT_SUCCESS;
if (strcasecmp(client_data->in_type, "DotSO") == 0)
if (strcasecmp(client_data->in_type, "DotSO") == 0 || strcasecmp(client_data->in_type, "JSON") == 0)
err = in_dotso_out_cli_exec_schema(client_data, argv);
else if (strcasecmp(client_data->in_type, "UBUS") == 0)
err = in_ubus_out_cli_exec_schema(client_data, argv);
@ -615,18 +634,42 @@ static int cli_exec_command(client_data_t *client_data, int argc, char *argv[])
if (!client_data->cmd || strlen(client_data->cmd) == 0)
return EXIT_FAILURE;
if (strcasecmp(client_data->in_type, "DotSO") == 0) {
if (strcasecmp(client_data->in_type, "DotSO") == 0 || strcasecmp(client_data->in_type, "JSON") == 0) {
bbf_ctx_init(&client_data->bbf_ctx, DM_ROOT_OBJ, DM_VENDOR_EXTENSION, DM_VENDOR_EXTENSION_EXCLUDE);
if (strcasecmp(client_data->in_type, "DotSO") == 0) {
if (load_dotso_plugin(&client_lib_handle, client_data->in_name,
&CLIENT_DM_ROOT_OBJ,
CLIENT_DM_VENDOR_EXTENSION,
&CLIENT_DM_VENDOR_EXTENSION_EXCLUDE) != 0) {
err = EXIT_FAILURE;
goto end;
}
} else {
if (load_json_plugin(&loaded_json_files, &json_list, &json_memhead, client_data->in_name,
&CLIENT_DM_ROOT_OBJ) != 0) {
err = EXIT_FAILURE;
goto end;
}
}
if (CLIENT_DM_ROOT_OBJ == NULL) {
err = EXIT_FAILURE;
goto end;
}
bbf_ctx_init(&client_data->bbf_ctx, CLIENT_DM_ROOT_OBJ, CLIENT_DM_VENDOR_EXTENSION, CLIENT_DM_VENDOR_EXTENSION_EXCLUDE);
client_data->bbf_ctx.dm_type = client_data->proto;
client_data->bbf_ctx.instance_mode = client_data->instance_mode;
client_data->bbf_ctx.enable_plugins = client_data->enable_plugins;
} else if (strcasecmp(client_data->in_type, "UBUS") != 0) {
return -1;
}
for (size_t i = 0; i < ARRAY_SIZE(cli_commands); i++) {
cli_cmd = &cli_commands[i];
if (strcmp(client_data->cmd, cli_cmd->name)==0) {
if (strcmp(client_data->cmd, cli_cmd->name) == 0) {
if (argc-1 < cli_cmd->num_args) {
printf("ERROR: Number of arguments for %s method is wrong(%d), it should be %d\n", cli_cmd->name, argc-1, cli_cmd->num_args);
@ -644,13 +687,17 @@ static int cli_exec_command(client_data_t *client_data, int argc, char *argv[])
if (!registred_command) {
printf("ERROR: Unknown command: %s\n", client_data->cmd);
cli_commands[0].exec_cmd(client_data, NULL);
return EXIT_FAILURE;
err = EXIT_FAILURE;
}
end:
if (strcasecmp(client_data->in_type, "DotSO") == 0) {
bbf_ctx_clean(&client_data->bbf_ctx);
bbf_global_clean(DM_ROOT_OBJ);
bbf_global_clean(CLIENT_DM_ROOT_OBJ);
free_dotso_plugin(client_lib_handle);
} else if (strcasecmp(client_data->in_type, "JSON") == 0) {
bbf_ctx_clean(&client_data->bbf_ctx);
free_json_plugin();
}
return err;

View file

@ -17,10 +17,9 @@
#include "bbfdmd.h"
#define ROOT_NODE "Device."
#define METHOD_NAME "bbfdm"
#define BBF_ADD_EVENT METHOD_NAME".AddObj"
#define BBF_DEL_EVENT METHOD_NAME".DelObj"
#define BBF_EVENT METHOD_NAME".event"
#define BBF_ADD_EVENT "AddObj"
#define BBF_DEL_EVENT "DelObj"
#define BBF_EVENT "event"
#define MAX_DM_KEY_LEN 256
#define MAX_DM_PATH 1024
@ -34,9 +33,9 @@
#define USP_ERR_OK 0
extern DMOBJ *DM_ROOT_OBJ;
extern DM_MAP_VENDOR *DM_VENDOR_EXTENSION[2];
extern DM_MAP_VENDOR_EXCLUDE *DM_VENDOR_EXTENSION_EXCLUDE;
extern DMOBJ *DEAMON_DM_ROOT_OBJ;
extern DM_MAP_VENDOR *DEAMON_DM_VENDOR_EXTENSION[2];
extern DM_MAP_VENDOR_EXCLUDE *DEAMON_DM_VENDOR_EXTENSION_EXCLUDE;
bool match(const char *string, const char *pattern);
bool is_str_eq(const char *s1, const char *s2);

View file

@ -26,6 +26,9 @@
#include "get_helper.h"
#include <libubus.h>
extern char UBUS_METHOD_NAME[32];
extern bool enable_plugins;
static struct event_map_list ev_map_list[] = {
/* { event name, DM Path, .arguments[] = { event_args, dm_args } } */
{ "wifi.dataelements.Associated", "Device.WiFi.DataElements.AssociationEvent.Associated!",
@ -171,6 +174,7 @@ static void uspd_event_handler(struct ubus_context *ctx, struct ubus_event_handl
serialize_blob_msg(msg, "", &pv_list);
struct blob_buf b, bb;
char method_name[40] = {0};
memset(&b, 0, sizeof(struct blob_buf));
memset(&bb, 0, sizeof(struct blob_buf));
@ -178,6 +182,8 @@ static void uspd_event_handler(struct ubus_context *ctx, struct ubus_event_handl
blob_buf_init(&b, 0);
blob_buf_init(&bb, 0);
snprintf(method_name, sizeof(method_name), "%s.%s", UBUS_METHOD_NAME, BBF_EVENT);
blobmsg_add_string(&b, "name", dm_path);
generate_blob_input(&bb, type, &pv_list);
blobmsg_add_field(&b, BLOBMSG_TYPE_TABLE, "input", blob_data(bb.head), blob_len(bb.head));
@ -269,6 +275,7 @@ bool is_registered_event(char *name)
.iscommand = false,
.isevent = true,
.isinfo = false,
.enable_plugins = enable_plugins,
.instance_mode = INSTANCE_MODE_NUMBER,
.dm_type = BBFDM_USP
};

View file

@ -31,15 +31,10 @@
#include "pretty_print.h"
#include "libbbfdm-api/dmentry.h"
#include "libbbfdm/dmtree/tr181/device.h"
#include "libbbfdm/dmtree/vendor/vendor.h"
DMOBJ *DM_ROOT_OBJ = tEntryRoot;
DM_MAP_VENDOR *DM_VENDOR_EXTENSION[2] = {
tVendorExtension,
tVendorExtensionOverwrite
};
DM_MAP_VENDOR_EXCLUDE *DM_VENDOR_EXTENSION_EXCLUDE = tVendorExtensionExclude;
DMOBJ *DEAMON_DM_ROOT_OBJ = NULL;
DM_MAP_VENDOR *DEAMON_DM_VENDOR_EXTENSION[2] = {0};
DM_MAP_VENDOR_EXCLUDE *DEAMON_DM_VENDOR_EXTENSION_EXCLUDE = NULL;
// uloop.h does not have versions, below line is to use
// deprecated uloop_timeout_remaining for the time being
@ -79,7 +74,7 @@ void bb_add_string(struct blob_buf *bb, const char *name, const char *value)
void bbf_init(struct dmctx *dm_ctx)
{
bbf_ctx_init(dm_ctx, DM_ROOT_OBJ, DM_VENDOR_EXTENSION, DM_VENDOR_EXTENSION_EXCLUDE);
bbf_ctx_init(dm_ctx, DEAMON_DM_ROOT_OBJ, DEAMON_DM_VENDOR_EXTENSION, DEAMON_DM_VENDOR_EXTENSION_EXCLUDE);
}
void bbf_cleanup(struct dmctx *dm_ctx)
@ -89,7 +84,7 @@ void bbf_cleanup(struct dmctx *dm_ctx)
void bbf_sub_init(struct dmctx *dm_ctx)
{
bbf_ctx_init_sub(dm_ctx, DM_ROOT_OBJ, DM_VENDOR_EXTENSION, DM_VENDOR_EXTENSION_EXCLUDE);
bbf_ctx_init_sub(dm_ctx, DEAMON_DM_ROOT_OBJ, DEAMON_DM_VENDOR_EXTENSION, DEAMON_DM_VENDOR_EXTENSION_EXCLUDE);
}
void bbf_sub_cleanup(struct dmctx *dm_ctx)

165
bbfdmd/src/plugin.c Normal file
View file

@ -0,0 +1,165 @@
/*
* plugin.c: Plugin file bbfdmd
*
* Copyright (C) 2023 iopsys Software Solutions AB. All rights reserved.
*
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include <string.h>
#include <stdlib.h>
#include <dlfcn.h>
#include "common.h"
#include "libbbfdm-api/dmapi.h"
#include "libbbfdm-api/dm_plugin/dmdynamicjson.h"
extern struct list_head global_memhead;
int load_dotso_plugin(void **lib_handle, const char *file_path,
DMOBJ **main_entry,
DM_MAP_VENDOR *main_Extension[],
DM_MAP_VENDOR_EXCLUDE **main_Extension_exclude)
{
if (!lib_handle || !file_path || !strlen(file_path) || !main_entry || !main_Extension || !main_Extension_exclude)
return -1;
void *handle = dlopen(file_path, RTLD_NOW|RTLD_LOCAL);
if (!handle) {
fprintf(stderr, "ERROR: Plugin failed [%s]\n", dlerror());
return -1;
}
*lib_handle = handle;
//Dynamic Object
DM_MAP_OBJ *dynamic_obj = NULL;
*(void **) (&dynamic_obj) = dlsym(handle, "tDynamicObj");
if (dynamic_obj) {
char *node_obj = dm_dynamic_strdup(&global_memhead, dynamic_obj[0].path);
unsigned int len = strlen(node_obj);
if (strncmp(node_obj, ROOT_NODE, strlen(ROOT_NODE)) != 0 || node_obj[len-1] != '.') {
fprintf(stderr, "ERROR: Object (%s) not valid\n", node_obj);
return -1;
}
DMOBJ *dm_entryobj = (DMOBJ *)dm_dynamic_calloc(&global_memhead, 2, sizeof(DMOBJ));
if (dm_entryobj == NULL) {
fprintf(stderr, "ERROR: No Memory exists\n");
return -1;
}
node_obj[len-1] = 0;
dm_entryobj[0].obj = node_obj;
dm_entryobj[0].permission = &DMREAD;
dm_entryobj[0].nextobj = dynamic_obj[0].root_obj;
dm_entryobj[0].leaf = dynamic_obj[0].root_leaf;
dm_entryobj[0].bbfdm_type = BBFDM_BOTH;
*main_entry = dm_entryobj;
} else {
fprintf(stderr, "ERROR: Main entry not available");
return -1;
}
//Vendor Extension
DM_MAP_VENDOR *vendor_extension = NULL;
*(void **) (&vendor_extension) = dlsym(handle, "tVendorExtension");
if (vendor_extension) main_Extension[0] = vendor_extension;
//Vendor Extension Overwrite
DM_MAP_VENDOR *vendor_extension_overwrite = NULL;
*(void **) (&vendor_extension_overwrite) = dlsym(handle, "tVendorExtensionOverwrite");
if (vendor_extension_overwrite) main_Extension[1] = vendor_extension_overwrite;
//Vendor Extension Exclude
DM_MAP_VENDOR_EXCLUDE *vendor_extension_exclude = NULL;
*(void **) (&vendor_extension_exclude) = dlsym(handle, "tVendorExtensionExclude");
if (vendor_extension_exclude) *main_Extension_exclude = vendor_extension_exclude;
return 0;
}
int free_dotso_plugin(void *lib_handle)
{
if (lib_handle)
dlclose(lib_handle);
return 0;
}
int load_json_plugin(struct list_head *json_plugin, struct list_head *json_list, struct list_head *json_memhead, const char *file_path,
DMOBJ **main_entry)
{
int json_plugin_version = 0;
if (!file_path || !strlen(file_path) || !main_entry)
return -1;
json_object *json_obj = json_object_from_file(file_path);
if (!json_obj)
return -1;
save_loaded_json_files(json_plugin, json_obj);
json_object_object_foreach(json_obj, key, jobj) {
if (strcmp(key, "json_plugin_version") == 0) {
json_plugin_version = json_object_get_int(jobj);
continue;
}
char *node_obj = replace_str(key, "{BBF_VENDOR_PREFIX}", BBF_VENDOR_PREFIX);
unsigned int len = strlen(node_obj);
if (strncmp(node_obj, ROOT_NODE, strlen(ROOT_NODE)) != 0 || node_obj[len-1] != '.') {
fprintf(stderr, "ERROR: Object (%s) not valid\n", node_obj);
return -1;
}
char obj_prefix[512] = {0};
find_prefix_obj(node_obj, obj_prefix, sizeof(obj_prefix));
obj_prefix[strlen(obj_prefix)-1] = 0;
DMOBJ *dm_entryobj = (DMOBJ *)dm_dynamic_calloc(json_memhead, 2, sizeof(DMOBJ));
if (dm_entryobj == NULL) {
fprintf(stderr, "ERROR: No Memory exists\n");
return -1;
}
*main_entry = dm_entryobj;
dm_entryobj[0].obj = dm_dynamic_strdup(json_memhead, obj_prefix);
dm_entryobj[0].permission = &DMREAD;
dm_entryobj[0].nextobj = (DMOBJ *)dm_dynamic_calloc(json_memhead, 2, sizeof(DMOBJ));
dm_entryobj[0].leaf = NULL;
dm_entryobj[0].bbfdm_type = BBFDM_BOTH;
parse_obj(node_obj, jobj, dm_entryobj[0].nextobj, 0, json_plugin_version, json_list);
FREE(node_obj);
break;
}
return 0;
}
int free_json_plugin(void)
{
return free_json_loaded_object();
}

35
bbfdmd/src/plugin.h Normal file
View file

@ -0,0 +1,35 @@
/*
* plugin.h: Plugin file bbfdmd
*
* Copyright (C) 2023 iopsys Software Solutions AB. All rights reserved.
*
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifndef PLUGIN_H
int load_dotso_plugin(void **lib_handle, const char *file_path,
DMOBJ **main_entry,
DM_MAP_VENDOR *tVendorExtension[],
DM_MAP_VENDOR_EXCLUDE **tVendorExtensionExclude);
int free_dotso_plugin(void *lib_handle);
int load_json_plugin(struct list_head *json_plugin, struct list_head *json_list, struct list_head *json_memhead, const char *file_path,
DMOBJ **main_entry);
int free_json_plugin(void);
#endif /* PLUGIN_H */

View file

@ -43,14 +43,10 @@ done
echo "1..${num}" >> ./funl-result.log
generate_report python_test ./funl-result.log
# run functional on bbf object validation
rm /usr/share/rpcd/schemas/bbf.json
fault=0
# run functional on bbf object validation
cp -r ./schemas/ubus/bbfdm.json /usr/share/rpcd/schemas/bbf.json
ubus-api-validator -t 5 -f ./test/funl/validation/bbf.validation.json > ./funl-result.log
fault=$(( $fault + $? ))
fault=$?
generate_report bbf_positive ./funl-result.log
supervisorctl stop all

View file

@ -1,10 +1,12 @@
{
"daemon": {
"config": {
"refresh_time": 10,
"enable_plugins": 1
},
"input": {
"type": "DotSO",
"name": "/usr/lib/libbbfdm.so"
"type": "DotSo",
"name": "/lib/libbbfdm.so"
},
"output": {
"type": "UBUS",
@ -14,7 +16,8 @@
"client": {
"config": {
"proto": "usp",
"instance_mode": 0
"instance_mode": 0,
"enable_plugins": 0
},
"input": {
"type": "UBUS",

View file

@ -14,9 +14,9 @@
#define MAX_DM_LENGTH (1024)
#define json_object_get_string(x) (char *)json_object_get_string(x)
static LIST_HEAD(loaded_json_files);
static LIST_HEAD(json_list);
static LIST_HEAD(json_memhead);
LIST_HEAD(loaded_json_files);
LIST_HEAD(json_list);
LIST_HEAD(json_memhead);
static operation_args empty_cmd = {
.in = (const char**)NULL,
@ -89,7 +89,7 @@ static void free_json_data(struct list_head *json_list)
}
}
static void save_loaded_json_files(struct list_head *json_list, json_object *data)
void save_loaded_json_files(struct list_head *json_list, json_object *data)
{
struct loaded_json_file *json_file = calloc(1, sizeof(struct loaded_json_file));
list_add_tail(&json_file->list, json_list);
@ -145,7 +145,15 @@ int free_json_dynamic_arrays(DMOBJ *dm_entryobj)
return 0;
}
static void find_prefix_obj(char *full_obj, char *prefix_obj, size_t len)
int free_json_loaded_object(void)
{
free_loaded_json_files(&loaded_json_files);
free_json_data(&json_list);
dm_dynamic_cleanmem(&json_memhead);
return 0;
}
void find_prefix_obj(char *full_obj, char *prefix_obj, size_t len)
{
int last_occurent = 0, occur = 0;
@ -160,7 +168,7 @@ static void find_prefix_obj(char *full_obj, char *prefix_obj, size_t len)
*(full_object + last_occurent + 1) = 0;
snprintf(prefix_obj, len, "%s", full_object);
dmfree(full_object);
FREE(full_object);
}
static void find_current_obj(char *full_obj, char *curr_obj, size_t len)
@ -178,7 +186,7 @@ static void find_current_obj(char *full_obj, char *curr_obj, size_t len)
full_object[occur] = 0;
snprintf(curr_obj, len, "%s", full_object + last_occurent + 1);
dmfree(full_object);
FREE(full_object);
}
static void generate_path_without_instance(char *full_obj, bool is_obj, char *obj_path, size_t len)
@ -763,6 +771,7 @@ static char *uci_get_value(json_object *mapping_obj, int json_version, char *ref
dmasprintf(&value, "cpe-%s", instance);
end:
FREE(linker);
return value;
}
@ -1782,6 +1791,7 @@ static void parse_param(char *object, char *param, json_object *jobj, DMLEAF *pl
pleaf[i].bbfdm_type = BBFDM_BOTH;
snprintf(full_param, sizeof(full_param), "%s%s", object, param_ext);
FREE(param_ext);
save_json_data(list, full_param, jobj, json_version, (const char**)in_p, (const char**)out_p, (const char**)ev_arg);
}
@ -1802,7 +1812,7 @@ static void count_obj_param_under_jsonobj(json_object *jsonobj, int *obj_number,
}
}
static void parse_obj(char *object, json_object *jobj, DMOBJ *pobj, int index, int json_version, struct list_head *list)
void parse_obj(char *object, json_object *jobj, DMOBJ *pobj, int index, int json_version, struct list_head *list)
{
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys(13)*/
@ -1816,7 +1826,7 @@ static void parse_obj(char *object, json_object *jobj, DMOBJ *pobj, int index, i
char *obj_path = replace_str(object, "{BBF_VENDOR_PREFIX}", BBF_VENDOR_PREFIX);
char *full_obj = replace_str(obj_path, ".{i}.", ".");
find_current_obj(full_obj, curr_obj, sizeof(curr_obj));
dmfree(obj_path);
FREE(obj_path);
if (!pobj)
return;
@ -1913,6 +1923,8 @@ static void parse_obj(char *object, json_object *jobj, DMOBJ *pobj, int index, i
i++;
}
}
FREE(full_obj);
}
int load_json_dynamic_arrays(struct dmctx *ctx)
@ -1950,8 +1962,10 @@ int load_json_dynamic_arrays(struct dmctx *ctx)
find_prefix_obj(obj_path, obj_prefix, MAX_DM_LENGTH);
bool obj_exists = find_root_entry(ctx, obj_prefix, &dm_entryobj);
if (obj_exists == 0 || !dm_entryobj)
if (obj_exists == 0 || !dm_entryobj) {
FREE(obj_path);
continue;
}
if (dm_entryobj->nextdynamicobj == NULL) {
dm_entryobj->nextdynamicobj = calloc(__INDX_DYNAMIC_MAX, sizeof(struct dm_dynamic_obj));
@ -1973,6 +1987,8 @@ int load_json_dynamic_arrays(struct dmctx *ctx)
memset(dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0] + (idx + 1), 0, sizeof(struct dm_obj_s));
parse_obj(obj_path, jobj, dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0], idx, json_plugin_version, &json_list);
}
FREE(obj_path);
}
save_loaded_json_files(&loaded_json_files, json);
}

View file

@ -16,6 +16,12 @@
#define JSON_FOLDER_PATH "/etc/bbfdm/json"
void save_loaded_json_files(struct list_head *json_list, json_object *data);
void parse_obj(char *object, json_object *jobj, DMOBJ *pobj, int index, int json_version, struct list_head *list);
void find_prefix_obj(char *full_obj, char *prefix_obj, size_t len);
int free_json_loaded_object(void);
int load_json_dynamic_arrays(struct dmctx *ctx);
int free_json_dynamic_arrays(DMOBJ *dm_entryobj);

View file

@ -1,18 +1,17 @@
/*
* Copyright (C) 2021 iopsys Software Solutions AB
* Copyright (C) 2023 iopsys Software Solutions AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* Author Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
* Author Amin Ben Romdhane <amin.benramdhane@iopsys.eu>
*
*/
#include "dmdynamiclibrary.h"
LIST_HEAD(loaded_library_list);
LIST_HEAD(library_memhead);
struct loaded_library
{
@ -20,14 +19,6 @@ struct loaded_library
void *library;
};
struct dynamic_operate
{
struct list_head list;
char *operate_path;
void *operate;
void *operate_args;
};
static void add_list_loaded_libraries(struct list_head *library_list, void *library)
{
struct loaded_library *lib = calloc(1, sizeof(struct loaded_library));
@ -79,7 +70,6 @@ void free_library_dynamic_arrays(DMOBJ *dm_entryobj)
DMNODE node = {.current_object = ""};
free_all_list_open_library(&loaded_library_list);
dm_dynamic_cleanmem(&library_memhead);
dm_browse_node_dynamic_object_tree(&node, root);
}
@ -99,11 +89,10 @@ int load_library_dynamic_arrays(struct dmctx *ctx)
void *handle = dlopen(buf, RTLD_NOW|RTLD_LOCAL);
if (!handle) {
fprintf(stderr, "Plugin failed [%s]", dlerror());
fprintf(stderr, "Plugin failed [%s]\n", dlerror());
continue;
}
//Dynamic Object
DM_MAP_OBJ *dynamic_obj = NULL;
*(void **) (&dynamic_obj) = dlsym(handle, "tDynamicObj");

View file

@ -1,11 +1,11 @@
/*
* Copyright (C) 2021 iopsys Software Solutions AB
* Copyright (C) 2023 iopsys Software Solutions AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* Author Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
* Author Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
*
*/

View file

@ -225,7 +225,7 @@ static void exclude_obj(struct dmctx *ctx, char *in_obj)
char *obj_path = replace_str(in_obj, ".{i}.", ".");
dm_exclude_obj(ctx, &node, root, obj_path);
dmfree(obj_path);
FREE(obj_path);
}
static void exclude_param(struct dmctx *ctx, char *in_param)

View file

@ -197,6 +197,7 @@ struct dmctx {
bool iscommand;
bool isevent;
bool isinfo;
bool enable_plugins;
};
typedef struct dmnode {

View file

@ -686,7 +686,7 @@ bool find_root_entry(struct dmctx *ctx, char *in_param, DMOBJ **root_entry)
char *old_in_param = ctx->in_param;
dm_check_dynamic_obj(ctx, &node, root, obj_path, obj_path, root_entry, &obj_found);
ctx->in_param = old_in_param;
dmfree(obj_path);
FREE(obj_path);
return (obj_found && *root_entry) ? true : false;
}

View file

@ -1847,7 +1847,7 @@ char *replace_str(const char *str, const char *substr, const char *replacement)
}
size_t new_str_len = i + cnt * (replacement_len - substr_len) + 1;
char *value = (char *)dmmalloc(new_str_len * sizeof(char));
char *value = (char *)malloc(new_str_len * sizeof(char));
i = 0;
while (*str) {

View file

@ -295,7 +295,8 @@ int bbf_entry_method(struct dmctx *ctx, int cmd)
return bbf_fault_map(ctx->dm_type, USP_FAULT_INVALID_PATH);
// Load dynamic objects and parameters
load_dynamic_arrays(ctx);
if (ctx->enable_plugins)
load_dynamic_arrays(ctx);
dmentry_instance_lookup_inparam(ctx);
@ -348,8 +349,8 @@ int bbf_entry_method(struct dmctx *ctx, int cmd)
void bbf_global_clean(DMOBJ *dm_entryobj)
{
dm_dynamic_cleanmem(&global_memhead);
free_dynamic_arrays(dm_entryobj);
dm_dynamic_cleanmem(&global_memhead);
}
int dm_entry_validate_allowed_objects(struct dmctx *ctx, char *value, char *objects[])

View file

@ -15,8 +15,6 @@
#ifndef __DMENTRY_H__
#define __DMENTRY_H__
extern struct list_head global_memhead;
void bbf_ctx_init(struct dmctx *ctx, DMOBJ *tEntryObj,
DM_MAP_VENDOR *tVendorExtension[],
DM_MAP_VENDOR_EXCLUDE *tVendorExtensionExclude);

View file

@ -80,6 +80,12 @@ static int operate_Device_FactoryReset(char *refparam, struct dmctx *ctx, void *
* OBJ & LEAF DEFINITION
***********************************************************************************************************************************/
/* *** BBFDM *** */
DM_MAP_OBJ tDynamicObj[] = {
/* parentobj, nextobject, parameter */
{"Device.", tDeviceObj, tDeviceParams},
{0}
};
DMOBJ tEntryRoot[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/
{"Device", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tDeviceObj, tDeviceParams, NULL, BBFDM_BOTH},

View file

@ -15,6 +15,8 @@
#include "libbbfdm-api/dmcommon.h"
extern DM_MAP_OBJ tDynamicObj[];
extern DMOBJ tEntryRoot[];
extern DMOBJ tDeviceObj[];
extern DMLEAF tDeviceParams[];

View file

@ -965,11 +965,13 @@ static void test_bbf_api_common(void **state)
DM_STRNCPY(buf, "Device.IEEE1905.AL.NetworkTopology.IEEE1905Device.{i}.IPv4Address.{i}.", sizeof(buf));
value = replace_str(buf, ".{i}.", ".");
assert_string_equal(value, "Device.IEEE1905.AL.NetworkTopology.IEEE1905Device.IPv4Address.");
FREE(value);
// replace_str: test
DM_STRNCPY(buf, "Device.IEEE1905.AL.NetworkTopology.IEEE1905Device.{i}.IPv4Address.{i}.", sizeof(buf));
value = replace_str(buf, ".{i}.", ".*.");
assert_string_equal(value, "Device.IEEE1905.AL.NetworkTopology.IEEE1905Device.*.IPv4Address.*.");
FREE(value);
/*

View file

@ -6,6 +6,7 @@
#include <libbbfdm-api/dmuci.h>
#include <libbbfdm-api/dmapi.h>
#include <libbbfdm-api/dmentry.h>
#include <libbbfdm/device.h>
#include <libbbfdm/vendor.h>
@ -24,6 +25,9 @@ static int setup(void **state)
bbf_ctx_init(ctx, TR181_ROOT_TREE, TR181_VENDOR_EXTENSION, TR181_VENDOR_EXTENSION_EXCLUDE);
// Enable Plugins
ctx->enable_plugins = true;
*state = ctx;
return 0;

View file

@ -6,6 +6,7 @@
#include <libbbfdm-api/dmuci.h>
#include <libbbfdm-api/dmapi.h>
#include <libbbfdm-api/dmentry.h>
#include <libbbfdm/device.h>
#include <libbbfdm/vendor.h>
@ -29,6 +30,9 @@ static int setup(void **state)
bbf_ctx_init(ctx, TR181_ROOT_TREE, TR181_VENDOR_EXTENSION, TR181_VENDOR_EXTENSION_EXCLUDE);
// Enable Plugins
ctx->enable_plugins = true;
*state = ctx;
return 0;
@ -592,6 +596,9 @@ static void test_api_bbfdm_json_get_value(void **state)
bbf_ctx_clean_sub(ctx);
bbf_ctx_init(ctx, TR181_ROOT_TREE, TR181_VENDOR_EXTENSION, TR181_VENDOR_EXTENSION_EXCLUDE);
// Enable Plugins
ctx->enable_plugins = true;
/*
* Test of JSON Parameter Path
*/
@ -605,6 +612,9 @@ static void test_api_bbfdm_json_get_value(void **state)
bbf_ctx_clean_sub(ctx);
bbf_ctx_init(ctx, TR181_ROOT_TREE, TR181_VENDOR_EXTENSION, TR181_VENDOR_EXTENSION_EXCLUDE);
// Enable Plugins
ctx->enable_plugins = true;
remove(DROPBEAR_JSON_PATH);
ctx->in_param = "Device.X_IOPSYS_EU_Dropbear.";
@ -682,6 +692,9 @@ static void test_api_bbfdm_library_get_value(void **state)
bbf_ctx_clean_sub(ctx);
bbf_ctx_init(ctx, TR181_ROOT_TREE, TR181_VENDOR_EXTENSION, TR181_VENDOR_EXTENSION_EXCLUDE);
// Enable Plugins
ctx->enable_plugins = true;
ctx->in_param = "Device.WiFi.SSID.1.Enable";
fault = bbf_entry_method(ctx, BBF_GET_VALUE);
@ -693,6 +706,9 @@ static void test_api_bbfdm_library_get_value(void **state)
bbf_ctx_clean_sub(ctx);
bbf_ctx_init(ctx, TR181_ROOT_TREE, TR181_VENDOR_EXTENSION, TR181_VENDOR_EXTENSION_EXCLUDE);
// Enable Plugins
ctx->enable_plugins = true;
remove(LIBBBF_TEST_BBFDM_PATH);
ctx->in_param = "Device.X_IOPSYS_EU_Syslog.";