Multiple updates

- Transaction APIs removed
- Use different save dirs per proto
- In process instance update notifier
- Use event based refresh timer
- Commit changes from main daemon for default proto
- For add request commit changes without reload for default proto
- extend bbf.config to monitor based on input
- extend bbf.config to reload/commit based on input
- extend bb.config to provide list of service changes based on proto
This commit is contained in:
Amin Ben Romdhane 2024-08-17 07:18:35 +00:00 committed by IOPSYS Dev
parent 75195a112e
commit fa69524868
No known key found for this signature in database
42 changed files with 763 additions and 1967 deletions

View file

@ -49,8 +49,6 @@ extern struct list_head json_memhead;
// micro-services should not use fork by default
#define BBF_SUBPROCESS_DEPTH (0)
// default instance updater timeout
#define BBF_INSTANCES_UPDATE_TIMEOUT (60 * 1000)
LIST_HEAD(head_registered_service);
@ -137,15 +135,12 @@ static void fill_optional_data(bbfdm_data_t *data, struct blob_attr *msg)
data->bbf_ctx.dm_type = get_proto_type(val);
}
if (is_str_eq(blobmsg_name(attr), "transaction_id"))
data->trans_id = blobmsg_get_u32(attr);
if (is_str_eq(blobmsg_name(attr), "format"))
data->is_raw = is_str_eq(blobmsg_get_string(attr), "raw") ? true : false;
}
char *proto = (data->bbf_ctx.dm_type == BBFDM_BOTH) ? "both" : (data->bbf_ctx.dm_type == BBFDM_CWMP) ? "cwmp" : "usp";
DEBUG("Proto:|%s|, Tran-id:|%d|, is_raw:|%d|", proto, data->trans_id, data->is_raw);
DEBUG("Proto:|%s|, is_raw:|%d|", proto, data->is_raw);
}
static void async_req_free(struct bbfdm_async_req *r)
@ -517,7 +512,6 @@ int bbfdm_set_handler(struct ubus_context *ctx, struct ubus_object *obj,
char path[PATH_MAX] = {'\0'};
bbfdm_data_t data;
int fault = 0;
int trans_id = 0;
LIST_HEAD(pv_list);
memset(&data, 0, sizeof(bbfdm_data_t));
@ -555,44 +549,25 @@ int bbfdm_set_handler(struct ubus_context *ctx, struct ubus_object *obj,
if (list_empty(&pv_list)) {
ERR("Fault in fill pvlist set path |%s| : |list is empty|", data.bbf_ctx.in_param);
fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR);
fault = USP_FAULT_INTERNAL_ERROR;
goto end;
}
data.plist = &pv_list;
// no need to process it further since transaction-id is not valid
if (data.trans_id && !is_transaction_valid(data.trans_id)) {
WARNING("Transaction not started yet");
fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR);
goto end;
} else {
data.bbf_ctx.trans_id = data.trans_id;
}
if (data.trans_id == 0) {
// Transaction-id is not defined so create an internal transaction
cancel_instance_refresh_timer(ctx);
trans_id = transaction_start(&data, "INT_SET", 0);
if (trans_id == 0) {
WARNING("Failed to get the lock for the transaction");
fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR);
goto end;
}
}
bbfdm_set_value(&data);
if (data.trans_id == 0) {
// Internal transaction: need to commit the changes
transaction_commit(NULL, trans_id, true);
register_instance_refresh_timer(ctx, 100);
}
fault = bbfdm_set_value(&data);
end:
if ((data.bbf_ctx.dm_type == BBFDM_BOTH) && (is_micro_service == false)) {
bbf_entry_services(data.bbf_ctx.dm_type, (!fault) ? true : false, true);
}
bbf_cleanup(&data.bbf_ctx);
free_pv_list(&pv_list);
ubus_send_reply(ctx, req, data.bb.head);
blob_buf_free(&data.bb);
free_pv_list(&pv_list);
bbf_cleanup(&data.bbf_ctx);
return 0;
}
@ -662,7 +637,6 @@ int bbfdm_add_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct blob_attr *tb[__DM_ADD_MAX];
char path[PATH_MAX];
bbfdm_data_t data;
int trans_id = 0;
int fault = 0;
memset(&data, 0, sizeof(bbfdm_data_t));
@ -687,36 +661,9 @@ int bbfdm_add_handler(struct ubus_context *ctx, struct ubus_object *obj,
blob_buf_init(&data.bb, 0);
bbf_init(&data.bbf_ctx);
// no need to process it further since transaction-id is not valid
if (data.trans_id && !is_transaction_valid(data.trans_id)) {
WARNING("Transaction not started yet");
fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR);
goto end;
} else {
data.bbf_ctx.trans_id = data.trans_id;
}
if (data.trans_id == 0) {
// Transaction-id is not defined so create an internal transaction
cancel_instance_refresh_timer(ctx);
trans_id = transaction_start(&data, "INT_ADD", 0);
if (trans_id == 0) {
ERR("Failed to get the lock for the transaction");
fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR);
goto end;
}
}
fault = create_add_response(&data);
if (fault) {
ERR("Fault in add path |%s|", data.bbf_ctx.in_param);
if (data.trans_id == 0) {
// Internal transaction: need to abort the changes
transaction_abort(NULL, trans_id);
register_instance_refresh_timer(ctx, 100);
}
goto end;
}
@ -729,13 +676,6 @@ int bbfdm_add_handler(struct ubus_context *ctx, struct ubus_object *obj,
if (fault) {
ERR("Fault in fill pvlist set path |%s|", path);
fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR);
if (data.trans_id == 0) {
// Internal transaction: need to abort the changes
transaction_abort(NULL, trans_id);
register_instance_refresh_timer(ctx, 100);
}
free_pv_list(&pv_list);
goto end;
}
@ -747,16 +687,16 @@ int bbfdm_add_handler(struct ubus_context *ctx, struct ubus_object *obj,
free_pv_list(&pv_list);
}
if (data.trans_id == 0) {
// Internal transaction: need to commit the changes
transaction_commit(NULL, trans_id, true);
register_instance_refresh_timer(ctx, 100);
end:
if ((data.bbf_ctx.dm_type == BBFDM_BOTH) && (is_micro_service == false)) {
bbf_entry_services(data.bbf_ctx.dm_type, (!fault) ? true : false, false);
}
end:
bbf_cleanup(&data.bbf_ctx);
ubus_send_reply(ctx, req, data.bb.head);
blob_buf_free(&data.bb);
bbf_cleanup(&data.bbf_ctx);
return 0;
}
@ -773,7 +713,7 @@ int bbfdm_del_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct blob_attr *tb[__DM_DEL_MAX];
LIST_HEAD(paths_list);
bbfdm_data_t data;
int trans_id = 0;
int fault = 0;
memset(&data, 0, sizeof(bbfdm_data_t));
@ -814,121 +754,17 @@ int bbfdm_del_handler(struct ubus_context *ctx, struct ubus_object *obj,
data.bbf_ctx.in_param = tb[DM_DEL_PATH] ? blobmsg_get_string(tb[DM_DEL_PATH]) : "";
// no need to process it further since transaction-id is not valid
if (data.trans_id && !is_transaction_valid(data.trans_id)) {
WARNING("Transaction not started yet");
fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR);
goto end;
} else {
data.bbf_ctx.trans_id = data.trans_id;
fault = create_del_response(&data);
if ((data.bbf_ctx.dm_type == BBFDM_BOTH) && (is_micro_service == false)) {
bbf_entry_services(data.bbf_ctx.dm_type, (!fault) ? true : false, true);
}
if (data.trans_id == 0) {
// Transaction-id is not defined so create an internal transaction
cancel_instance_refresh_timer(ctx);
trans_id = transaction_start(&data, "INT_DEL", 0);
if (trans_id == 0) {
WARNING("Failed to get the lock for the transaction");
fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR);
goto end;
}
}
create_del_response(&data);
if (data.trans_id == 0) {
// Internal transaction: need to commit the changes
transaction_commit(NULL, trans_id, true);
register_instance_refresh_timer(ctx, 100);
}
end:
ubus_send_reply(ctx, req, data.bb.head);
blob_buf_free(&data.bb);
bbf_cleanup(&data.bbf_ctx);
free_path_list(&paths_list);
return 0;
}
enum {
TRANS_CMD,
TRANS_TIMEOUT,
TRANS_RESTART,
TRANS_OPTIONAL,
__TRANS_MAX,
};
static const struct blobmsg_policy transaction_policy[] = {
[TRANS_CMD] = { .name = "cmd", .type = BLOBMSG_TYPE_STRING },
[TRANS_TIMEOUT] = { .name = "timeout", .type = BLOBMSG_TYPE_INT32 },
[TRANS_RESTART] = { .name = "restart_services", .type = BLOBMSG_TYPE_INT8 },
[TRANS_OPTIONAL] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE },
};
static int bbfdm_transaction_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__TRANS_MAX] = {NULL};
bbfdm_data_t data;
bool is_service_restart = true;
uint32_t max_timeout = 0;
char *trans_cmd = "status";
int ret;
memset(&data, 0, sizeof(bbfdm_data_t));
if (blobmsg_parse(transaction_policy, __TRANS_MAX, tb, blob_data(msg), blob_len(msg))) {
ERR("Failed to parse blob");
return UBUS_STATUS_UNKNOWN_ERROR;
}
if (!tb[TRANS_CMD])
return UBUS_STATUS_INVALID_ARGUMENT;
if (tb[TRANS_CMD])
trans_cmd = blobmsg_get_string(tb[TRANS_CMD]);
if (tb[TRANS_TIMEOUT])
max_timeout = blobmsg_get_u32(tb[TRANS_TIMEOUT]);
if (tb[TRANS_RESTART])
is_service_restart = blobmsg_get_bool(tb[TRANS_RESTART]);
fill_optional_data(&data, tb[TRANS_OPTIONAL]);
INFO("ubus method|%s|, name|%s|, cmd [%s]", method, obj->name, trans_cmd);
bbf_init(&data.bbf_ctx);
blob_buf_init(&data.bb, 0);
data.ctx = ctx;
if (is_str_eq(trans_cmd, "start")) {
ret = transaction_start(&data, "API", max_timeout);
if (ret) {
blobmsg_add_u8(&data.bb, "status", true);
blobmsg_add_u32(&data.bb, "transaction_id", ret);
} else {
blobmsg_add_u8(&data.bb, "status", false);
transaction_status(&data.bb);
}
} else if (is_str_eq(trans_cmd, "commit")) {
ret = transaction_commit(&data, data.trans_id, is_service_restart);
blobmsg_add_u8(&data.bb, "status", (ret == 0));
} else if (is_str_eq(trans_cmd, "abort")) {
ret = transaction_abort(&data, data.trans_id);
blobmsg_add_u8(&data.bb, "status", (ret == 0));
} else if (is_str_eq(trans_cmd, "status")) {
transaction_status(&data.bb);
} else {
WARNING("method(%s) not supported", method);
}
ubus_send_reply(ctx, req, data.bb.head);
blob_buf_free(&data.bb);
bbf_cleanup(&data.bbf_ctx);
return 0;
}
@ -1093,7 +929,6 @@ static struct ubus_method bbf_methods[] = {
UBUS_METHOD("operate", bbfdm_operate_handler, dm_operate_policy),
UBUS_METHOD("add", bbfdm_add_handler, dm_add_policy),
UBUS_METHOD("del", bbfdm_del_handler, dm_del_policy),
UBUS_METHOD("transaction", bbfdm_transaction_handler, transaction_policy),
UBUS_METHOD("service", bbfdm_service_handler, service_policy),
UBUS_METHOD("notify_event", bbfdm_notify_event, dm_notify_event_policy),
};
@ -1125,25 +960,17 @@ static void run_schema_updater(struct bbfdm_context *u)
}
}
static void broadcast_add_del_event(const char *method, struct list_head *inst, bool is_add)
static void broadcast_add_del_event(struct ubus_context *ctx, const char *method, 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;
if (list_empty(inst)) {
return;
}
ret = ubus_connect_ctx(&ctx, NULL);
if (ret != UBUS_STATUS_OK) {
fprintf(stderr, "Failed to connect to ubus\n");
return;
}
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
@ -1157,12 +984,11 @@ static void broadcast_add_del_event(const char *method, struct list_head *inst,
snprintf(method_name, sizeof(method_name), "%s.%s", method, is_add ? BBF_ADD_EVENT : BBF_DEL_EVENT);
if (is_add)
ubus_send_event(&ctx, method_name, bb.head);
ubus_send_event(ctx, method_name, bb.head);
else
ubus_send_event(&ctx, method_name, bb.head);
ubus_send_event(ctx, method_name, bb.head);
blob_buf_free(&bb);
ubus_shutdown(&ctx);
}
static void update_instances_list(struct list_head *inst)
@ -1172,7 +998,7 @@ static void update_instances_list(struct list_head *inst)
.in_param = ROOT_NODE,
.nextlevel = false,
.disable_mservice_browse = true,
.dm_type = BBFDM_USP
.dm_type = BBFDM_BOTH
};
bbf_init(&bbf_ctx);
@ -1182,6 +1008,9 @@ static void update_instances_list(struct list_head *inst)
struct blob_attr *cur = NULL;
size_t rem = 0;
// Apply all bbfdm changes
dmuci_commit_bbfdm();
blobmsg_for_each_attr(cur, bbf_ctx.bb.head, rem) {
struct blob_attr *tb[1] = {0};
const struct blobmsg_policy p[1] = {
@ -1201,26 +1030,6 @@ static void update_instances_list(struct list_head *inst)
bbf_cleanup(&bbf_ctx);
}
static void instance_fork_done(struct uloop_process *p, int ret)
{
struct bbfdm_async_req *r = container_of(p, struct bbfdm_async_req, process);
if (r) {
INFO("Instance updater(%d) completed, starting a new instance timer", r->process.pid);
struct bbfdm_context *u = (struct bbfdm_context *)r->result;
if (u->config.refresh_time != 0) {
u->instance_timer.cb = periodic_instance_updater;
uloop_timeout_set(&u->instance_timer, u->config.refresh_time);
}
free_path_list(&u->old_instances);
async_req_free(r);
}
if (ret) {
WARNING("Instance updater cb failed %d", ret);
}
}
static void instance_compare_publish(struct bbfdm_context *daemon_ctx)
{
struct pathNode *ptr;
@ -1237,7 +1046,7 @@ static void instance_compare_publish(struct bbfdm_context *daemon_ctx)
add_path_list(ptr->path, &inst_list);
}
}
broadcast_add_del_event(method, &inst_list, false);
broadcast_add_del_event(&daemon_ctx->ubus_ctx, method, &inst_list, false);
free_path_list(&inst_list);
list_for_each_entry(ptr, new_inst, list) {
@ -1245,65 +1054,10 @@ static void instance_compare_publish(struct bbfdm_context *daemon_ctx)
add_path_list(ptr->path, &inst_list);
}
}
broadcast_add_del_event(method, &inst_list, true);
broadcast_add_del_event(&daemon_ctx->ubus_ctx, method, &inst_list, true);
free_path_list(&inst_list);
}
static int fork_instance_checker(struct bbfdm_context *u)
{
struct bbfdm_async_req *r = NULL;
pid_t child;
r = async_req_new();
if (r == NULL) {
ERR("Error allocating instance req");
if (u->config.refresh_time != 0) {
u->instance_timer.cb = periodic_instance_updater;
uloop_timeout_set(&u->instance_timer, u->config.refresh_time);
}
free_path_list(&u->old_instances);
goto err_out;
}
child = fork();
if (child == 0) {
char inst_ser[32] = {0};
snprintf(inst_ser, sizeof(inst_ser), "dm_%s_in", u->config.service_name);
INFO("{%s::fork} Instances checker entry", inst_ser);
prctl(PR_SET_NAME, inst_ser, NULL, NULL, NULL);
// child initialise signal to prevent segfaults
signal_init();
/* free fd's and memory inherited from parent */
uloop_done();
ubus_shutdown(&u->ubus_ctx);
async_req_free(r);
fclose(stdin);
fclose(stdout);
fclose(stderr);
instance_compare_publish(u);
bbfdm_cleanup(u);
closelog();
INFO("{fork} Instances checker exit");
/* write result and exit */
exit(EXIT_SUCCESS);
}
// parent
INFO("# Creating instance checker process child %d", child);
r->result = u;
r->process.pid = child;
r->process.cb = instance_fork_done;
uloop_process_add(&r->process);
return 0;
err_out:
if (r)
async_req_free(r);
return UBUS_STATUS_UNKNOWN_ERROR;
}
static void periodic_instance_updater(struct uloop_timeout *t)
{
struct bbfdm_context *u;
@ -1314,43 +1068,23 @@ static void periodic_instance_updater(struct uloop_timeout *t)
return;
}
if (u->config.refresh_time == 0) {
return; // periodic refresh disabled
}
if (is_transaction_running()) {
DEBUG("Transaction ongoing, schedule refresh timer after 1s");
u->instance_timer.cb = periodic_instance_updater;
uloop_timeout_set(&u->instance_timer, 1000);
return;
}
if (list_empty(&u->instances)) {
if (!list_empty(&u->old_instances)) {
list_splice_init(&u->old_instances, &u->instances);
} else {
update_instances_list(&u->instances);
DEBUG("Creating timer for instance update checker, init instances");
u->instance_timer.cb = periodic_instance_updater;
uloop_timeout_set(&u->instance_timer, u->config.refresh_time);
return;
}
}
free_path_list(&u->old_instances);
list_splice_init(&u->instances, &u->old_instances);
update_instances_list(&u->instances);
if (list_empty(&u->instances)) {
update_instances_list(&u->instances);
WARNING("Failed to get current instances, restart the timer");
u->instance_timer.cb = periodic_instance_updater;
uloop_timeout_set(&u->instance_timer, u->config.refresh_time);
return;
}
// fork a process and send it to compare, when process completes
// delete the old instances and add a new timer
fork_instance_checker(u);
update_instances_list(&u->instances);
if (!list_empty(&u->instances) && !list_empty(&u->old_instances)) {
INFO("Comparing instances ...");
instance_compare_publish(u);
}
}
static bool register_service(struct ubus_context *ctx)
@ -1404,22 +1138,6 @@ static int _parse_daemon_config_options(bbfdm_config_t *config, json_object *dae
set_debug_level(BBFDM_DEFAULT_DEBUG_LEVEL);
}
opt_val = dmjson_get_value(daemon_obj, 2, "config", "refresh_time");
if (DM_STRLEN(opt_val)) {
config->refresh_time = (unsigned int) strtoul(opt_val, NULL, 10) * 1000;
} else {
config->refresh_time = BBF_INSTANCES_UPDATE_TIMEOUT;
}
opt_val = dmjson_get_value(daemon_obj, 2, "config", "transaction_timeout");
if (DM_STRLEN(opt_val)) {
config->transaction_timeout = (int) strtol(opt_val, NULL, 10);
configure_transaction_timeout(config->transaction_timeout);
} else {
config->transaction_timeout = 30;
configure_transaction_timeout(30*1000);
}
opt_val = dmjson_get_value(daemon_obj, 2, "config", "subprocess_level");
if (DM_STRLEN(opt_val)) {
config->subprocess_level = (unsigned int) strtoul(opt_val, NULL, 10);
@ -1672,7 +1390,6 @@ static void lookup_event_cb(struct ubus_context *ctx,
void register_instance_refresh_timer(struct ubus_context *ctx, int start_in)
{
struct bbfdm_context *u;
unsigned refresh_time = 0;
u = container_of(ctx, struct bbfdm_context, ubus_ctx);
if (u == NULL) {
@ -1680,16 +1397,10 @@ void register_instance_refresh_timer(struct ubus_context *ctx, int start_in)
return;
}
if (start_in < 0) {
refresh_time = u->config.refresh_time;
} else {
refresh_time = start_in;
}
if (u->config.refresh_time != 0) {
INFO("Register instance refresh timer in %d ms...", refresh_time);
if (start_in >= 0) {
INFO("Register instance refresh timer in %d ms...", start_in);
u->instance_timer.cb = periodic_instance_updater;
uloop_timeout_set(&u->instance_timer, refresh_time);
uloop_timeout_set(&u->instance_timer, start_in);
}
}
@ -1704,9 +1415,7 @@ void cancel_instance_refresh_timer(struct ubus_context *ctx)
}
DEBUG("Cancelling Instance refresh timer");
if (u->config.refresh_time != 0) {
uloop_timeout_cancel(&u->instance_timer);
}
uloop_timeout_cancel(&u->instance_timer);
}
static void bbf_config_change_cb(struct ubus_context *ctx, struct ubus_event_handler *ev,
@ -1719,8 +1428,10 @@ static void bbf_config_change_cb(struct ubus_context *ctx, struct ubus_event_han
if (type && strcmp(type, "bbf.config.change") != 0)
return;
INFO("Config updated, Scheduling instance refresh timers");
cancel_instance_refresh_timer(ctx);
register_instance_refresh_timer(ctx, 100);
register_instance_refresh_timer(ctx, 0);
}
static void bbfdm_ctx_init(struct bbfdm_context *bbfdm_ctx)

View file

@ -19,7 +19,6 @@ struct bbfdm_async_req {
typedef struct bbfdm_config {
int proto; // Protocol identifier, Possible values: { '0'<both>, '1'<cwmp>, '2'<usp> }
int transaction_timeout; // Timeout for transactions
int subprocess_level; // Subprocess level
uint8_t log_level; // Log level, Possible values: { '1', '2', '3', '4' }
uint32_t refresh_time; // Refresh time
@ -62,7 +61,6 @@ typedef struct bbfdm_data {
struct blob_buf bb;
uint8_t depth;
bool is_raw;
int trans_id;
} bbfdm_data_t;
void register_instance_refresh_timer(struct ubus_context *ctx, int start_sec);

View file

@ -181,7 +181,7 @@ static int in_ubus_out_cli_exec_cmd(cli_data_t *cli_data, const char *path, cons
if (value) blobmsg_add_string(&b, "value", value);
table = blobmsg_open_table(&b, "optional");
blobmsg_add_string(&b, "proto", (cli_data->proto == BBFDM_CWMP) ? "cwmp" : "usp");
blobmsg_add_string(&b, "proto", (cli_data->proto == BBFDM_CWMP) ? "cwmp" : (cli_data->proto == BBFDM_USP) ? "usp" : "both");
blobmsg_add_string(&b, "format", "raw");
blobmsg_close_table(&b, table);
@ -280,6 +280,8 @@ static int in_dotso_out_cli_exec_get(cli_data_t *cli_data, char *argv[])
printf("%s => %s\n", name, data);
}
// Apply all bbfdm changes
dmuci_commit_bbfdm();
} else {
printf("ERROR: %d retrieving %s\n", err, cli_data->bbf_ctx.in_param);
@ -319,10 +321,10 @@ static int in_dotso_out_cli_exec_set(cli_data_t *cli_data, char *argv[])
err = bbf_entry_method(&cli_data->bbf_ctx, BBF_SET_VALUE);
if (!err) {
printf("%s => Set value is successfully done\n", cli_data->bbf_ctx.in_param);
bbf_entry_restart_services(NULL, true);
bbf_entry_services(cli_data->proto, true, true);
} else {
printf("Fault %d: %s\n", err, cli_data->bbf_ctx.fault_msg);
bbf_entry_revert_changes(NULL);
bbf_entry_services(cli_data->proto, false, true);
err = EXIT_FAILURE;
}
@ -357,10 +359,10 @@ static int in_dotso_out_cli_exec_add(cli_data_t *cli_data, char *argv[])
err = bbf_entry_method(&cli_data->bbf_ctx, BBF_ADD_OBJECT);
if (!err) {
printf("Added %s%s.\n", cli_data->bbf_ctx.in_param, cli_data->bbf_ctx.addobj_instance);
bbf_entry_restart_services(NULL, true);
bbf_entry_services(cli_data->proto, true, false);
} else {
printf("Fault %d: %s\n", err, cli_data->bbf_ctx.fault_msg);
bbf_entry_revert_changes(NULL);
bbf_entry_services(cli_data->proto, false, false);
err = EXIT_FAILURE;
}
@ -395,10 +397,10 @@ static int in_dotso_out_cli_exec_del(cli_data_t *cli_data, char *argv[])
err = bbf_entry_method(&cli_data->bbf_ctx, BBF_DEL_OBJECT);
if (!err) {
printf("Deleted %s\n", cli_data->bbf_ctx.in_param);
bbf_entry_restart_services(NULL, true);
bbf_entry_services(cli_data->proto, true, true);
} else {
printf("Fault %d: %s\n", err, cli_data->bbf_ctx.fault_msg);
bbf_entry_revert_changes(NULL);
bbf_entry_services(cli_data->proto, false, true);
err = EXIT_FAILURE;
}

View file

@ -880,6 +880,10 @@ void bbfdm_get_value(bbfdm_data_t *data, void *output)
// free
blob_buf_free(&data->bb);
// Apply all bbfdm changes
dmuci_commit_bbfdm();
bbf_cleanup(&data->bbf_ctx);
}
@ -914,6 +918,9 @@ void bbfdm_get_names(bbfdm_data_t *data)
if (data->ctx && data->req)
ubus_send_reply(data->ctx, data->req, data->bbf_ctx.bb.head);
// Apply all bbfdm changes
dmuci_commit_bbfdm();
bbf_cleanup(&data->bbf_ctx);
}
@ -948,6 +955,9 @@ void bbfdm_get_instances(bbfdm_data_t *data)
if (data->ctx && data->req)
ubus_send_reply(data->ctx, data->req, data->bbf_ctx.bb.head);
// Apply all bbfdm changes
dmuci_commit_bbfdm();
bbf_cleanup(&data->bbf_ctx);
}

View file

@ -18,17 +18,8 @@
#include "common.h"
#include "pretty_print.h"
extern struct list_head head_registered_service;
DMOBJ *DEAMON_DM_ROOT_OBJ = NULL;
static struct {
int trans_id;
struct uloop_timeout trans_timeout;
int timeout_ms;
char app[32];
} g_current_trans = {.trans_id=0, .timeout_ms=10000};
static jmp_buf gs_jump_location;
static bool gs_jump_called_by_bbf = false;
@ -189,24 +180,6 @@ void fill_err_code_array(bbfdm_data_t *data, int fault)
blobmsg_close_array(&data->bb, array);
}
static void transaction_timeout_handler(struct uloop_timeout *t __attribute__((unused)))
{
INFO("Transaction timeout called, aborting tid %d", g_current_trans.trans_id);
transaction_abort(NULL, g_current_trans.trans_id);
}
static int get_random_id(void)
{
int ret;
srand(time(0));
ret = rand();
if (!ret)
ret = 1;
return ret;
}
static int CountConsecutiveDigits(char *p)
{
char c;
@ -273,134 +246,6 @@ static int compare_path(const void *arg1, const void *arg2)
return (int)c1 - (int)c2;
}
// Returns transaction id if successful, otherwise 0
int transaction_start(bbfdm_data_t *data, char *app, uint32_t max_timeout)
{
int ret = 0;
uint32_t timeout;
if (g_current_trans.trans_id) {
WARNING("%s Transaction locked by %s", app, g_current_trans.app);
return 0;
}
if (max_timeout > 0) {
timeout = max_timeout;
} else {
timeout = g_current_trans.timeout_ms;
}
ret = data->trans_id ? data->trans_id : get_random_id();
strncpyt(g_current_trans.app, app, 32);
g_current_trans.trans_id = ret;
g_current_trans.trans_timeout.cb = transaction_timeout_handler;
uloop_timeout_set(&g_current_trans.trans_timeout, timeout);
INFO("Transaction created by [%s] id %d, timeout %zd", g_current_trans.app, g_current_trans.trans_id, timeout);
if (strcmp(app, "API") == 0) {
// Call transaction for registered services only if transaction id is defined
handle_transaction_of_registered_service(data->ctx, NULL, &head_registered_service, "start", ret, timeout, 0);
}
return ret;
}
int transaction_status(struct blob_buf *bb)
{
if (g_current_trans.trans_id) {
int64_t rem = uloop_timeout_remaining64(&g_current_trans.trans_timeout);
blobmsg_add_string(bb, "app", g_current_trans.app);
blobmsg_add_string(bb, "tstatus", "running");
blobmsg_add_u64(bb, "remaining_time", rem / 1000);
} else {
blobmsg_add_string(bb, "tstatus", "Idle");
}
return 0;
}
bool is_transaction_running(void)
{
return (g_current_trans.trans_id == 0 ? false : true);
}
bool is_transaction_valid(int trans_id)
{
if (trans_id == 0)
return false;
return (trans_id == g_current_trans.trans_id);
}
int transaction_commit(bbfdm_data_t *data, int trans_id, bool is_service_restart)
{
int ret = -1;
if (is_transaction_valid(trans_id)) {
struct blob_buf *bb = data ? &data->bb : NULL;
void *arr = NULL;
INFO("Commit on-going transaction by %s", g_current_trans.app);
uloop_timeout_cancel(&g_current_trans.trans_timeout);
g_current_trans.trans_id = 0;
g_current_trans.app[0] = '\0';
if (bb) arr = blobmsg_open_array(bb, "updated_services");
bbf_entry_restart_services(bb, is_service_restart);
if (data && data->trans_id) {
// Call transaction for registered services only if transaction id is defined
handle_transaction_of_registered_service(data->ctx, bb, &head_registered_service, "commit", data->trans_id, 0, is_service_restart);
}
if (bb) blobmsg_close_array(bb, arr);
ret = 0;
} else {
WARNING("Transaction id mismatch(%d)", trans_id);
}
return ret;
}
int transaction_abort(bbfdm_data_t *data, int trans_id)
{
int ret = -1;
if (is_transaction_valid(trans_id)) {
struct blob_buf *bb = data ? &data->bb : NULL;
void *arr = NULL;
INFO("Abort on-going transaction by %s", g_current_trans.app);
uloop_timeout_cancel(&g_current_trans.trans_timeout);
g_current_trans.trans_id = 0;
g_current_trans.app[0] = '\0';
if (bb) arr = blobmsg_open_array(bb, "updated_services");
bbf_entry_revert_changes(bb);
if (data && data->trans_id) {
// Call transaction for registered services only if transaction id is defined
handle_transaction_of_registered_service(data->ctx, bb, &head_registered_service, "abort", data->trans_id, 0, 0);
}
if (bb) blobmsg_close_array(bb, arr);
ret = 0;
} else {
WARNING("Transaction id mismatch(%d)", trans_id);
}
return ret;
}
int configure_transaction_timeout(int timeout)
{
if (timeout <= 0)
return -1;
g_current_trans.timeout_ms = timeout * 1000;
return 0;
}
// Returns a pointer to the sorted array of PVs, memory need to be freed by caller
struct pvNode *sort_pv_path(struct list_head *pv_list, size_t pv_count)
{

View file

@ -40,13 +40,6 @@ void fill_err_code_array(bbfdm_data_t *data, int fault);
void bb_add_string(struct blob_buf *bb, const char *name, const char *value);
int transaction_start(bbfdm_data_t *data, char *app, uint32_t max_timeout);
int transaction_commit(bbfdm_data_t *data, int trans_id, bool is_service_restart);
int transaction_abort(bbfdm_data_t *data, int trans_id);
int transaction_status(struct blob_buf *bb);
bool is_transaction_running(void);
bool is_transaction_valid(int trans_id);
int configure_transaction_timeout(int timeout);
struct pvNode *sort_pv_path(struct list_head *pv_list, size_t pv_count);
#endif /* GET_HELPER_H */

View file

@ -113,11 +113,6 @@
"raw",
"pretty"
]
},
"trans_id_t": {
"description": "Required for CUD operation, it shall be same number as got from transaction->start",
"type": "integer",
"minimum": 1
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
@ -406,8 +401,7 @@
"input": {
"type": "object",
"required": [
"path",
"optional"
"path"
],
"properties": {
"path": {
@ -416,14 +410,6 @@
"obj_path": {
"type": "object",
"properties": {}
},
"optional": {
"type": "object",
"properties": {
"transaction_id": {
"$ref": "#/definitions/trans_id_t"
}
}
}
}
},
@ -473,8 +459,7 @@
"input": {
"type": "object",
"required": [
"path",
"transaction_id"
"path"
],
"properties": {
"path": {
@ -488,14 +473,6 @@
"$ref": "#/definitions/query_path_t"
}
]
},
"optional": {
"type": "object",
"properties": {
"transaction_id": {
"$ref": "#/definitions/trans_id_t"
}
}
}
}
},
@ -547,8 +524,7 @@
"type": "object",
"required": [
"path",
"value",
"optional"
"value"
],
"properties": {
"path": {
@ -571,17 +547,6 @@
],
"type": "object",
"properties": {}
},
"optional": {
"type": "object",
"properties": {
"proto": {
"$ref": "#/definitions/proto_t"
},
"transaction_id": {
"$ref": "#/definitions/trans_id_t"
}
}
}
}
},
@ -715,62 +680,6 @@
}
}
},
"transaction": {
"title": "Start/commit/abort/status a transaction before set/add/del operations",
"type": "object",
"properties": {
"input": {
"type": "object",
"properties": {
"cmd": {
"$ref": "#/definitions/trans_type_t"
},
"timeout": {
"type": "integer",
"description": "Timeout (in milliseconds) for the transaction, on timeout changes will be reverted",
"minimum":0
},
"restart_services": {
"description": "If yes, bbfdmd restart the service after CUD operation, else return list of updated uci to handler restart externally.",
"type": "boolean"
},
"optional": {
"type": "object",
"properties": {
"transaction_id": {
"$ref": "#/definitions/trans_id_t"
}
}
}
},
"required": [
"cmd"
]
},
"output": {
"type": "object",
"properties": {
"status": {
"type": "boolean"
},
"transaction_id": {
"type": "integer",
"minimum": 1
},
"error": {
"type": "string"
}
},
"required": [
"status"
]
}
},
"required": [
"input",
"output"
]
},
"service": {
"title": "Register a micro-service in the main service",
"type": "object",

View file

@ -21,7 +21,6 @@ https://dev.iopsys.eu/bbf/bbfdm/-/blob/devel/docs/api/ubus/bbfdm.md
| [schema](#schema) | Method | bbf (this schema) |
| [service](#service) | Method | bbf (this schema) |
| [set](#set) | Method | bbf (this schema) |
| [transaction](#transaction) | Method | bbf (this schema) |
## add
@ -56,7 +55,6 @@ Add a new object in multi instance object
| Property | Type | Required |
| ---------- | ------ | ------------ |
| `obj_path` | object | Optional |
| `optional` | object | **Required** |
| `path` | string | **Required** |
#### obj_path
@ -74,36 +72,6 @@ Add a new object in multi instance object
| -------- | ---- | -------- |
| None | None | None |
#### optional
`optional`
- is **required**
- type: `object`
##### optional Type
`object` with following properties:
| Property | Type | Required |
| ---------------- | ------- | -------- |
| `transaction_id` | integer | Optional |
#### transaction_id
Required for CUD operation, it shall be same number as got from transaction->start
`transaction_id`
- is optional
- type: reference
##### transaction_id Type
`integer`
- minimum value: `1`
#### path
Complete object element path as per TR181
@ -141,7 +109,7 @@ Device.WiFi.
### Ubus CLI Example
```
ubus call bbf add {"path":"dolore magna","optional":{"transaction_id":48031089},"obj_path":{}}
ubus call bbf add {"path":"voluptate veniam","obj_path":{}}
```
### JSONRPC Example
@ -151,12 +119,7 @@ ubus call bbf add {"path":"dolore magna","optional":{"transaction_id":48031089},
"jsonrpc": "2.0",
"id": 0,
"method": "call",
"params": [
"<SID>",
"bbf",
"add",
{ "path": "dolore magna", "optional": { "transaction_id": 48031089 }, "obj_path": {} }
]
"params": ["<SID>", "bbf", "add", { "path": "voluptate veniam", "obj_path": {} }]
}
```
@ -223,10 +186,10 @@ All items must be of the type: Unknown type ``.
{
"results": [
{
"path": "commodo oc",
"data": "reprehenderit amet culpa Excepteur",
"fault": 8107,
"fault_msg": "elit in ea ut non"
"path": "laborum",
"data": "occaecat tempor fugiat sit",
"fault": 9015,
"fault_msg": "cillum deserunt incididunt "
}
]
}
@ -262,41 +225,10 @@ Delete a object instance from multi instance object
`object` with following properties:
| Property | Type | Required |
| ---------- | ------ | ------------ |
| `optional` | object | Optional |
| `path` | string | **Required** |
| `paths` | array | Optional |
#### optional
`optional`
- is optional
- type: `object`
##### optional Type
`object` with following properties:
| Property | Type | Required |
| ---------------- | ------- | -------- |
| `transaction_id` | integer | Optional |
#### transaction_id
Required for CUD operation, it shall be same number as got from transaction->start
`transaction_id`
- is optional
- type: reference
##### transaction_id Type
`integer`
- minimum value: `1`
| Property | Type | Required |
| -------- | ------ | ------------ |
| `path` | string | **Required** |
| `paths` | array | Optional |
#### path
@ -361,7 +293,7 @@ All items must be of the type: Unknown type ``.
### Ubus CLI Example
```
ubus call bbf del {"path":"non ipsu","paths":["dolor nisi amet veniam Duis"],"optional":{"transaction_id":85944852}}
ubus call bbf del {"path":"elit sit Ut magna","paths":["dolor irure"]}
```
### JSONRPC Example
@ -371,12 +303,7 @@ ubus call bbf del {"path":"non ipsu","paths":["dolor nisi amet veniam Duis"],"op
"jsonrpc": "2.0",
"id": 0,
"method": "call",
"params": [
"<SID>",
"bbf",
"del",
{ "path": "non ipsu", "paths": ["dolor nisi amet veniam Duis"], "optional": { "transaction_id": 85944852 } }
]
"params": ["<SID>", "bbf", "del", { "path": "elit sit Ut magna", "paths": ["dolor irure"] }]
}
```
@ -440,7 +367,16 @@ All items must be of the type: Unknown type ``.
### Output Example
```json
{ "results": [{ "path": "cupidatat in", "data": "tempo", "fault": 7626, "fault_msg": "mollit dolore commodo" }] }
{
"results": [
{
"path": "fugiat consequat dolor culpa",
"data": "Lorem et veniam laboris nulla",
"fault": 8956,
"fault_msg": "dolor"
}
]
}
```
## get
@ -619,7 +555,7 @@ All items must be of the type: Unknown type ``.
### Ubus CLI Example
```
ubus call bbf get {"path":"esseco","paths":["esttempor labore nisi cillum sint"],"maxdepth":-31080155,"optional":{"format":"pretty","proto":"cwmp"}}
ubus call bbf get {"path":"amet elit occaecat mag","paths":["in nisi"],"maxdepth":54340400,"optional":{"format":"pretty","proto":"both"}}
```
### JSONRPC Example
@ -634,10 +570,10 @@ ubus call bbf get {"path":"esseco","paths":["esttempor labore nisi cillum sint"]
"bbf",
"get",
{
"path": "esseco",
"paths": ["esttempor labore nisi cillum sint"],
"maxdepth": -31080155,
"optional": { "format": "pretty", "proto": "cwmp" }
"path": "amet elit occaecat mag",
"paths": ["in nisi"],
"maxdepth": 54340400,
"optional": { "format": "pretty", "proto": "both" }
}
]
}
@ -709,11 +645,11 @@ All items must be of the type: Unknown type ``.
{
"results": [
{
"path": "quisExcepteur ullamco magna non et",
"data": "dolor nisi ex eu ut",
"type": "xsd:unsignedLong",
"fault": 8725,
"fault_msg": "elit Lorem"
"path": "do laborum culpa ad",
"data": "anim minim sint pariatur",
"type": "xsd:object",
"fault": 8594,
"fault_msg": "con"
}
]
}
@ -846,7 +782,7 @@ Device.WiFi.
### Ubus CLI Example
```
ubus call bbf instances {"path":"elitanim Lorem eiusmod ea","first_level":false,"optional":{"proto":"both"}}
ubus call bbf instances {"path":"in Lor","first_level":true,"optional":{"proto":"both"}}
```
### JSONRPC Example
@ -856,12 +792,7 @@ ubus call bbf instances {"path":"elitanim Lorem eiusmod ea","first_level":false,
"jsonrpc": "2.0",
"id": 0,
"method": "call",
"params": [
"<SID>",
"bbf",
"instances",
{ "path": "elitanim Lorem eiusmod ea", "first_level": false, "optional": { "proto": "both" } }
]
"params": ["<SID>", "bbf", "instances", { "path": "in Lor", "first_level": true, "optional": { "proto": "both" } }]
}
```
@ -922,11 +853,7 @@ All items must be of the type: Unknown type ``.
### Output Example
```json
{
"results": [
{ "path": "fugiat reprehenderit sunt aliqua est", "fault": 7511, "fault_msg": "Duis ut labore proident" }
]
}
{ "results": [{ "path": "in eiusmod dolore mollit", "fault": 8737, "fault_msg": "eu dolore ipsum" }] }
```
## notify_event
@ -991,7 +918,7 @@ All items must be of the type: Unknown type ``.
### Ubus CLI Example
```
ubus call bbf notify_event {"name":"dolore voluptate minim","input":{}}
ubus call bbf notify_event {"name":"","input":{}}
```
### JSONRPC Example
@ -1001,7 +928,7 @@ ubus call bbf notify_event {"name":"dolore voluptate minim","input":{}}
"jsonrpc": "2.0",
"id": 0,
"method": "call",
"params": ["<SID>", "bbf", "notify_event", { "name": "dolore voluptate minim", "input": {} }]
"params": ["<SID>", "bbf", "notify_event", { "name": "", "input": {} }]
}
```
@ -1101,14 +1028,9 @@ Unknown type ``.
"type": "string",
"default": "pretty",
"enum": ["raw", "pretty"]
},
"trans_id_t": {
"description": "Required for CUD operation, it shall be same number as got from transaction->start",
"type": "integer",
"minimum": 1
}
},
"out": "{\"definitions\":{\"path_t\":{\"description\":\"Complete object element path as per TR181\",\"type\":\"string\",\"minLength\":6,\"maxLength\":1024,\"examples\":[\"Device.\",\"Device.DeviceInfo.Manufacturer\",\"Device.WiFi.SSID.1.\",\"Device.WiFi.\"]},\"schema_path_t\":{\"description\":\"Datamodel object schema path\",\"type\":\"string\",\"minLength\":6,\"maxLength\":1024,\"examples\":[\"Device.Bridging.Bridge.{i}.\",\"Device.DeviceInfo.Manufacturer\",\"Device.WiFi.SSID.{i}.SSID\"]},\"boolean_t\":{\"type\":\"string\",\"enum\":[\"0\",\"1\"]},\"operate_path_t\":{\"description\":\"Datamodel object schema path\",\"type\":\"string\",\"minLength\":6,\"maxLength\":1024,\"examples\":[\"Device.IP.Diagnostics.IPPing()\",\"Device.DHCPv4.Client.{i}.Renew()\",\"Device.FactoryReset()\"]},\"query_path_t\":{\"description\":\"DM object path with search queries\",\"type\":\"string\",\"minLength\":6,\"maxLength\":1024,\"examples\":[\"Device.\",\"Device.DeviceInfo.Manufacturer\",\"Device.WiFi.SSID.1.BSSID\",\"Device.WiFi.SSID.*.BSSID\",\"Device.WiFi.\"]},\"instance_t\":{\"description\":\"Multi object instances\",\"type\":\"string\",\"minLength\":6,\"maxLength\":256},\"proto_t\":{\"type\":\"string\",\"default\":\"both\",\"enum\":[\"usp\",\"cwmp\",\"both\"]},\"type_t\":{\"type\":\"string\",\"enum\":[\"xsd:string\",\"xsd:unsignedInt\",\"xsd:int\",\"xsd:unsignedLong\",\"xsd:long\",\"xsd:boolean\",\"xsd:dateTime\",\"xsd:hexBinary\",\"xsd:object\",\"xsd:command\",\"xsd:event\"]},\"fault_t\":{\"type\":\"integer\",\"minimum\":7000,\"maximum\":9050},\"trans_type_t\":{\"type\":\"string\",\"enum\":[\"start\",\"commit\",\"abort\",\"status\"]},\"srv_type_t\":{\"type\":\"string\",\"enum\":[\"register\",\"list\"]},\"format_t\":{\"type\":\"string\",\"default\":\"pretty\",\"enum\":[\"raw\",\"pretty\"]},\"trans_id_t\":{\"description\":\"Required for CUD operation, it shall be same number as got from transaction->start\",\"type\":\"integer\",\"minimum\":1}}}",
"out": "{\"definitions\":{\"path_t\":{\"description\":\"Complete object element path as per TR181\",\"type\":\"string\",\"minLength\":6,\"maxLength\":1024,\"examples\":[\"Device.\",\"Device.DeviceInfo.Manufacturer\",\"Device.WiFi.SSID.1.\",\"Device.WiFi.\"]},\"schema_path_t\":{\"description\":\"Datamodel object schema path\",\"type\":\"string\",\"minLength\":6,\"maxLength\":1024,\"examples\":[\"Device.Bridging.Bridge.{i}.\",\"Device.DeviceInfo.Manufacturer\",\"Device.WiFi.SSID.{i}.SSID\"]},\"boolean_t\":{\"type\":\"string\",\"enum\":[\"0\",\"1\"]},\"operate_path_t\":{\"description\":\"Datamodel object schema path\",\"type\":\"string\",\"minLength\":6,\"maxLength\":1024,\"examples\":[\"Device.IP.Diagnostics.IPPing()\",\"Device.DHCPv4.Client.{i}.Renew()\",\"Device.FactoryReset()\"]},\"query_path_t\":{\"description\":\"DM object path with search queries\",\"type\":\"string\",\"minLength\":6,\"maxLength\":1024,\"examples\":[\"Device.\",\"Device.DeviceInfo.Manufacturer\",\"Device.WiFi.SSID.1.BSSID\",\"Device.WiFi.SSID.*.BSSID\",\"Device.WiFi.\"]},\"instance_t\":{\"description\":\"Multi object instances\",\"type\":\"string\",\"minLength\":6,\"maxLength\":256},\"proto_t\":{\"type\":\"string\",\"default\":\"both\",\"enum\":[\"usp\",\"cwmp\",\"both\"]},\"type_t\":{\"type\":\"string\",\"enum\":[\"xsd:string\",\"xsd:unsignedInt\",\"xsd:int\",\"xsd:unsignedLong\",\"xsd:long\",\"xsd:boolean\",\"xsd:dateTime\",\"xsd:hexBinary\",\"xsd:object\",\"xsd:command\",\"xsd:event\"]},\"fault_t\":{\"type\":\"integer\",\"minimum\":7000,\"maximum\":9050},\"trans_type_t\":{\"type\":\"string\",\"enum\":[\"start\",\"commit\",\"abort\",\"status\"]},\"srv_type_t\":{\"type\":\"string\",\"enum\":[\"register\",\"list\"]},\"format_t\":{\"type\":\"string\",\"default\":\"pretty\",\"enum\":[\"raw\",\"pretty\"]}}}",
"simpletype": "complex"
}
```
@ -1174,12 +1096,7 @@ Unknown type ``.
"fault_t": { "type": "integer", "minimum": 7000, "maximum": 9050 },
"trans_type_t": { "type": "string", "enum": ["start", "commit", "abort", "status"] },
"srv_type_t": { "type": "string", "enum": ["register", "list"] },
"format_t": { "type": "string", "default": "pretty", "enum": ["raw", "pretty"] },
"trans_id_t": {
"description": "Required for CUD operation, it shall be same number as got from transaction->start",
"type": "integer",
"minimum": 1
}
"format_t": { "type": "string", "default": "pretty", "enum": ["raw", "pretty"] }
}
}
```
@ -1347,7 +1264,7 @@ The value of this property **must** be equal to one of the [known values below](
### Ubus CLI Example
```
ubus call bbf operate {"command":"minim enim au","command_key":"proident adipisicing enim ullamco","input":{},"optional":{"format":"pretty","proto":"cwmp"}}
ubus call bbf operate {"command":"minim tempor dolor ut","command_key":"cillum elit","input":{},"optional":{"format":"raw","proto":"both"}}
```
### JSONRPC Example
@ -1362,10 +1279,10 @@ ubus call bbf operate {"command":"minim enim au","command_key":"proident adipisi
"bbf",
"operate",
{
"command": "minim enim au",
"command_key": "proident adipisicing enim ullamco",
"command": "minim tempor dolor ut",
"command_key": "cillum elit",
"input": {},
"optional": { "format": "pretty", "proto": "cwmp" }
"optional": { "format": "raw", "proto": "both" }
}
]
}
@ -1453,11 +1370,11 @@ All items must be of the type: Unknown type ``.
{
"results": [
{
"path": "quis dolor occaecat tempor",
"data": "1",
"fault": 8348,
"fault_msg": "aliqua dolore ad eu id",
"output": [{ "path": "sit esse dolor", "data": "1", "type": "xsd:command" }]
"path": "sit dolor dolore Lorem eiusmod",
"data": "0",
"fault": 8955,
"fault_msg": "elit occaecat tempor",
"output": [{ "path": "in qui cillum", "data": "0", "type": "xsd:int" }]
}
]
}
@ -1659,7 +1576,7 @@ All items must be of the type: Unknown type ``.
### Ubus CLI Example
```
ubus call bbf schema {"path":"ut nisi Duis aliqua","paths":["anim aliqua in ipsum mollit"],"first_level":true,"commands":true,"events":false,"params":true,"optional":{"proto":"both"}}
ubus call bbf schema {"path":"velit aliquip","paths":["volupta"],"first_level":true,"commands":false,"events":true,"params":true,"optional":{"proto":"cwmp"}}
```
### JSONRPC Example
@ -1674,13 +1591,13 @@ ubus call bbf schema {"path":"ut nisi Duis aliqua","paths":["anim aliqua in ipsu
"bbf",
"schema",
{
"path": "ut nisi Duis aliqua",
"paths": ["anim aliqua in ipsum mollit"],
"path": "velit aliquip",
"paths": ["volupta"],
"first_level": true,
"commands": true,
"events": false,
"commands": false,
"events": true,
"params": true,
"optional": { "proto": "both" }
"optional": { "proto": "cwmp" }
}
]
}
@ -1790,13 +1707,13 @@ All items must be of the type: Unknown type ``.
{
"results": [
{
"path": "laboris",
"data": "1",
"type": "xsd:int",
"fault": 8767,
"fault_msg": "cupidatat amet",
"input": [{ "path": "quiselit ad", "data": "0", "type": "xsd:hexBinary" }],
"output": [{ "path": "ipsum do Lorem nulla officia", "data": "0", "type": "xsd:unsignedLong" }]
"path": "aliquip nisi ven",
"data": "0",
"type": "xsd:object",
"fault": 8719,
"fault_msg": "mollit",
"input": [{ "path": "tempor Ut consectetu", "data": "1", "type": "xsd:long" }],
"output": [{ "path": "velit ipsum e", "data": "1", "type": "xsd:dateTime" }]
}
]
}
@ -1899,7 +1816,7 @@ Object path where the micro-service object will be added
### Ubus CLI Example
```
ubus call bbf service {"cmd":"register","name":"ea","parent_dm":"Ut labore in","object":"Duis commodo"}
ubus call bbf service {"cmd":"register","name":"sit dolore et qui in","parent_dm":"reprehenderit pariatur Excepteur","object":"enim non ex in"}
```
### JSONRPC Example
@ -1913,7 +1830,12 @@ ubus call bbf service {"cmd":"register","name":"ea","parent_dm":"Ut labore in","
"<SID>",
"bbf",
"service",
{ "cmd": "register", "name": "ea", "parent_dm": "Ut labore in", "object": "Duis commodo" }
{
"cmd": "register",
"name": "sit dolore et qui in",
"parent_dm": "reprehenderit pariatur Excepteur",
"object": "enim non ex in"
}
]
}
```
@ -1959,7 +1881,7 @@ ubus call bbf service {"cmd":"register","name":"ea","parent_dm":"Ut labore in","
### Output Example
```json
{ "status": true, "error": "tempor consectetur minim id anim" }
{ "status": false, "error": "magna nostrud Lorem" }
```
## set
@ -1995,7 +1917,6 @@ Set values of datamodel object element
| Property | Type | Required |
| ---------- | ------ | ------------ |
| `obj_path` | object | Optional |
| `optional` | object | **Required** |
| `path` | string | **Required** |
| `value` | string | **Required** |
@ -2026,59 +1947,6 @@ To set multiple values at once, path should be relative to object elements
{ "path": "Device.WiFi.SSID.2.", "obj_path": { "SSID": "test_ssid" } }
```
#### optional
`optional`
- is **required**
- type: `object`
##### optional Type
`object` with following properties:
| Property | Type | Required | Default |
| ---------------- | ------- | -------- | -------- |
| `proto` | string | Optional | `"both"` |
| `transaction_id` | integer | Optional | |
#### proto
`proto`
- is optional
- type: reference
- default: `"both"`
##### proto Type
`string`
The value of this property **must** be equal to one of the [known values below](#set-known-values).
##### proto Known Values
| Value |
| ----- |
| usp |
| cwmp |
| both |
#### transaction_id
Required for CUD operation, it shall be same number as got from transaction->start
`transaction_id`
- is optional
- type: reference
##### transaction_id Type
`integer`
- minimum value: `1`
#### path
DM object path with search queries
@ -2147,7 +2015,7 @@ value of the object element provided in path, path should contains valid writabl
### Ubus CLI Example
```
ubus call bbf set {"path":"amet aute laboris irure ad","value":"est dolore","optional":{"proto":"usp","transaction_id":79839602},"obj_path":{}}
ubus call bbf set {"path":"aliqua","value":"ullamco eu adipisicing tempor","obj_path":{}}
```
### JSONRPC Example
@ -2157,17 +2025,7 @@ ubus call bbf set {"path":"amet aute laboris irure ad","value":"est dolore","opt
"jsonrpc": "2.0",
"id": 0,
"method": "call",
"params": [
"<SID>",
"bbf",
"set",
{
"path": "amet aute laboris irure ad",
"value": "est dolore",
"optional": { "proto": "usp", "transaction_id": 79839602 },
"obj_path": {}
}
]
"params": ["<SID>", "bbf", "set", { "path": "aliqua", "value": "ullamco eu adipisicing tempor", "obj_path": {} }]
}
```
@ -2231,200 +2089,5 @@ All items must be of the type: Unknown type ``.
### Output Example
```json
{ "results": [{ "path": "eiusmod tempor dolore", "data": "1", "fault": 7804, "fault_msg": "amet commodo id tempor" }] }
```
## transaction
### Start/commit/abort/status a transaction before set/add/del operations
`transaction`
- type: `Method`
### transaction Type
`object` with following properties:
| Property | Type | Required |
| -------- | ------ | ------------ |
| `input` | object | **Required** |
| `output` | object | **Required** |
#### input
`input`
- is **required**
- type: `object`
##### input Type
`object` with following properties:
| Property | Type | Required |
| ------------------ | ------- | ------------ |
| `cmd` | string | **Required** |
| `optional` | object | Optional |
| `restart_services` | boolean | Optional |
| `timeout` | integer | Optional |
#### cmd
`cmd`
- is **required**
- type: reference
##### cmd Type
`string`
The value of this property **must** be equal to one of the [known values below](#transaction-known-values).
##### cmd Known Values
| Value |
| ------ |
| start |
| commit |
| abort |
| status |
#### optional
`optional`
- is optional
- type: `object`
##### optional Type
`object` with following properties:
| Property | Type | Required |
| ---------------- | ------- | -------- |
| `transaction_id` | integer | Optional |
#### transaction_id
Required for CUD operation, it shall be same number as got from transaction->start
`transaction_id`
- is optional
- type: reference
##### transaction_id Type
`integer`
- minimum value: `1`
#### restart_services
If yes, bbfdmd restart the service after CUD operation, else return list of updated uci to handler restart externally.
`restart_services`
- is optional
- type: `boolean`
##### restart_services Type
`boolean`
#### timeout
Timeout (in milliseconds) for the transaction, on timeout changes will be reverted
`timeout`
- is optional
- type: `integer`
##### timeout Type
`integer`
- minimum value: `0`
### Ubus CLI Example
```
ubus call bbf transaction {"cmd":"commit","timeout":98560738,"restart_services":false,"optional":{"transaction_id":36502520}}
```
### JSONRPC Example
```json
{
"jsonrpc": "2.0",
"id": 0,
"method": "call",
"params": [
"<SID>",
"bbf",
"transaction",
{ "cmd": "commit", "timeout": 98560738, "restart_services": false, "optional": { "transaction_id": 36502520 } }
]
}
```
#### output
`output`
- is **required**
- type: `object`
##### output Type
`object` with following properties:
| Property | Type | Required |
| ---------------- | ------- | ------------ |
| `error` | string | Optional |
| `status` | boolean | **Required** |
| `transaction_id` | integer | Optional |
#### error
`error`
- is optional
- type: `string`
##### error Type
`string`
#### status
`status`
- is **required**
- type: `boolean`
##### status Type
`boolean`
#### transaction_id
`transaction_id`
- is optional
- type: `integer`
##### transaction_id Type
`integer`
- minimum value: `1`
### Output Example
```json
{ "status": true, "transaction_id": 33849248, "error": "Duis nostrud amet enim" }
{ "results": [{ "path": "ea sed Ut aute", "data": "0", "fault": 7846, "fault_msg": "magna veniam eu fugiat id" }] }
```

View file

@ -113,11 +113,6 @@
"raw",
"pretty"
]
},
"trans_id_t": {
"description": "Required for CUD operation, it shall be same number as got from transaction->start",
"type": "integer",
"minimum": 1
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
@ -406,8 +401,7 @@
"input": {
"type": "object",
"required": [
"path",
"optional"
"path"
],
"properties": {
"path": {
@ -416,14 +410,6 @@
"obj_path": {
"type": "object",
"properties": {}
},
"optional": {
"type": "object",
"properties": {
"transaction_id": {
"$ref": "#/definitions/trans_id_t"
}
}
}
}
},
@ -473,8 +459,7 @@
"input": {
"type": "object",
"required": [
"path",
"transaction_id"
"path"
],
"properties": {
"path": {
@ -488,14 +473,6 @@
"$ref": "#/definitions/query_path_t"
}
]
},
"optional": {
"type": "object",
"properties": {
"transaction_id": {
"$ref": "#/definitions/trans_id_t"
}
}
}
}
},
@ -547,8 +524,7 @@
"type": "object",
"required": [
"path",
"value",
"optional"
"value"
],
"properties": {
"path": {
@ -571,17 +547,6 @@
],
"type": "object",
"properties": {}
},
"optional": {
"type": "object",
"properties": {
"proto": {
"$ref": "#/definitions/proto_t"
},
"transaction_id": {
"$ref": "#/definitions/trans_id_t"
}
}
}
}
},
@ -714,62 +679,6 @@
}
}
}
},
"transaction": {
"title": "Start/commit/abort/status a transaction before set/add/del operations",
"type": "object",
"properties": {
"input": {
"type": "object",
"properties": {
"cmd": {
"$ref": "#/definitions/trans_type_t"
},
"timeout": {
"type": "integer",
"description": "Timeout (in milliseconds) for the transaction, on timeout changes will be reverted",
"minimum":0
},
"restart_services": {
"description": "If yes, bbfdmd restart the service after CUD operation, else return list of updated uci to handler restart externally.",
"type": "boolean"
},
"optional": {
"type": "object",
"properties": {
"transaction_id": {
"$ref": "#/definitions/trans_id_t"
}
}
}
},
"required": [
"cmd"
]
},
"output": {
"type": "object",
"properties": {
"status": {
"type": "boolean"
},
"transaction_id": {
"type": "integer",
"minimum": 1
},
"error": {
"type": "string"
}
},
"required": [
"status"
]
}
},
"required": [
"input",
"output"
]
}
}
}

View file

@ -10,16 +10,15 @@ https://dev.iopsys.eu/bbf/bbfdm/-/blob/devel/docs/api/ubus/bbfdm.md
# bbf
| List of Methods |
| --------------------------- |
| [add](#add) | Method | bbf (this schema) |
| [del](#del) | Method | bbf (this schema) |
| [get](#get) | Method | bbf (this schema) |
| [instances](#instances) | Method | bbf (this schema) |
| [operate](#operate) | Method | bbf (this schema) |
| [schema](#schema) | Method | bbf (this schema) |
| [set](#set) | Method | bbf (this schema) |
| [transaction](#transaction) | Method | bbf (this schema) |
| List of Methods |
| ----------------------- |
| [add](#add) | Method | bbf (this schema) |
| [del](#del) | Method | bbf (this schema) |
| [get](#get) | Method | bbf (this schema) |
| [instances](#instances) | Method | bbf (this schema) |
| [operate](#operate) | Method | bbf (this schema) |
| [schema](#schema) | Method | bbf (this schema) |
| [set](#set) | Method | bbf (this schema) |
## add
@ -54,7 +53,6 @@ Add a new object in multi instance object
| Property | Type | Required |
| ---------- | ------ | ------------ |
| `obj_path` | object | Optional |
| `optional` | object | **Required** |
| `path` | string | **Required** |
#### obj_path
@ -72,36 +70,6 @@ Add a new object in multi instance object
| -------- | ---- | -------- |
| None | None | None |
#### optional
`optional`
- is **required**
- type: `object`
##### optional Type
`object` with following properties:
| Property | Type | Required |
| ---------------- | ------- | -------- |
| `transaction_id` | integer | Optional |
#### transaction_id
Required for CUD operation, it shall be same number as got from transaction->start
`transaction_id`
- is optional
- type: reference
##### transaction_id Type
`integer`
- minimum value: `1`
#### path
Complete object element path as per TR181
@ -139,7 +107,7 @@ Device.WiFi.
### Ubus CLI Example
```
ubus call bbf add {"path":"labore ullamco","optional":{"transaction_id":3482835},"obj_path":{}}
ubus call bbf add {"path":"tempor nostrud in i","obj_path":{}}
```
### JSONRPC Example
@ -149,12 +117,7 @@ ubus call bbf add {"path":"labore ullamco","optional":{"transaction_id":3482835}
"jsonrpc": "2.0",
"id": 0,
"method": "call",
"params": [
"<SID>",
"bbf",
"add",
{ "path": "labore ullamco", "optional": { "transaction_id": 3482835 }, "obj_path": {} }
]
"params": ["<SID>", "bbf", "add", { "path": "tempor nostrud in i", "obj_path": {} }]
}
```
@ -218,16 +181,7 @@ All items must be of the type: Unknown type ``.
### Output Example
```json
{
"results": [
{
"path": "tempor consequat dolor",
"data": "in aliquip",
"fault": 7759,
"fault_msg": "ea irure sunt laboris commodo"
}
]
}
{ "results": [{ "path": "laborum", "data": "mollit enim", "fault": 8110, "fault_msg": "culpa fugiat" }] }
```
## del
@ -260,41 +214,10 @@ Delete a object instance from multi instance object
`object` with following properties:
| Property | Type | Required |
| ---------- | ------ | ------------ |
| `optional` | object | Optional |
| `path` | string | **Required** |
| `paths` | array | Optional |
#### optional
`optional`
- is optional
- type: `object`
##### optional Type
`object` with following properties:
| Property | Type | Required |
| ---------------- | ------- | -------- |
| `transaction_id` | integer | Optional |
#### transaction_id
Required for CUD operation, it shall be same number as got from transaction->start
`transaction_id`
- is optional
- type: reference
##### transaction_id Type
`integer`
- minimum value: `1`
| Property | Type | Required |
| -------- | ------ | ------------ |
| `path` | string | **Required** |
| `paths` | array | Optional |
#### path
@ -359,7 +282,7 @@ All items must be of the type: Unknown type ``.
### Ubus CLI Example
```
ubus call bbf del {"path":"laborum","paths":["aliquip ea"],"optional":{"transaction_id":37938814}}
ubus call bbf del {"path":"culpasunt","paths":["deserunt labore ut consequa"]}
```
### JSONRPC Example
@ -369,12 +292,7 @@ ubus call bbf del {"path":"laborum","paths":["aliquip ea"],"optional":{"transact
"jsonrpc": "2.0",
"id": 0,
"method": "call",
"params": [
"<SID>",
"bbf",
"del",
{ "path": "laborum", "paths": ["aliquip ea"], "optional": { "transaction_id": 37938814 } }
]
"params": ["<SID>", "bbf", "del", { "path": "culpasunt", "paths": ["deserunt labore ut consequa"] }]
}
```
@ -438,11 +356,7 @@ All items must be of the type: Unknown type ``.
### Output Example
```json
{
"results": [
{ "path": "proident eiusmod et Lorem", "data": "ullamco sed", "fault": 8168, "fault_msg": "sint quis nostrud est" }
]
}
{ "results": [{ "path": "dolor laborum esse", "data": "laborum amet Excepteur", "fault": 8595, "fault_msg": "ut" }] }
```
## get
@ -506,10 +420,10 @@ Integer to decide the depth of data model to be parsed
`object` with following properties:
| Property | Type | Required | Default |
| --------------- | ------- | -------- | ---------- |
| `format` | string | Optional | `"pretty"` |
| `proto` | string | Optional | `"both"` |
| Property | Type | Required | Default |
| -------- | ------ | -------- | ---------- |
| `format` | string | Optional | `"pretty"` |
| `proto` | string | Optional | `"both"` |
#### format
@ -621,7 +535,7 @@ All items must be of the type: Unknown type ``.
### Ubus CLI Example
```
ubus call bbf get {"path":"officia","paths":["aliqua nisi sunt"],"maxdepth":-49153948,"optional":{"format":"raw","proto":"cwmp"}}
ubus call bbf get {"path":"officia","paths":["reprehenderit Ut"],"maxdepth":-61996452,"optional":{"format":"pretty","proto":"both"}}
```
### JSONRPC Example
@ -637,9 +551,9 @@ ubus call bbf get {"path":"officia","paths":["aliqua nisi sunt"],"maxdepth":-491
"get",
{
"path": "officia",
"paths": ["aliqua nisi sunt"],
"maxdepth": -49153948,
"optional": { "format": "raw", "proto": "cwmp" }
"paths": ["reprehenderit Ut"],
"maxdepth": -61996452,
"optional": { "format": "pretty", "proto": "both" }
}
]
}
@ -710,13 +624,7 @@ All items must be of the type: Unknown type ``.
```json
{
"results": [
{
"path": "anim sit aute non mollit",
"data": "sed consectetur ipsum exercitation magna",
"type": "xsd:string",
"fault": 8050,
"fault_msg": "nostrud nisi laboris exercitation"
}
{ "path": "proident", "data": "consectetur", "type": "xsd:unsignedLong", "fault": 8751, "fault_msg": "culpa ea" }
]
}
```
@ -781,9 +689,9 @@ gets only first level objects if true
`object` with following properties:
| Property | Type | Required | Default |
| --------------- | ------- | -------- | -------- |
| `proto` | string | Optional | `"both"` |
| Property | Type | Required | Default |
| -------- | ------ | -------- | -------- |
| `proto` | string | Optional | `"both"` |
#### proto
@ -848,7 +756,7 @@ Device.WiFi.
### Ubus CLI Example
```
ubus call bbf instances {"path":"id aliquip","first_level":false,"optional":{"proto":"usp"}}
ubus call bbf instances {"path":"et elit officia ut","first_level":false,"optional":{"proto":"both"}}
```
### JSONRPC Example
@ -862,7 +770,7 @@ ubus call bbf instances {"path":"id aliquip","first_level":false,"optional":{"pr
"<SID>",
"bbf",
"instances",
{ "path": "id aliquip", "first_level": false, "optional": { "proto": "usp" } }
{ "path": "et elit officia ut", "first_level": false, "optional": { "proto": "both" } }
]
}
```
@ -924,7 +832,7 @@ All items must be of the type: Unknown type ``.
### Output Example
```json
{ "results": [{ "path": "ad qui ", "fault": 7181, "fault_msg": "elit" }] }
{ "results": [{ "path": "est do aliqua dolor", "fault": 7913, "fault_msg": "enim ex ipsum tempor elit" }] }
```
## operate
@ -1039,10 +947,10 @@ Input arguments for the operate command as defined in TR-181-2.13
`object` with following properties:
| Property | Type | Required | Default |
| --------------- | ------- | -------- | ---------- |
| `format` | string | Optional | `"pretty"` |
| `proto` | string | Optional | `"both"` |
| Property | Type | Required | Default |
| -------- | ------ | -------- | ---------- |
| `format` | string | Optional | `"pretty"` |
| `proto` | string | Optional | `"both"` |
#### format
@ -1090,7 +998,7 @@ The value of this property **must** be equal to one of the [known values below](
### Ubus CLI Example
```
ubus call bbf operate {"command":"et sit dolor","command_key":"nulla velit ut in Excepteur","input":{},"optional":{"format":"raw","proto":"both"}}
ubus call bbf operate {"command":"irure reprehen","command_key":"tempor ipsum","input":{},"optional":{"format":"raw","proto":"usp"}}
```
### JSONRPC Example
@ -1105,10 +1013,10 @@ ubus call bbf operate {"command":"et sit dolor","command_key":"nulla velit ut in
"bbf",
"operate",
{
"command": "et sit dolor",
"command_key": "nulla velit ut in Excepteur",
"command": "irure reprehen",
"command_key": "tempor ipsum",
"input": {},
"optional": { "format": "raw", "proto": "both" }
"optional": { "format": "raw", "proto": "usp" }
}
]
}
@ -1196,11 +1104,11 @@ All items must be of the type: Unknown type ``.
{
"results": [
{
"path": "aliqua",
"data": "0",
"fault": 7611,
"fault_msg": "ea occaecat voluptate tempor",
"output": [{ "path": "consequat dolor elit", "data": "1", "type": "xsd:int" }]
"path": "ea Lorem officia n",
"data": "1",
"fault": 8207,
"fault_msg": "in Duis eiusmod culpa",
"output": [{ "path": "eiusmod voluptate", "data": "1", "type": "xsd:command" }]
}
]
}
@ -1402,7 +1310,7 @@ All items must be of the type: Unknown type ``.
### Ubus CLI Example
```
ubus call bbf schema {"path":"laboris elit in dolore ali","paths":["pariatur elit eu"],"first_level":false,"commands":false,"events":false,"params":false,"optional":{"proto":"usp"}}
ubus call bbf schema {"path":"sit Lorem aliquip quis adipisic","paths":["cupidatat Excepteur"],"first_level":true,"commands":true,"events":false,"params":true,"optional":{"proto":"both"}}
```
### JSONRPC Example
@ -1417,13 +1325,13 @@ ubus call bbf schema {"path":"laboris elit in dolore ali","paths":["pariatur eli
"bbf",
"schema",
{
"path": "laboris elit in dolore ali",
"paths": ["pariatur elit eu"],
"first_level": false,
"commands": false,
"path": "sit Lorem aliquip quis adipisic",
"paths": ["cupidatat Excepteur"],
"first_level": true,
"commands": true,
"events": false,
"params": false,
"optional": { "proto": "usp" }
"params": true,
"optional": { "proto": "both" }
}
]
}
@ -1533,13 +1441,13 @@ All items must be of the type: Unknown type ``.
{
"results": [
{
"path": "Excepteur irure consequat",
"path": "veniam ipsum ea elit lab",
"data": "0",
"type": "xsd:dateTime",
"fault": 7546,
"fault_msg": "cupidatat Excepteur",
"input": [{ "path": "minim pariatur id laboris ut", "data": "1", "type": "xsd:unsignedInt" }],
"output": [{ "path": "ea enim Excepteur proident est", "data": "1", "type": "xsd:long" }]
"type": "xsd:command",
"fault": 7148,
"fault_msg": "laboris et officia Duis",
"input": [{ "path": "cillum ea", "data": "1", "type": "xsd:dateTime" }],
"output": [{ "path": "esse aliquip in eu et", "data": "1", "type": "xsd:string" }]
}
]
}
@ -1578,7 +1486,6 @@ Set values of datamodel object element
| Property | Type | Required |
| ---------- | ------ | ------------ |
| `obj_path` | object | Optional |
| `optional` | object | **Required** |
| `path` | string | **Required** |
| `value` | string | **Required** |
@ -1609,59 +1516,6 @@ To set multiple values at once, path should be relative to object elements
{ "path": "Device.WiFi.SSID.2.", "obj_path": { "SSID": "test_ssid" } }
```
#### optional
`optional`
- is **required**
- type: `object`
##### optional Type
`object` with following properties:
| Property | Type | Required | Default |
| ---------------- | ------- | -------- | -------- |
| `proto` | string | Optional | `"both"` |
| `transaction_id` | integer | Optional | |
#### proto
`proto`
- is optional
- type: reference
- default: `"both"`
##### proto Type
`string`
The value of this property **must** be equal to one of the [known values below](#set-known-values).
##### proto Known Values
| Value |
| ----- |
| usp |
| cwmp |
| both |
#### transaction_id
Required for CUD operation, it shall be same number as got from transaction->start
`transaction_id`
- is optional
- type: reference
##### transaction_id Type
`integer`
- minimum value: `1`
#### path
DM object path with search queries
@ -1730,7 +1584,7 @@ value of the object element provided in path, path should contains valid writabl
### Ubus CLI Example
```
ubus call bbf set {"path":"nonmagna ut anim","value":"cupidatat","optional":{"proto":"usp","transaction_id":45864115},"obj_path":{}}
ubus call bbf set {"path":"quioccaecat labore elit offic","value":"dolore nostrud dolore anim non","obj_path":{}}
```
### JSONRPC Example
@ -1744,12 +1598,7 @@ ubus call bbf set {"path":"nonmagna ut anim","value":"cupidatat","optional":{"pr
"<SID>",
"bbf",
"set",
{
"path": "nonmagna ut anim",
"value": "cupidatat",
"optional": { "proto": "usp", "transaction_id": 45864115 },
"obj_path": {}
}
{ "path": "quioccaecat labore elit offic", "value": "dolore nostrud dolore anim non", "obj_path": {} }
]
}
```
@ -1814,200 +1663,5 @@ All items must be of the type: Unknown type ``.
### Output Example
```json
{ "results": [{ "path": "pariatur", "data": "0", "fault": 8723, "fault_msg": "ut aliquip" }] }
```
## transaction
### Start/commit/abort/status a transaction before set/add/del operations
`transaction`
- type: `Method`
### transaction Type
`object` with following properties:
| Property | Type | Required |
| -------- | ------ | ------------ |
| `input` | object | **Required** |
| `output` | object | **Required** |
#### input
`input`
- is **required**
- type: `object`
##### input Type
`object` with following properties:
| Property | Type | Required |
| ------------------ | ------- | ------------ |
| `cmd` | string | **Required** |
| `optional` | object | Optional |
| `restart_services` | boolean | Optional |
| `timeout` | integer | Optional |
#### cmd
`cmd`
- is **required**
- type: reference
##### cmd Type
`string`
The value of this property **must** be equal to one of the [known values below](#transaction-known-values).
##### cmd Known Values
| Value |
| ------ |
| start |
| commit |
| abort |
| status |
#### optional
`optional`
- is optional
- type: `object`
##### optional Type
`object` with following properties:
| Property | Type | Required |
| ---------------- | ------- | -------- |
| `transaction_id` | integer | Optional |
#### transaction_id
Required for CUD operation, it shall be same number as got from transaction->start
`transaction_id`
- is optional
- type: reference
##### transaction_id Type
`integer`
- minimum value: `1`
#### restart_services
If yes, bbfdmd restart the service after CUD operation, else return list of updated uci to handler restart externally.
`restart_services`
- is optional
- type: `boolean`
##### restart_services Type
`boolean`
#### timeout
Timeout (in milliseconds) for the transaction, on timeout changes will be reverted
`timeout`
- is optional
- type: `integer`
##### timeout Type
`integer`
- minimum value: `0`
### Ubus CLI Example
```
ubus call bbf transaction {"cmd":"commit","timeout":95277085,"restart_services":false,"optional":{"transaction_id":36491321}}
```
### JSONRPC Example
```json
{
"jsonrpc": "2.0",
"id": 0,
"method": "call",
"params": [
"<SID>",
"bbf",
"transaction",
{ "cmd": "commit", "timeout": 95277085, "restart_services": false, "optional": { "transaction_id": 36491321 } }
]
}
```
#### output
`output`
- is **required**
- type: `object`
##### output Type
`object` with following properties:
| Property | Type | Required |
| ---------------- | ------- | ------------ |
| `error` | string | Optional |
| `status` | boolean | **Required** |
| `transaction_id` | integer | Optional |
#### error
`error`
- is optional
- type: `string`
##### error Type
`string`
#### status
`status`
- is **required**
- type: `boolean`
##### status Type
`boolean`
#### transaction_id
`transaction_id`
- is optional
- type: `integer`
##### transaction_id Type
`integer`
- minimum value: `1`
### Output Example
```json
{ "status": false, "transaction_id": 87022462, "error": "occaecat Excepteur" }
{ "results": [{ "path": "anim no", "data": "0", "fault": 7259, "fault_msg": "ad" }] }
```

View file

@ -26,13 +26,6 @@
"default": "",
"description": "Path for ubus socket to register bbfdmd services"
},
{
"name": "transaction_timeout",
"type": "integer",
"required": "no",
"default": "10",
"description": "Transaction timeout value in seconds"
},
{
"name": "loglevel",
"type": "integer",

View file

@ -84,23 +84,6 @@
<div class="td_row_even">Path for ubus socket to register bbfdmd services</div>
</td>
</tr>
<tr>
<td class="td_row_odd">
<div class="td_row_odd">transaction_timeout</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">integer</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">no</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">10</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">Transaction timeout value in seconds</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">loglevel</div>

View file

@ -14,7 +14,6 @@
"config": {
"loglevel": "1",
"refresh_time": "120",
"transaction_timeout": "30",
"subprocess_level": "2"
},
"input": {
@ -132,7 +131,6 @@ Following are the ubus methods exposed by `bbfdmd` main process:
"operate":{"command":"String","command_key":"String","input":"Table","optional":"Table"}
"add":{"path":"String","obj_path":"Table","optional":"Table"}
"del":{"path":"String","paths":"Array","optional":"Table"}
"transaction":{"cmd":"String","timeout":"Integer","restart_services":"Boolean","optional":"Table"}
"service":{"cmd":"String","name":"String","parent_dm":"String","objects":"Array"}
"notify_event":{"name":"String","input":"Table"}
```
@ -149,19 +147,16 @@ Each datamodel micro-service expose their own ubus object, which is slightly dif
"operate":{"command":"String","command_key":"String","input":"Table","optional":"Table"}
"add":{"path":"String","obj_path":"Table","optional":"Table"}
"del":{"path":"String","paths":"Array","optional":"Table"}
"transaction":{"cmd":"String","timeout":"Integer","restart_services":"Boolean","optional":"Table"}
```
> Note1: `optional` table are present in all methods and it supports below options:
```console
"optional":{"proto":"String", "transaction_id":"Integer", "format":"String"}
"optional":{"proto":"String", "format":"String"}
```
- `proto` in each method specify the data-model prototype('cwmp', 'usp') to use, if not provided default data-model will be used.
- `transaction_id` to define the transaction id number.
- `format` could be 'raw' or 'pretty', to specify the format to use as output, if not provided 'pretty' format will be used.
> Note2: `first_level` true means only get next level objects and false means get all objects recursively

View file

@ -118,8 +118,8 @@ input
pointer to the struct blob_buf object. contains all the packages updated.
bool restart_services
if true packages will be updated through ubus call.
if false packages will be updated through uci.
if true packages will be updated through ubus call bbf.config internally.
if false packages will be updated through ubus call bbf.config externally.
return
None
@ -129,11 +129,15 @@ return
This method is used to revert the changes whenever its state is changed
```
void bbf_entry_revert_changes(struct blob_buf *bb)
void bbf_entry_revert_changes(struct blob_buf *bb, bool revert_changes)
input
struct blob_buf *bb
pointer to the struct blob_buf object. contains all the packages updated.
bool revert_changes
if true changes will be reverted through ubus call bbf.config internally.
if false changes will be reverted through ubus call bbf.config externally.
return
None

View file

@ -55,8 +55,8 @@ supervisorctl status
gcovr -r . --xml -o ./funl-test-coverage.xml
gcovr -r .
echo > memory-report.xml
check_valgrind_xml "Main Service bbfdmd" "/tmp/memory-report.xml"
check_valgrind_xml "/tmp/memory-report.xml" "bbfdmd"
check_valgrind_xml "/tmp/memory-config-report.xml" "bbf.config"
if [ "${fault}" -ne 0 ]; then
echo "Failed running ubus-api-validator fault[$fault]"

View file

@ -11,6 +11,7 @@ make clean -C test/cmocka/
make functional-test -C test/cmocka/
check_ret $?
sleep 10
supervisorctl stop all
supervisorctl status

View file

@ -7,7 +7,7 @@ source ./gitlab-ci/shared.sh
# install required packages
exec_cmd apt update
exec_cmd apt install -y python3-pip iproute2 jq
exec_cmd pip3 install pexpect ubus xlwt
exec_cmd pip3 install pexpect ubus xlwt ValgrindCI
# Make sure that all plugins are removed
[ ! -d "${BBFDM_PLUGIN_DIR}" ] && mkdir -p "${BBFDM_PLUGIN_DIR}"

View file

@ -0,0 +1,5 @@
[program:bbf.config]
priority=5
command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/tmp/memory-config-report.xml --leak-check=full --show-reachable=yes --show-leak-kinds=all --errors-for-leak-kinds=all --error-exitcode=1 --track-origins=yes --leak-resolution=high --show-error-list=yes --child-silent-after-fork=yes /usr/sbin/bbf_configd"

View file

@ -6,7 +6,8 @@ echo "# Preparation script ..."
ln -sf bash /bin/sh
echo "Installing bbfdm rpcd utilities"
cp utilities/files/usr/libexec/rpcd/* /usr/libexec/rpcd/
cp utilities/files/usr/libexec/rpcd/bbf.diag /usr/libexec/rpcd/
cp utilities/files/usr/libexec/rpcd/bbf.secure /usr/libexec/rpcd/
cp -r ./test/files/etc/* /etc/
cp -r ./test/files/usr/* /usr/
@ -14,7 +15,10 @@ cp -r ./test/files/var/* /var/
cp -r ./test/files/tmp/* /tmp/
cp -r ./test/files/lib/* /lib/
mkdir -p /tmp/bbfdm/.bbfdm /tmp/bbfdm/.cwmp /tmp/bbfdm/.usp
cp ./gitlab-ci/core_service.conf /etc/supervisor/conf.d/
cp ./gitlab-ci/reload_service.conf /etc/supervisor/conf.d/
rm -f /etc/bbfdm/dmmap/*

View file

@ -72,6 +72,7 @@ function install_libbbf()
exec_cmd_verbose make install
echo "371d530c95a17d1ca223a29b7a6cdc97e1135c1e0959b51106cca91a0b148b5e42742d372a359760742803f2a44bd88fca67ccdcfaeed26d02ce3b6049cb1e04" > /etc/bbfdm/.secure_hash
cd ..
exec_cmd cp utilities/bbf_configd /usr/sbin/
}
function install_libbbf_test()
@ -100,18 +101,9 @@ function error_on_zero()
}
function check_valgrind_xml() {
echo "${1}: Checking memory leaks..."
echo "checking UninitCondition"
grep -q "<kind>UninitCondition</kind>" ${2}
error_on_zero $?
echo "checking Leak_PossiblyLost"
grep -q "<kind>Leak_PossiblyLost</kind>" ${2}
error_on_zero $?
echo "checking Leak_DefinitelyLost"
grep -q "<kind>Leak_DefinitelyLost</kind>" ${2}
error_on_zero $?
echo "Memory check [$@] ..."
valgrind-ci ${1} --summary
exec_cmd valgrind-ci ${1} --abort-on-errors
}
function generate_report()

View file

@ -174,6 +174,9 @@ struct dmctx {
struct list_head *memhead;
struct blob_buf bb;
DMOBJ *dm_entryobj;
struct uci_context *config_uci_ctx;
struct uci_context *dmmap_uci_ctx;
struct uci_context *varstate_uci_ctx;
bool nextlevel;
bool iswildcard;
int faultcode;
@ -193,7 +196,6 @@ struct dmctx {
bool isevent;
bool isinfo;
bool disable_mservice_browse;
int trans_id;
};
typedef struct dmnode {

View file

@ -1285,7 +1285,6 @@ static int add_ubus_object(struct dmctx *dmctx, struct dmnode *node)
json_object *in_args = json_object_new_object();
json_object_object_add(in_args, "proto", json_object_new_string((dmctx->dm_type == BBFDM_BOTH) ? "both" : (dmctx->dm_type == BBFDM_CWMP) ? "cwmp" : "usp"));
json_object_object_add(in_args, "format", json_object_new_string("raw"));
json_object_object_add(in_args, "transaction_id", json_object_new_int(dmctx->trans_id));
dmubus_call(ubus_name, "add",
UBUS_ARGS{
@ -1331,7 +1330,6 @@ static int del_ubus_object(struct dmctx *dmctx, struct dmnode *node)
json_object *in_args = json_object_new_object();
json_object_object_add(in_args, "proto", json_object_new_string((dmctx->dm_type == BBFDM_BOTH) ? "both" : (dmctx->dm_type == BBFDM_CWMP) ? "cwmp" : "usp"));
json_object_object_add(in_args, "format", json_object_new_string("raw"));
json_object_object_add(in_args, "transaction_id", json_object_new_int(dmctx->trans_id));
dmubus_call(ubus_name, "del",
UBUS_ARGS{
@ -1405,7 +1403,6 @@ static int set_ubus_value(struct dmctx *dmctx, struct dmnode *node)
json_object *in_args = json_object_new_object();
json_object_object_add(in_args, "proto", json_object_new_string((dmctx->dm_type == BBFDM_BOTH) ? "both" : (dmctx->dm_type == BBFDM_CWMP) ? "cwmp" : "usp"));
json_object_object_add(in_args, "format", json_object_new_string("raw"));
json_object_object_add(in_args, "transaction_id", json_object_new_int(dmctx->trans_id));
if (is_reference_parameter(ubus_name, dmctx->in_param, in_args, &ref_value)) {
ref_value = get_value_by_reference(dmctx, ref_value);

View file

@ -17,7 +17,6 @@
#include "dmcommon.h"
#include "dmentry.h"
LIST_HEAD(head_package_change);
LIST_HEAD(global_memhead);
static struct dm_fault DM_FAULT_ARRAY[] = {
@ -49,16 +48,16 @@ void bbf_ctx_init(struct dmctx *ctx, DMOBJ *tEntryObj)
ctx->dm_entryobj = tEntryObj;
bbfdm_init_mem(ctx);
dm_uci_init();
bbfdm_uci_init(ctx);
}
void bbf_ctx_clean(struct dmctx *ctx)
{
blob_buf_free(&ctx->bb);
dm_uci_exit();
dmubus_free();
bbfdm_uci_exit(ctx);
bbfdm_clean_mem(ctx);
dmubus_free();
}
void bbf_ctx_init_sub(struct dmctx *ctx, DMOBJ *tEntryObj)
@ -216,18 +215,12 @@ int bbf_entry_method(struct dmctx *ctx, int cmd)
break;
case BBF_SET_VALUE:
fault = dm_entry_set_value(ctx);
if (!fault)
dmuci_change_packages(&head_package_change);
break;
case BBF_ADD_OBJECT:
fault = dm_entry_add_object(ctx);
if (!fault)
dmuci_change_packages(&head_package_change);
break;
case BBF_DEL_OBJECT:
fault = dm_entry_delete_object(ctx);
if (!fault)
dmuci_change_packages(&head_package_change);
break;
case BBF_OPERATE:
fault = dm_entry_operate(ctx);
@ -349,40 +342,19 @@ bool adm_entry_object_exists(struct dmctx *ctx, char *param) // To be removed la
return dmctx.match;
}
void bbf_entry_restart_services(struct blob_buf *bb, bool restart_services)
void bbf_entry_services(unsigned int proto, bool is_commit, bool reload_required)
{
struct package_change *pc = NULL;
struct blob_buf bb = {0};
list_for_each_entry(pc, &head_package_change, list) {
memset(&bb, 0, sizeof(struct blob_buf));
if (bb) blobmsg_add_string(bb, NULL, pc->package);
blob_buf_init(&bb, 0);
if (restart_services) {
// Internal transaction: need to commit the changes
dmubus_call_set("uci", "commit", UBUS_ARGS{{"config", pc->package, String}}, 1);
}
}
blobmsg_add_string(&bb, "proto", (proto == BBFDM_CWMP) ? "cwmp": (proto == BBFDM_USP) ? "usp" : "both");
blobmsg_add_u8(&bb, "monitor", false);
blobmsg_add_u8(&bb, "reload", reload_required);
if (restart_services) {
// Internal transaction: need to commit the changes
dmuci_commit_bbfdm();
}
dmubus_call_blob_msg_set("bbf.config", is_commit ? "commit" : "revert", &bb);
free_all_list_package_change(&head_package_change);
}
void bbf_entry_revert_changes(struct blob_buf *bb)
{
struct package_change *pc = NULL;
list_for_each_entry(pc, &head_package_change, list) {
if (bb) blobmsg_add_string(bb, NULL, pc->package);
dmubus_call_set("uci", "revert", UBUS_ARGS{{"config", pc->package, String}}, 1);
}
dmuci_revert_bbfdm();
free_all_list_package_change(&head_package_change);
blob_buf_free(&bb);
}

View file

@ -32,14 +32,10 @@ int dm_validate_allowed_objects(struct dmctx *ctx, struct dm_reference *referenc
bool adm_entry_object_exists(struct dmctx *ctx, char *param); // To be removed later!!!!!!!!!!!! (After moving all Objects outside bbfdm core)
void bbf_entry_restart_services(struct blob_buf *bb, bool restart_services);
void bbf_entry_revert_changes(struct blob_buf *bb);
void bbf_entry_services(unsigned int proto, bool is_commit, bool reload_required);
void get_list_of_registered_service(struct list_head *srvlist, struct blob_buf *bb);
bool load_service(DMOBJ *main_dm, struct list_head *srv_list, char *srv_name, char *srv_parent_dm, char *srv_obj);
void free_services_from_list(struct list_head *clist);
int handle_transaction_of_registered_service(struct ubus_context *ctx, struct blob_buf *trans_bb, struct list_head *srvlist,
const char *trans_cmd, int trans_id, uint32_t max_timeout, bool service_restart);
#endif //__DMENTRY_H__

View file

@ -122,71 +122,6 @@ bool load_service(DMOBJ *main_dm, struct list_head *srv_list, char *srv_name, ch
return true;
}
static void ubus_transaction_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg)
{
struct blob_attr *tb[1] = {0};
const struct blobmsg_policy p[1] = {
{ "updated_services", BLOBMSG_TYPE_ARRAY },
};
if (msg == NULL || req == NULL)
return;
struct blob_buf *bb = (struct blob_buf *)req->priv;
if (bb == NULL)
return;
blobmsg_parse(p, 1, tb, blobmsg_data(msg), blobmsg_len(msg));
if (tb[0]) {
struct blob_attr *service = NULL;
size_t rem;
blobmsg_for_each_attr(service, tb[0], rem) {
blobmsg_add_string(bb, NULL, blobmsg_get_string(service));
}
}
}
int handle_transaction_of_registered_service(struct ubus_context *ctx, struct blob_buf *trans_bb, struct list_head *srvlist,
const char *trans_cmd, int trans_id, uint32_t max_timeout, bool service_restart)
{
struct service *srv = NULL;
if (is_micro_service == true) // This should be called only from main daemon
return -1;
if (ctx == NULL || trans_id == 0)
return -1;
list_for_each_entry(srv, srvlist, list) {
struct blob_buf bb = {0};
void *table = NULL;
uint32_t ubus_id;
// check if object already present
int ret = ubus_lookup_id(ctx, srv->name, &ubus_id);
if (ret != 0)
continue;
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
blobmsg_add_string(&bb, "cmd", trans_cmd);
blobmsg_add_u8(&bb, "restart_services", service_restart);
blobmsg_add_u32(&bb, "timeout", max_timeout);
table = blobmsg_open_table(&bb, "optional");
blobmsg_add_u32(&bb, "transaction_id", trans_id);
blobmsg_close_table(&bb, table);
ubus_invoke(ctx, ubus_id, "transaction", bb.head, ubus_transaction_callback, (void *)trans_bb, 5000);
blob_buf_free(&bb);
}
return 0;
}
void get_list_of_registered_service(struct list_head *srvlist, struct blob_buf *bb)
{
struct service *srv = NULL;

View file

@ -260,7 +260,7 @@ static int dmubus_call_blob_internal(char *obj, char *method, void *value, int t
int dmubus_call_blob(char *obj, char *method, void *value, json_object **resp)
{
return dmubus_call_blob_internal(obj, method, value, UBUS_TIMEOUT, resp);
return dmubus_call_blob_internal(obj, method, value, UBUS_TIMEOUT, resp);
}
int dmubus_call_blob_blocking(char *obj, char *method, void *value, json_object **resp)
@ -280,6 +280,47 @@ int dmubus_call_blob_set(char *obj, char *method, void *value)
return rc;
}
static int dmubus_call_blob_msg_internal(char *obj, char *method, struct blob_buf *data, int timeout, json_object **resp)
{
uint32_t id = 0;
int rc = -1;
json_res = NULL;
if (resp)
*resp = NULL;
if (ubus_ctx == NULL) {
ubus_ctx = dm_libubus_init();
if (ubus_ctx == NULL) {
printf("UBUS context is null\n\r");
return -1;
}
}
if (!ubus_lookup_id(ubus_ctx, obj, &id)) {
rc = ubus_invoke(ubus_ctx, id, method, data->head,
receive_call_result_data, NULL, timeout);
}
if (resp)
*resp = json_res;
return rc;
}
int dmubus_call_blob_msg_set(char *obj, char *method, struct blob_buf *data)
{
int rc = dmubus_call_blob_msg_internal(obj, method, data, UBUS_TIMEOUT, NULL);
if (json_res != NULL) {
json_object_put(json_res);
json_res = NULL;
}
return rc;
}
/* Based on an efficient hash function published by D. J. Bernstein
*/
static unsigned int djbhash(unsigned hash, const char *data, unsigned len)

View file

@ -44,6 +44,8 @@ int dmubus_call_blob(char *obj, char *method, void *value, json_object **resp);
int dmubus_call_blob_blocking(char *obj, char *method, void *value, json_object **resp);
int dmubus_call_blob_set(char *obj, char *method, void *value);
int dmubus_call_blob_msg_set(char *obj, char *method, struct blob_buf *blob_msg);
void dmubus_free();
bool dmubus_object_method_exists(const char *obj);

View file

@ -19,50 +19,62 @@
static struct uci_context *uci_ctx = NULL;
static char *db_config = NULL;
NEW_UCI_PATH(bbfdm, BBFDM_CONFIG, BBFDM_SAVEDIR)
NEW_UCI_PATH(varstate, VARSTATE_CONFDIR, VARSTATE_SAVEDIR)
NEW_UCI_PATH(bbfdm)
NEW_UCI_PATH(varstate)
int dmuci_init(void)
static void bbfdm_uci_init_ctx(struct uci_context **uci_ctx, const char *confdir, const char *savedir)
{
if (uci_ctx == NULL) {
uci_ctx = uci_alloc_context();
if (!uci_ctx)
return -1;
uci_set_confdir(uci_ctx, UCI_CONFIG_DIR);
*uci_ctx = uci_alloc_context();
if (!*uci_ctx) {
BBF_ERR("Failed to allocate memory for (%s) && (%s)!!!", confdir, savedir);
return;
}
return 0;
uci_set_confdir(*uci_ctx, confdir);
uci_set_savedir(*uci_ctx, savedir);
}
void dmuci_exit(void)
void bbfdm_uci_init(struct dmctx *bbf_ctx)
{
if (uci_ctx)
uci_free_context(uci_ctx);
uci_ctx = NULL;
}
if (bbf_ctx->dm_type == BBFDM_CWMP) {
bbfdm_uci_init_ctx(&bbf_ctx->config_uci_ctx, "/etc/config/", "/tmp/bbfdm/.cwmp/config/");
bbfdm_uci_init_ctx(&bbf_ctx->dmmap_uci_ctx, "/etc/bbfdm/dmmap/", "/tmp/bbfdm/.cwmp/dmmap/");
} else if (bbf_ctx->dm_type == BBFDM_USP) {
bbfdm_uci_init_ctx(&bbf_ctx->config_uci_ctx, "/etc/config/", "/tmp/bbfdm/.usp/config/");
bbfdm_uci_init_ctx(&bbf_ctx->dmmap_uci_ctx, "/etc/bbfdm/dmmap/", "/tmp/bbfdm/.usp/dmmap/");
} else {
bbfdm_uci_init_ctx(&bbf_ctx->config_uci_ctx, "/etc/config/", "/tmp/bbfdm/.bbfdm/config/");
bbfdm_uci_init_ctx(&bbf_ctx->dmmap_uci_ctx, "/etc/bbfdm/dmmap/", "/tmp/bbfdm/.bbfdm/dmmap/");
}
int dm_uci_init(void)
{
dmuci_init();
bbfdm_uci_init_ctx(&bbf_ctx->varstate_uci_ctx, "/var/state/", "/tmp/bbfdm/.varstate/");
dmuci_init_varstate();
dmuci_init_bbfdm();
uci_ctx = bbf_ctx->config_uci_ctx;
uci_ctx_bbfdm = bbf_ctx->dmmap_uci_ctx;
uci_ctx_varstate = bbf_ctx->varstate_uci_ctx;
db_config = ETC_DB_CONFIG;
return 0;
}
int dm_uci_exit(void)
void bbfdm_uci_exit(struct dmctx *bbf_ctx)
{
dmuci_exit();
if (bbf_ctx->config_uci_ctx) {
uci_free_context(bbf_ctx->config_uci_ctx);
bbf_ctx->config_uci_ctx = NULL;
uci_ctx = NULL;
}
dmuci_exit_varstate();
if (bbf_ctx->dmmap_uci_ctx) {
uci_free_context(bbf_ctx->dmmap_uci_ctx);
bbf_ctx->dmmap_uci_ctx = NULL;
uci_ctx_bbfdm = NULL;
}
dmuci_exit_bbfdm();
return 0;
if (bbf_ctx->varstate_uci_ctx) {
uci_free_context(bbf_ctx->varstate_uci_ctx);
bbf_ctx->varstate_uci_ctx = NULL;
uci_ctx_varstate = NULL;
}
}
char *dmuci_list_to_string(struct uci_list *list, const char *delimitor)
@ -101,30 +113,6 @@ static inline bool check_section_name(const char *str, bool name)
return true;
}
static void add_list_package_change(struct list_head *clist, char *package)
{
struct package_change *pc = NULL;
list_for_each_entry(pc, clist, list) {
if (DM_STRCMP(pc->package, package) == 0)
return;
}
pc = calloc(1, sizeof(struct package_change));
list_add_tail(&pc->list, clist);
pc->package = strdup(package);
}
void free_all_list_package_change(struct list_head *clist)
{
struct package_change *pc;
while (clist->next != clist) {
pc = list_entry(clist->next, struct package_change, list);
list_del(&pc->list);
free(pc->package);
free(pc);
}
}
/**** UCI LOOKUP ****/
int dmuci_lookup_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *package, char *section, char *option, char *value)
{
@ -466,34 +454,6 @@ int dmuci_revert(void)
return 0;
}
/**** UCI CHANGES PACKAGES *****/
int dmuci_change_packages(struct list_head *clist)
{
char **configs = NULL;
char **p;
if (uci_list_configs(uci_ctx, &configs) != UCI_OK)
return -1;
if (!configs)
return -1;
for (p = configs; *p; p++) {
struct uci_ptr ptr = {0};
if (uci_lookup_ptr(uci_ctx, &ptr, *p, true) != UCI_OK)
continue;
if (uci_list_empty(&ptr.p->delta))
continue;
add_list_package_change(clist, *p);
}
free(configs);
return 0;
}
/**** UCI SET *****/
int dmuci_set_value(char *package, char *section, char *option, char *value)
{

View file

@ -24,19 +24,11 @@
#include <uci.h>
#include <libubox/list.h>
#include "dmapi.h"
#ifndef ETC_DB_CONFIG
#define ETC_DB_CONFIG "/etc/board-db/config"
#endif
#define VARSTATE_CONFIG "/var/state"
#ifndef BBFDM_CONFIG
#define BBFDM_CONFIG "/etc/bbfdm/dmmap"
#endif
#define BBFDM_SAVEDIR "/tmp/.bbfdm"
#ifndef UCI_CONFIG_DIR
#define UCI_CONFIG_DIR "/etc/config/"
#endif
#define VARSTATE_CONFDIR "/var/state/"
#define VARSTATE_SAVEDIR "/tmp/.bbfdm_var"
struct package_change
{
@ -153,10 +145,8 @@ static inline void uci_list_init(struct uci_list *ptr)
ptr->next = ptr;
}
#define NEW_UCI_PATH(UCI_PATH, CPATH, DPATH) \
#define NEW_UCI_PATH(UCI_PATH) \
struct uci_context *uci_ctx_##UCI_PATH = NULL; \
const char *uci_savedir_##UCI_PATH = DPATH; \
const char *uci_confdir_##UCI_PATH = CPATH; \
int dmuci_get_section_type_##UCI_PATH(char *package, char *section,char **value) \
{\
struct uci_context *save_uci_ctx; \
@ -166,23 +156,6 @@ int dmuci_get_section_type_##UCI_PATH(char *package, char *section,char **value)
uci_ctx = save_uci_ctx; \
return res; \
}\
int dmuci_init_##UCI_PATH(void) \
{\
if (uci_ctx_##UCI_PATH == NULL) { \
uci_ctx_##UCI_PATH = uci_alloc_context(); \
if (!uci_ctx_##UCI_PATH) \
return -1; \
uci_add_delta_path(uci_ctx_##UCI_PATH, uci_ctx_##UCI_PATH->savedir); \
uci_set_savedir(uci_ctx_##UCI_PATH, uci_savedir_##UCI_PATH); \
uci_set_confdir(uci_ctx_##UCI_PATH, uci_confdir_##UCI_PATH); \
} \
return 0; \
}\
void dmuci_exit_##UCI_PATH(void) \
{\
if (uci_ctx_##UCI_PATH) uci_free_context(uci_ctx_##UCI_PATH);\
uci_ctx_##UCI_PATH = NULL; \
}\
int dmuci_get_option_value_string_##UCI_PATH(char *package, char *section, char *option, char **value) \
{\
struct uci_context *save_uci_ctx; \
@ -328,12 +301,10 @@ int dmuci_delete_by_section_unnamed_##UCI_PATH(struct uci_section *s, char *opti
return res; \
}\
int dmuci_init(void);
void dmuci_exit(void);
int dm_uci_init(void);
int dm_uci_exit(void);
void bbfdm_uci_init(struct dmctx *bbf_ctx);
void bbfdm_uci_exit(struct dmctx *bbf_ctx);
char *dmuci_list_to_string(struct uci_list *list, const char *delimitor);
void free_all_list_package_change(struct list_head *clist);
int dmuci_lookup_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *package, char *section, char *option, char *value);
int dmuci_import(char *package_name, const char *input_path);
int dmuci_export_package(char *package, const char *output_path);
@ -344,7 +315,6 @@ int dmuci_save_package(char *package);
int dmuci_save(void);
int dmuci_revert_package(char *package);
int dmuci_revert(void);
int dmuci_change_packages(struct list_head *clist);
int dmuci_get_section_type(char *package, char *section, char **value);
int dmuci_get_option_value_string(char *package, char *section, char *option, char **value);
@ -386,12 +356,8 @@ int dmuci_save_package_varstate(char *package);
int dmuci_revert_package_varstate(char *package);
struct uci_section *dmuci_walk_section_bbfdm(char *package, char *stype, void *arg1, void *arg2, int cmp , int (*filter)(struct uci_section *s, void *value), struct uci_section *prev_section, int walk);
struct uci_section *dmuci_walk_section_varstate(char *package, char *stype, void *arg1, void *arg2, int cmp , int (*filter)(struct uci_section *s, void *value), struct uci_section *prev_section, int walk);
int dmuci_init_bbfdm(void);
void dmuci_exit_bbfdm(void);
void commit_and_free_uci_ctx_bbfdm(char *dmmap_config);
int dmuci_add_section_varstate(char *package, char *stype, struct uci_section **s);
int dmuci_init_varstate(void);
void dmuci_exit_varstate(void);
int db_get_value_string(char *package, char *section, char *option, char **value);
int dmuci_get_option_value_string_varstate(char *package, char *section, char *option, char **value);
int dmuci_set_value_varstate(char *package, char *section, char *option, char *value);

View file

@ -11,15 +11,15 @@ static struct dmctx bbf_ctx = {0};
static int setup_teardown(void **state)
{
bbfdm_init_mem(&bbf_ctx);
dm_uci_init();
bbfdm_uci_init(&bbf_ctx);
return 0;
}
static int group_teardown(void **state)
{
dm_uci_exit();
dmubus_free();
bbfdm_uci_exit(&bbf_ctx);
bbfdm_clean_mem(&bbf_ctx);
dmubus_free();
return 0;
}

View file

@ -32,7 +32,7 @@ static int teardown_commit(void **state)
{
struct dmctx *ctx = (struct dmctx *) *state;
bbf_entry_restart_services(NULL, true);
bbf_entry_services(ctx->dm_type, true, true);
bbf_ctx_clean(ctx);
free(ctx);
@ -183,6 +183,7 @@ static void test_api_bbfdm_get_set_json_v1_parameter(void **state)
ctx->in_value = "iopsys_test";
fault = bbf_entry_method(ctx, BBF_SET_VALUE);
assert_int_equal(fault, 0);
dmuci_commit_package("users");
// get value ==> expected "0" error
ctx->in_param = "Device.UCI_TEST_V1.Password";
@ -285,6 +286,7 @@ static void test_api_bbfdm_get_set_json_v1_parameter(void **state)
ctx->in_value = "owsd_pwd";
fault = bbf_entry_method(ctx, BBF_SET_VALUE);
assert_int_equal(fault, 0);
dmuci_commit_package("owsd");
// get value ==> expected "0" error
ctx->in_param = "Device.UCI_TEST_V1.OWSD.3.Password";

View file

@ -32,7 +32,7 @@ static int teardown_commit(void **state)
{
struct dmctx *ctx = (struct dmctx *) *state;
bbf_entry_restart_services(NULL, true);
bbf_entry_services(ctx->dm_type, true, true);
bbf_ctx_clean(ctx);
free(ctx);
@ -43,7 +43,7 @@ static int teardown_revert(void **state)
{
struct dmctx *ctx = (struct dmctx *) *state;
bbf_entry_revert_changes(NULL);
bbf_entry_services(ctx->dm_type, false, true);
bbf_ctx_clean(ctx);
free(ctx);
@ -553,7 +553,7 @@ static void test_api_bbfdm_library_get_value(void **state)
bbf_ctx_clean(ctx);
bbf_ctx_init(ctx, TR181_ROOT_TREE);
ctx->in_param = "Device.WiFi.SSID.1.Enable";
ctx->in_param = "Device.WiFi.SSID.2.Enable";
fault = bbf_entry_method(ctx, BBF_GET_VALUE);
assert_int_equal(fault, 0);
@ -580,7 +580,7 @@ static void test_api_bbfdm_library_delete_object(void **state)
struct dmctx *ctx = (struct dmctx *) *state;
int fault = 0;
ctx->in_param = "Device.WiFi.SSID.1.";
ctx->in_param = "Device.WiFi.SSID.2.";
fault = bbf_entry_method(ctx, BBF_DEL_OBJECT);
assert_int_equal(fault, 0);

View file

@ -1,8 +1,7 @@
{
"daemon": {
"config": {
"loglevel": "1",
"transaction_timeout": "30",
"loglevel": "4",
"subprocess_level": "2"
},
"input": {

View file

@ -118,22 +118,6 @@
},
"rc": 0
},
{
"method": "transaction",
"args": {
"cmd": "commit",
"optional":{"transaction_id":123}
},
"rc": 0
},
{
"method": "transaction",
"args": {
"cmd": "abort",
"optional":{"transaction_id":123}
},
"rc": 0
},
{
"method": "get",
"args": {
@ -146,8 +130,7 @@
"method": "set",
"args": {
"path": "Device.WiFi.SSID.1.",
"obj_path": {"Alias":"test", "Enable":"1"},
"optional":{"transaction_id":123}
"obj_path": {"Alias":"test", "Enable":"1"}
},
"rc": 0
}

View file

@ -1,40 +0,0 @@
#!/usr/bin/python3
import ubus
import json
import pathlib
TEST_NAME = "Validate fault on invalid transaction id with bbf"
print("Running: " + TEST_NAME)
def fault_wrong_transaction(cmd, param, efault):
out = ubus.call("bbfdm", cmd, param)
assert out[0]['results'][0]['fault'] == efault, "FAIL: for " + cmd + str(param) + " output " + str(out)
sock = pathlib.Path('/var/run/ubus/ubus.sock')
if sock.exists ():
assert ubus.connect('/var/run/ubus/ubus.sock')
else:
assert ubus.connect()
fault_wrong_transaction("set", {"path":"Device.WiFi.SSID.1.SSID", "value":"abc", "optional":{"format":"raw", "transaction_id":1234}}, 7003)
fault_wrong_transaction("set", {"path":"Device.WiFi.SSID.1.SSID", "value":"abc", "optional":{"format":"raw", "proto":"usp", "transaction_id":1234}}, 7003)
fault_wrong_transaction("set", {"path":"Device.WiFi.SSID.1.SSID", "value":"abc", "optional":{"format":"raw", "proto":"cwmp", "transaction_id":1234}}, 9002)
fault_wrong_transaction("set", {"path":"Device.WiFi.SSID.1.", "obj_path":{"SSID":"abc"}, "optional":{"format":"raw", "transaction_id":1234}}, 7003)
fault_wrong_transaction("set", {"path":"Device.WiFi.SSID.1.", "obj_path":{"SSID":"abc"}, "optional":{"format":"raw", "transaction_id":1234, "proto":"usp"}}, 7003)
fault_wrong_transaction("set", {"path":"Device.WiFi.SSID.1.", "obj_path":{"SSID":"abc"}, "optional":{"format":"raw", "transaction_id":1234, "proto":"cwmp"}}, 9002)
fault_wrong_transaction("add", {"path":"Device.WiFi.SSID.", "optional":{"format":"raw", "transaction_id":1234}}, 7003)
fault_wrong_transaction("add", {"path":"Device.WiFi.SSID.", "optional":{"format":"raw", "transaction_id":1234, "proto":"usp"}}, 7003)
fault_wrong_transaction("add", {"path":"Device.WiFi.SSID.", "optional":{"format":"raw", "transaction_id":1234, "proto":"cwmp"}}, 9002)
fault_wrong_transaction("del", {"path":"Device.WiFi.SSID.1", "optional":{"format":"raw", "transaction_id":1234}}, 7003)
fault_wrong_transaction("del", {"path":"Device.WiFi.SSID.1", "optional":{"format":"raw", "transaction_id":1234, "proto":"usp"}}, 7003)
fault_wrong_transaction("del", {"path":"Device.WiFi.SSID.1", "optional":{"format":"raw", "transaction_id":1234, "proto":"cwmp"}}, 9002)
ubus.disconnect()
print("PASS: " + TEST_NAME)

View file

@ -1,31 +0,0 @@
#!/usr/bin/python3
import pexpect
import os
print("Running: Schema updater notification validation")
ret = 1
child = pexpect.spawn('ubus monitor')
# force change in schema, by removing dependency uci file
os.rename("/etc/config/dropbear", "/etc/config/dropbear_1")
try:
ret = child.expect('notify', timeout=65)
except:
print("FAIL: Schema updater notification")
if ret == 0:
try:
ret = child.expect('bbfdm.DelObj')
except:
print("FAIL: Schema updater notification")
# Revert back uci changes
os.rename("/etc/config/dropbear_1", "/etc/config/dropbear")
if ret == 0:
print("PASS: Schema updater notification")
exit(ret)

View file

@ -324,7 +324,7 @@ def fill_list_supported_dm():
DB[:] = remove_duplicate_elements(DB)
def clone_git_repository(repo, version=None):
repo_path='.repo/'+os.path.basename(repo).replace('.git','')
repo_path='/tmp/repo/'+os.path.basename(repo).replace('.git','')
if os.path.exists(repo_path):
print(f' {repo} already exists at {repo_path} !')
return True
@ -354,7 +354,7 @@ def download_and_build_plugins(plugins, vendor_prefix):
print("Generating data models from defined plugins...")
remove_folder(".repo")
remove_folder("/tmp/repo")
for plugin_index, plugin in enumerate(plugins):
@ -375,7 +375,7 @@ def download_and_build_plugins(plugins, vendor_prefix):
print(f' - Processing plugin: MS({is_microservice}) {plugin}')
if proto == "git":
repo_path = ".repo/"+name
repo_path = "/tmp/repo/"+name
version = get_option_value(plugin, "version")
@ -394,9 +394,9 @@ def download_and_build_plugins(plugins, vendor_prefix):
BBF_ERROR_CODE += 1
continue
create_folder(".repo/dm_info")
create_folder("/tmp/repo/dm_info")
if dm_desc_file.endswith('.json'):
dest_file = ".repo/dm_info/" + os.path.basename(dm_desc_file).replace('.json', f"_{plugin_index}.json")
dest_file = "/tmp/repo/dm_info/" + os.path.basename(dm_desc_file).replace('.json', f"_{plugin_index}.json")
rename_file(repo_path + "/" + dm_desc_file, dest_file)
LIST_FILES = []

View file

@ -100,7 +100,7 @@ else:
print("Dumping default DM_JSON_FILES")
print(DM_JSON_FILES)
DM_JSON_FILES.extend(glob.glob('.repo/dm_info/*.json'))
DM_JSON_FILES.extend(glob.glob('/tmp/repo/dm_info/*.json'))
print("Dumping all")
print(DM_JSON_FILES)

View file

@ -2,8 +2,10 @@
. /usr/share/libubox/jshn.sh
BBFDM_DMMAP_CONFIG="/etc/bbfdm/dmmap"
BBFDM_DMMAP_SAVEDIR="/tmp/.bbfdm"
BBFDM_CONFIG_CONFDIR="/etc/config"
BBFDM_DMMAP_CONFDIR="/etc/bbfdm/dmmap"
BBFDM_CONFIG_SAVEDIR="/tmp/bbfdm/.bbfdm/config"
BBFDM_DMMAP_SAVEDIR="/tmp/bbfdm/.bbfdm/dmmap"
LOGLEVEL="$(uci -q get bbfdm.bbfdmd.loglevel)"
@ -30,6 +32,7 @@ check_result() {
apply_config_changes() {
local service="$1"
local action="$3"
local reload="$4"
# Check if either service or action is empty
if [ -z "$service" ] || [ -z "$action" ]; then
@ -37,15 +40,22 @@ apply_config_changes() {
fi
log "Applying $action configuration for service: $service"
# Commit/Revert config changes
ubus -t 1 call uci ${action} "{'config': '${service}'}"
log "Applying ${action} configuration for file: ${service}"
uci -q -c "${BBFDM_CONFIG_CONFDIR}" -t "${BBFDM_CONFIG_SAVEDIR}" "${action}" "${service}"
check_result "$?" "${service}" "${action}"
if [ "${reload}" == "1" ]; then
# Reload service
ubus -t 1 call uci "${action}" "{'config': '${service}'}"
check_result "$?" "${service}" "${action}"
fi
}
case "$1" in
list)
echo '{ "commit": { "services": [] }, "revert": { "services": [] } }'
echo '{ "commit": { "services": [], "proto": "str", "monitor": true, "reload": true }, "revert": { "services": [], "proto": "str", "monitor": true, "reload": true }, "changes": { "proto": "str" } }'
;;
call)
# Read input JSON from standard input
@ -54,33 +64,81 @@ case "$1" in
# Parse input JSON
json_load "${input}"
# Check if 'services' array is provided
json_get_type type "services"
if [ -z "${type}" ]; then
echo '{ "error": "Services array should be defined !!!" }'
exit 1
# Get the 'proto' value from the input JSON
json_get_var proto proto
if [ "${proto}" == "cwmp" ]; then
BBFDM_CONFIG_SAVEDIR="/tmp/bbfdm/.cwmp/config"
BBFDM_DMMAP_SAVEDIR="/tmp/bbfdm/.cwmp/dmmap"
elif [ "${proto}" == "usp" ]; then
BBFDM_CONFIG_SAVEDIR="/tmp/bbfdm/.usp/config"
BBFDM_DMMAP_SAVEDIR="/tmp/bbfdm/.usp/dmmap"
fi
# Check if 'services' is array
if [ "${type}" != "array" ]; then
echo '{ "error": "Services argument should be array of strings !!!" }'
exit 1
fi
case "$2" in
commit|revert)
# Iterate over each service and apply config changes
json_for_each_item "apply_config_changes" "services" "$2"
# Commit/Revert bbfdm dmmap config changes
for file in "${BBFDM_DMMAP_CONFIG}"/*; do
file_name=$(basename "${file}")
log "Applying $2 configuration for file: $file_name"
uci -q -c "${BBFDM_DMMAP_CONFIG}" -t "${BBFDM_DMMAP_SAVEDIR}" "$2" "${file_name}"
check_result "$?" "${file_name}" "$2"
done
# Get the 'reload' value from the input JSON
json_get_var reload reload
json_get_var monitor monitor
# Send 'bbf.config.change' event to run refresh instances
ubus send bbf.config.change
if [ -z "${reload}" ]; then
reload=1
else
if [ "${reload}" != "0" ] && [ "${reload}" != "1" ]; then
echo '{ "error": "Reload should be boolean type !!!" }'
exit 1
fi
fi
echo '{ "status": "ok" }'
# Check if 'services' array is provided
json_get_type type "services"
if [ -z "${type}" ]; then
# Iterate over all services and apply config changes
for config in $(uci -q -c "${BBFDM_CONFIG_CONFDIR}" -t "${BBFDM_CONFIG_SAVEDIR}" changes | awk -F'.' '{print $1}' | sort | uniq); do
apply_config_changes "${config}" "" "$2" "$reload"
done
else
# Check if 'services' is array
if [ "${type}" != "array" ]; then
echo '{ "error": "Services argument should be array of strings !!!" }'
exit 1
fi
# Iterate over each service and apply config changes
json_for_each_item "apply_config_changes" "services" "$2" "$reload"
fi
if [ "${reload}" == "1" ]; then
# Commit/Revert bbfdm dmmap config changes
if [ -d "${BBFDM_DMMAP_SAVEDIR}" ] && [ "$(ls -A "${BBFDM_DMMAP_SAVEDIR}" 2>/dev/null)" ]; then
for file in "${BBFDM_DMMAP_SAVEDIR}"/*; do
file_name=$(basename "${file}")
log "Applying $2 configuration for file: $file_name"
uci -q -c "${BBFDM_DMMAP_CONFDIR}" -t "${BBFDM_DMMAP_SAVEDIR}" "$2" "${file_name}"
check_result "$?" "${file_name}" "$2"
done
fi
fi
if [ "${monitor}" -eq "1" ]; then
sleep 3
fi
# Send 'bbf.config.change' event to run refresh instances
ubus send bbf.config.change
echo '{ "status": "ok" }'
;;
changes)
json_init
json_add_array "configs"
for config in $(uci -q -c "${BBFDM_CONFIG_CONFDIR}" -t "${BBFDM_CONFIG_SAVEDIR}" changes | awk -F'.' '{print $1}' | sort | uniq); do
json_add_string "" "${config}"
done
json_close_array
json_dump
;;
esac
;;
esac

View file

@ -23,8 +23,34 @@
#define MAX_INSTANCE_NUM 32
#define NAME_LENGTH 64
#define DM_DMMAP_CONFIG "/etc/bbfdm/dmmap"
#define DM_DMMAP_SAVEDIR "/tmp/.bbfdm"
#define CONFIG_CONFDIR "/etc/config/"
#define DMMAP_CONFDIR "/etc/bbfdm/dmmap/"
uint8_t g_log_level = 0;
void print_log(const char *format, ...);
#define LOG(fmt, args...) \
print_log(fmt, ##args)
struct proto_args {
const char *name;
const char *config_savedir;
const char *dmmap_savedir;
unsigned char index;
};
static struct proto_args supported_protocols[] = {
{
"both", "/tmp/bbfdm/.bbfdm/config/", "/tmp/bbfdm/.bbfdm/dmmap/", 0
},
{
"cwmp", "/tmp/bbfdm/.cwmp/config/", "/tmp/bbfdm/.cwmp/dmmap/", 1
},
{
"usp", "/tmp/bbfdm/.usp/config/", "/tmp/bbfdm/.usp/dmmap/", 2
},
};
// Structure to represent an instance of a service
struct instance {
@ -48,13 +74,41 @@ struct config_package {
enum {
SERVICES_NAME,
SERVICES_PROTO,
SERVICES_MONITOR,
SERVICES_RELOAD,
__MAX
};
static const struct blobmsg_policy bbf_config_policy[] = {
[SERVICES_NAME] = { .name = "services", .type = BLOBMSG_TYPE_ARRAY },
[SERVICES_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
[SERVICES_MONITOR] = { .name = "monitor", .type = BLOBMSG_TYPE_BOOL },
[SERVICES_RELOAD] = { .name = "reload", .type = BLOBMSG_TYPE_BOOL },
};
void print_log(const char *format, ...)
{
va_list arglist;
if (g_log_level < 1)
return;
va_start(arglist, format);
vsyslog(LOG_INFO, format, arglist);
va_end(arglist);
}
static unsigned char get_idx_by_proto(const char *proto)
{
for (int i = 0; i < ARRAY_SIZE(supported_protocols); i++) {
if (strcmp(supported_protocols[i].name, proto) == 0)
return supported_protocols[i].index;
}
return 0;
}
static int find_config_idx(struct config_package *package, const char *config_name)
{
if (!config_name)
@ -289,6 +343,7 @@ static void fill_service_info(struct ubus_context *ctx, struct config_package *p
{
struct blob_buf ubus_bb = {0};
memset(&ubus_bb, 0 , sizeof(struct blob_buf));
blob_buf_init(&ubus_bb, 0);
if (name) blobmsg_add_string(&ubus_bb, "name", name);
@ -365,13 +420,24 @@ wait:
sleep(TIME_TO_WAIT_FOR_RELOAD);
}
static void send_bbf_config_change_event(struct ubus_context *ctx)
static void send_bbf_config_change_event()
{
struct ubus_context *ctx;
struct blob_buf bb = {0};
ctx = ubus_connect(NULL);
if (ctx == NULL) {
LOG("Can't create UBUS context for event");
return;
}
LOG("Sending bbf.config.change event");
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
ubus_send_event(ctx, "bbf.config.change", bb.head);
blob_buf_free(&bb);
ubus_free(ctx);
}
static int bbf_config_commit_handler(struct ubus_context *ctx, struct ubus_object *obj __attribute__((unused)),
@ -381,7 +447,10 @@ static int bbf_config_commit_handler(struct ubus_context *ctx, struct ubus_objec
struct blob_attr *tb[__MAX];
struct blob_buf bb = {0};
struct config_package package[MAX_PACKAGE_NUM];
unsigned char idx = 0;
bool monitor = true, reload = true;
LOG("Commit handler called");
memset(package, 0, sizeof(struct config_package) * MAX_PACKAGE_NUM);
memset(&bb, 0, sizeof(struct blob_buf));
@ -392,33 +461,45 @@ static int bbf_config_commit_handler(struct ubus_context *ctx, struct ubus_objec
goto end;
}
struct blob_attr *services = tb[SERVICES_NAME];
if (!services) {
blobmsg_add_string(&bb, "error", "Services array should be defined !!!");
goto end;
if (tb[SERVICES_PROTO]) {
char *proto = blobmsg_get_string(tb[SERVICES_PROTO]);
idx = get_idx_by_proto(proto);
}
// Commit all uci dmmap changes
uci_apply_changes(DM_DMMAP_CONFIG, DM_DMMAP_SAVEDIR, true);
if (tb[SERVICES_MONITOR])
monitor = blobmsg_get_bool(tb[SERVICES_MONITOR]);
size_t arr_len = blobmsg_len(services);
if (tb[SERVICES_RELOAD])
reload = blobmsg_get_bool(tb[SERVICES_RELOAD]);
if (arr_len) {
if (monitor) {
// Get all configs information before calling ubus call uci commit
fill_service_info(ctx, package, NULL, true, _get_service_list_cb);
}
// Commit uci config changes for the required configs
reload_services(ctx, services, true);
if (reload) {
// Commit all uci dmmap changes
uci_apply_changes(DMMAP_CONFDIR, supported_protocols[idx].dmmap_savedir, true);
}
struct blob_attr *services = tb[SERVICES_NAME];
size_t arr_len = (services) ? blobmsg_len(services) : 0;
if (arr_len) {
// Commit uci config changes for the required configs and reload services
reload_specified_services(ctx, CONFIG_CONFDIR, supported_protocols[idx].config_savedir, services, true, reload);
} else {
// Commit uci config changes for all configs and reload services
reload_all_services(ctx, CONFIG_CONFDIR, supported_protocols[idx].config_savedir, true, reload);
}
if (monitor) {
// Wait at least 2 seconds to reload the services
sleep(2);
// Check if the required services are really reloaded
validate_required_services(ctx, package, services);
// Send 'bbf.config.change' event to run refresh instances
send_bbf_config_change_event(ctx);
}
blobmsg_add_string(&bb, "status", "ok");
@ -427,6 +508,10 @@ end:
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
// Send 'bbf.config.change' event to run refresh instances
send_bbf_config_change_event();
LOG("Commit handler exit");
return 0;
}
@ -436,6 +521,57 @@ static int bbf_config_revert_handler(struct ubus_context *ctx, struct ubus_objec
{
struct blob_attr *tb[__MAX];
struct blob_buf bb = {0};
unsigned char idx = 0;
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
LOG("Revert handler called");
if (blobmsg_parse(bbf_config_policy, __MAX, tb, blob_data(msg), blob_len(msg))) {
blobmsg_add_string(&bb, "error", "Failed to parse blob");
goto end;
}
if (tb[SERVICES_PROTO]) {
char *proto = blobmsg_get_string(tb[SERVICES_PROTO]);
idx = get_idx_by_proto(proto);
}
struct blob_attr *services = tb[SERVICES_NAME];
size_t arr_len = (services) ? blobmsg_len(services) : 0;
if (arr_len) {
// Revert uci config changes for the required configs and reload services
reload_specified_services(ctx, CONFIG_CONFDIR, supported_protocols[idx].config_savedir, services, false, false);
} else {
// Revert uci config changes for all configs and reload services
reload_all_services(ctx, CONFIG_CONFDIR, supported_protocols[idx].config_savedir, false, false);
}
// Revert all uci dmmap changes
uci_apply_changes(DMMAP_CONFDIR, supported_protocols[idx].dmmap_savedir, false);
blobmsg_add_string(&bb, "status", "ok");
end:
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
// Send 'bbf.config.change' event to run refresh instances
send_bbf_config_change_event();
LOG("revert handler exit");
return 0;
}
static int bbf_config_changes_handler(struct ubus_context *ctx, struct ubus_object *obj __attribute__((unused)),
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg)
{
struct blob_attr *tb[__MAX];
struct blob_buf bb = {0};
unsigned char idx = 0;
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
@ -445,27 +581,16 @@ static int bbf_config_revert_handler(struct ubus_context *ctx, struct ubus_objec
goto end;
}
struct blob_attr *services = tb[SERVICES_NAME];
if (!services) {
blobmsg_add_string(&bb, "error", "Services array should be defined !!!");
goto end;
if (tb[SERVICES_PROTO]) {
char *proto = blobmsg_get_string(tb[SERVICES_PROTO]);
idx = get_idx_by_proto(proto);
}
// Revert all uci dmmap changes
uci_apply_changes(DM_DMMAP_CONFIG, DM_DMMAP_SAVEDIR, false);
void *array = blobmsg_open_array(&bb, "configs");
size_t arr_len = blobmsg_len(services);
uci_config_changes(CONFIG_CONFDIR, supported_protocols[idx].config_savedir, &bb);
if (arr_len) {
// Revert uci config changes for the required configs
reload_services(ctx, services, false);
// Send 'bbf.config.change' event to run refresh instances
send_bbf_config_change_event(ctx);
}
blobmsg_add_string(&bb, "status", "ok");
blobmsg_close_array(&bb, array);
end:
ubus_send_reply(ctx, req, bb.head);
@ -478,6 +603,7 @@ end:
static const struct ubus_method bbf_config_methods[] = {
UBUS_METHOD("commit", bbf_config_commit_handler, bbf_config_policy),
UBUS_METHOD("revert", bbf_config_revert_handler, bbf_config_policy),
UBUS_METHOD("changes", bbf_config_changes_handler, bbf_config_policy),
};
static struct ubus_object_type bbf_config_object_type = UBUS_OBJECT_TYPE("bbf.config", bbf_config_methods);
@ -489,9 +615,20 @@ static struct ubus_object bbf_config_object = {
.n_methods = ARRAY_SIZE(bbf_config_methods),
};
static void usage(char *prog)
{
fprintf(stderr, "Usage: %s [options]\n", prog);
fprintf(stderr, "\n");
fprintf(stderr, "options:\n");
fprintf(stderr, " -d Use multiple time to get more verbose debug logs\n");
fprintf(stderr, " -h Displays this help\n");
fprintf(stderr, "\n");
}
int main(int argc, char **argv)
{
struct ubus_context *uctx;
int ch;
openlog("bbf.config", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
@ -501,6 +638,19 @@ int main(int argc, char **argv)
return -1;
}
while ((ch = getopt(argc, argv, "hd")) != -1) {
switch (ch) {
case 'd':
g_log_level += 1;
break;
case 'h':
usage(argv[0]);
exit(0);
default:
break;
}
}
uloop_init();
ubus_add_uloop(uctx);

View file

@ -69,22 +69,54 @@ static void reload_service(struct ubus_context *ctx, const char *config_name, bo
blob_buf_free(&bb);
}
void reload_services(struct ubus_context *ctx, struct blob_attr *services, bool is_commit)
void reload_specified_services(struct ubus_context *ctx, const char *conf_dir, const char *save_dir, struct blob_attr *services, bool is_commit, bool reload)
{
struct uci_context *uci_ctx = NULL;
struct blob_attr *service = NULL;
size_t rem = 0;
blobmsg_for_each_attr(service, services, rem) {
char *config_name = blobmsg_get_string(service);
reload_service(ctx, config_name, is_commit);
uci_ctx = uci_alloc_context();
if (!uci_ctx) {
return;
}
if (conf_dir) {
uci_set_confdir(uci_ctx, conf_dir);
}
if (save_dir) {
uci_set_savedir(uci_ctx, save_dir);
}
blobmsg_for_each_attr(service, services, rem) {
struct uci_ptr ptr = {0};
char *config_name = blobmsg_get_string(service);
if (uci_lookup_ptr(uci_ctx, &ptr, config_name, true) != UCI_OK)
continue;
if (is_commit) {
if (uci_commit(uci_ctx, &ptr.p, false) != UCI_OK)
continue;
} else {
if (uci_revert(uci_ctx, &ptr) != UCI_OK) {
continue;
}
}
if (reload) {
reload_service(ctx, config_name, is_commit);
}
}
uci_free_context(uci_ctx);
}
void uci_apply_changes(const char *conf_dir, const char *save_dir, bool is_commit)
void reload_all_services(struct ubus_context *ctx, const char *conf_dir, const char *save_dir, bool is_commit, bool reload)
{
struct uci_context *uci_ctx = NULL;
char **configs = NULL, **p = NULL;
struct uci_ptr ptr = {0};
uci_ctx = uci_alloc_context();
if (!uci_ctx) {
@ -104,6 +136,59 @@ void uci_apply_changes(const char *conf_dir, const char *save_dir, bool is_commi
}
for (p = configs; p && *p; p++) {
struct uci_ptr ptr = {0};
if (uci_lookup_ptr(uci_ctx, &ptr, *p, true) != UCI_OK)
continue;
if (uci_list_empty(&ptr.p->saved_delta))
continue;
if (is_commit) {
if (uci_commit(uci_ctx, &ptr.p, false) != UCI_OK)
continue;
} else {
if (uci_revert(uci_ctx, &ptr) != UCI_OK) {
continue;
}
}
if (reload) {
reload_service(ctx, *p, is_commit);
}
}
free(configs);
exit:
uci_free_context(uci_ctx);
}
void uci_apply_changes(const char *conf_dir, const char *save_dir, bool is_commit)
{
struct uci_context *uci_ctx = NULL;
char **configs = NULL, **p = NULL;
uci_ctx = uci_alloc_context();
if (!uci_ctx) {
return;
}
if (conf_dir) {
uci_set_confdir(uci_ctx, conf_dir);
}
if (save_dir) {
uci_set_savedir(uci_ctx, save_dir);
}
if (uci_list_configs(uci_ctx, &configs) != UCI_OK) {
goto exit;
}
for (p = configs; p && *p; p++) {
struct uci_ptr ptr = {0};
if (uci_lookup_ptr(uci_ctx, &ptr, *p, true) != UCI_OK)
continue;
@ -123,3 +208,43 @@ void uci_apply_changes(const char *conf_dir, const char *save_dir, bool is_commi
exit:
uci_free_context(uci_ctx);
}
void uci_config_changes(const char *conf_dir, const char *save_dir, struct blob_buf *bb)
{
struct uci_context *uci_ctx = NULL;
char **configs = NULL, **p = NULL;
uci_ctx = uci_alloc_context();
if (!uci_ctx) {
return;
}
if (conf_dir) {
uci_set_confdir(uci_ctx, conf_dir);
}
if (save_dir) {
uci_set_savedir(uci_ctx, save_dir);
}
if (uci_list_configs(uci_ctx, &configs) != UCI_OK) {
goto exit;
}
for (p = configs; p && *p; p++) {
struct uci_ptr ptr = {0};
if (uci_lookup_ptr(uci_ctx, &ptr, *p, true) != UCI_OK)
continue;
if (uci_list_empty(&ptr.p->saved_delta))
continue;
blobmsg_add_string(bb, NULL, *p);
}
free(configs);
exit:
uci_free_context(uci_ctx);
}

View file

@ -11,14 +11,22 @@
#ifndef __UTILS_H__
#define __UTILS_H__
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif
void dbg_printf(const char *format, ...);
void strncpyt(char *dst, const char *src, size_t n);
int bbf_config_call(struct ubus_context *ctx, const char *object, const char *method, struct blob_buf *data, ubus_data_handler_t callback, void *arg);
void reload_specified_services(struct ubus_context *ctx, const char *conf_dir, const char *save_dir, struct blob_attr *services, bool is_commit, bool reload);
void reload_all_services(struct ubus_context *ctx, const char *conf_dir, const char *save_dir, bool is_commit, bool reload);
void uci_apply_changes(const char *conf_dir, const char *save_dir, bool is_commit);
void reload_services(struct ubus_context *ctx, struct blob_attr *services, bool is_commit);
void uci_config_changes(const char *conf_dir, const char *save_dir, struct blob_buf *bb);
#endif //__UTILS_H__