diff --git a/bbfdmd/ubus/bbfdmd.c b/bbfdmd/ubus/bbfdmd.c index 1b000815..b93aa2de 100644 --- a/bbfdmd/ubus/bbfdmd.c +++ b/bbfdmd/ubus/bbfdmd.c @@ -61,6 +61,44 @@ static void service_request_timeout(struct uloop_timeout *timeout) BBFDM_FREE(tracker); } +static void service_result_callback(struct ubus_request *req __attribute__((unused)), int type __attribute__((unused)), struct blob_attr *msg) +{ + if (!msg) + return; + + struct blob_buf bb = {0}; + bool uci_exist = false; + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + + blobmsg_add_string(&bb, "proto", "both"); + blobmsg_add_u8(&bb, "reload", false); + + void *array = blobmsg_open_array(&bb, "services"); + + struct blob_attr *modified_uci = get_modified_uci_array(msg); + if (modified_uci) { + struct blob_attr *attr = NULL; + int remaining = 0; + + blobmsg_for_each_attr(attr, modified_uci, remaining) { + char *file = blobmsg_get_string(attr); + if (file && strncmp(file, "/etc/bbfdm/dmmap/", 17) == 0) { + blobmsg_add_string(&bb, NULL, file); + uci_exist = true; + } + } + } + + blobmsg_close_array(&bb, array); + + if (uci_exist) + BBFDM_UBUS_INVOKE_SYNC("bbf.config", "commit", bb.head, 10000, NULL, NULL); + + blob_buf_free(&bb); +} + static void service_request_complete(struct ubus_request *req, int ret) { struct service_request_tracker *tracker = container_of(req, struct service_request_tracker, async_request); @@ -120,6 +158,7 @@ static void verify_service(struct ubus_context *ubus_ctx, service_entry_t *servi uloop_timeout_cancel(&tracker->timeout); BBFDM_FREE(tracker); } else { + tracker->async_request.data_cb = service_result_callback; tracker->async_request.complete_cb = service_request_complete; ubus_complete_request_async(ubus_ctx, &tracker->async_request); } diff --git a/bbfdmd/ubus/cli.c b/bbfdmd/ubus/cli.c index e2c4e352..5e3545f5 100644 --- a/bbfdmd/ubus/cli.c +++ b/bbfdmd/ubus/cli.c @@ -70,6 +70,45 @@ static int bbfdm_ubus_invoke(const char *obj, const char *method, struct blob_at return rc; } +static void handle_uci_commit(const char *cmd, struct blob_attr *modified_uci, bool commit) +{ + bool uci_exist = false; + + if (modified_uci == NULL) + return; + + struct blob_buf bb = {0}; + + memset(&bb, 0, sizeof(struct blob_buf)); + + blob_buf_init(&bb, 0); + + blobmsg_add_string(&bb, "proto", "both"); + + if (strcmp(cmd, "get") == 0 || strcmp(cmd, "schema") == 0 || + strcmp(cmd, "instances") == 0 || commit == false) { + blobmsg_add_u8(&bb, "reload", false); + } else { + blobmsg_add_u8(&bb, "reload", true); + } + + void *array = blobmsg_open_array(&bb, "services"); + struct blob_attr *attr = NULL; + int remaining = 0; + + blobmsg_for_each_attr(attr, modified_uci, remaining) { + blobmsg_add_string(&bb, NULL, blobmsg_get_string(attr)); + uci_exist = true; + } + + blobmsg_close_array(&bb, array); + + if (uci_exist) + BBFDM_UBUS_INVOKE_SYNC("bbf.config", commit ? "commit" : "revert", bb.head, 10000, NULL, NULL); + + blob_buf_free(&bb); +} + static void __ubus_callback(struct ubus_request *req, int msgtype __attribute__((unused)), struct blob_attr *msg) { struct blob_attr *cur = NULL; @@ -89,14 +128,17 @@ static void __ubus_callback(struct ubus_request *req, int msgtype __attribute__( cli_data_t *cli_data = (cli_data_t *)req->priv; struct blob_attr *parameters = get_results_array(msg); + struct blob_attr *modified_uci = get_modified_uci_array(msg); if (parameters == NULL) { cli_data->ubus_status = false; + handle_uci_commit(cli_data->cmd, modified_uci, false); return; } if (blobmsg_len(parameters) == 0) { cli_data->ubus_status = true; + handle_uci_commit(cli_data->cmd, modified_uci, true); return; } @@ -111,6 +153,7 @@ static void __ubus_callback(struct ubus_request *req, int msgtype __attribute__( if (tb[3]) { printf("Fault %u: %s\n", blobmsg_get_u32(tb[3]), tb[6] ? blobmsg_get_string(tb[6]) : ""); cli_data->ubus_status = false; + handle_uci_commit(cli_data->cmd, modified_uci, false); return; } @@ -131,6 +174,8 @@ static void __ubus_callback(struct ubus_request *req, int msgtype __attribute__( cli_data->ubus_status = true; } + + handle_uci_commit(cli_data->cmd, modified_uci, true); } static int cli_exec_cmd(cli_data_t *cli_data, const char *path, const char *value) diff --git a/bbfdmd/ubus/common.c b/bbfdmd/ubus/common.c index a3c8858a..e3e31fe9 100644 --- a/bbfdmd/ubus/common.c +++ b/bbfdmd/ubus/common.c @@ -198,7 +198,7 @@ void run_sync_call(const char *ubus_obj, const char *ubus_method, struct blob_at BBFDM_FREE(json_str); } - BBFDM_UBUS_INVOKE_SYNC(ubus_obj, ubus_method, req_buf.head, 5000, sync_callback, bb_response); + BBFDM_UBUS_INVOKE_SYNC(ubus_obj, ubus_method, req_buf.head, 10000, sync_callback, bb_response); blob_buf_free(&req_buf); } diff --git a/bbfdmd/ubus/service.c b/bbfdmd/ubus/service.c index 476d142d..2e57dce1 100644 --- a/bbfdmd/ubus/service.c +++ b/bbfdmd/ubus/service.c @@ -319,6 +319,11 @@ static void fill_from_services(json_object *services_arr, const char *source_nam { size_t _len = json_object_array_length(services_arr); for (size_t _j = 0; _j < _len; _j++) { + if (*num_objs >= total_capacity) { + BBFDM_WARNING("Reached object capacity in %s", source_name); + break; + } + json_object *_svc = json_object_array_get_idx(services_arr, _j); json_object *_pdm = NULL, *_obj = NULL, *_proto = NULL; const char *_pdm_str, *_obj_str; @@ -343,10 +348,6 @@ static void fill_from_services(json_object *services_arr, const char *source_nam objects[*num_objs].protocol = get_proto_type(_proto ? json_object_get_string(_proto) : ""); (*num_objs)++; - if (*num_objs >= total_capacity) { - BBFDM_WARNING("Reached object capacity in %s", source_name); - break; - } } } diff --git a/libbbfdm-api/legacy/dmbbf.c b/libbbfdm-api/legacy/dmbbf.c index 59de9a62..83c8a526 100644 --- a/libbbfdm-api/legacy/dmbbf.c +++ b/libbbfdm-api/legacy/dmbbf.c @@ -167,6 +167,30 @@ static int plugin_obj_match(DMOBJECT_ARGS) return FAULT_9005; } +static int reference_obj_match(DMOBJECT_ARGS) +{ + char skip_obj[][64] = { "Device.MQTT.", "Device.LocalAgent.", "Device.USPAgent.", "Device.STOMP." }; + + for (int i = 0; i < ARRAY_SIZE(skip_obj); i++) { + if (DM_STRSTR(node->current_object, skip_obj[i]) == node->current_object) + return FAULT_9005; + } + + if (node->matched) + return 0; + + if (!dmctx->inparam_isparam && DM_STRSTR(node->current_object, dmctx->in_param) == node->current_object) { + node->matched++; + dmctx->findparam = 1; + return 0; + } + + if (DM_STRSTR(dmctx->in_param, node->current_object) == dmctx->in_param) + return 0; + + return FAULT_9005; +} + static int plugin_leaf_match(DMOBJECT_ARGS) { if (node->matched) @@ -2483,14 +2507,14 @@ static int mparam_get_references_db(DMPARAM_ARGS) if (node->is_instanceobj == 0) return 0; - char full_param[MAX_DM_PATH] = {0}; - char *value = dmstrdup(""); - - snprintf(full_param, sizeof(full_param), "%s%s", node->current_object, leaf->parameter); - - (leaf->getvalue)(full_param, dmctx, data, instance, &value); - if (leaf->dm_flags & DM_FLAG_LINKER) { + char full_param[MAX_DM_PATH] = {0}; + char *value = dmstrdup(""); + + snprintf(full_param, sizeof(full_param), "%s%s", node->current_object, leaf->parameter); + + (leaf->getvalue)(full_param, dmctx, data, instance, &value); + add_path((struct list_head *)dmctx->addobj_instance, full_param, value); } @@ -2507,7 +2531,7 @@ int dm_entry_references_db(struct dmctx *ctx) ctx->inparam_isparam = 0; ctx->findparam = 1; ctx->stop = 0; - ctx->checkobj = NULL; + ctx->checkobj = reference_obj_match; ctx->checkleaf = NULL; ctx->method_obj = mobj_get_references_db; ctx->method_param = mparam_get_references_db; diff --git a/libbbfdm-ubus/bbfdm-ubus.c b/libbbfdm-ubus/bbfdm-ubus.c index 8730a26c..8aa6bda7 100644 --- a/libbbfdm-ubus/bbfdm-ubus.c +++ b/libbbfdm-ubus/bbfdm-ubus.c @@ -380,11 +380,6 @@ int bbfdm_set_handler(struct ubus_context *ctx, struct ubus_object *obj, bbf_init(&data.bbf_ctx); fault = bbfdm_set_value(&data); - - if (data.bbf_ctx.dm_type == BBFDM_BOTH) { - bbf_entry_services(data.bbf_ctx.dm_type, (!fault) ? true : false, true); - } - bbf_cleanup(&data.bbf_ctx); if (!fault) { @@ -496,10 +491,6 @@ int bbfdm_add_handler(struct ubus_context *ctx, struct ubus_object *obj, } end: - if (data.bbf_ctx.dm_type == BBFDM_BOTH) { - bbf_entry_services(data.bbf_ctx.dm_type, (!fault) ? true : false, true); - } - bbf_cleanup(&data.bbf_ctx); if (!fault) { @@ -568,10 +559,6 @@ int bbfdm_del_handler(struct ubus_context *ctx, struct ubus_object *obj, fault = create_del_response(&data); - if (data.bbf_ctx.dm_type == BBFDM_BOTH) { - bbf_entry_services(data.bbf_ctx.dm_type, (!fault) ? true : false, true); - } - bbf_cleanup(&data.bbf_ctx); free_path_list(&paths_list); @@ -681,6 +668,15 @@ static int read_apply_handlers_config(const char *serv_config, bbfdm_config_t *c return -1; } + json_object *enable_jobj = NULL; + json_object_object_get_ex(daemon_config, "enable", &enable_jobj); + bool enable = enable_jobj ? json_object_get_boolean(enable_jobj) : false; + if (!enable) { + BBFDM_DEBUG("%s is disabled", serv_config); + json_object_put(json_root); + return 0; + } + if (suppress == true) { json_object *unified_daemon = NULL; @@ -1078,6 +1074,18 @@ int bbfdm_print_data_model_schema(struct bbfdm_context *bbfdm_ctx, const enum bb return err; } +static void send_sync_completed(struct bbfdm_context *bbfdm_ctx) +{ + struct blob_buf bb = {0}; + memset(&bb, 0, sizeof(struct blob_buf)); + + blob_buf_init(&bb, 0); + blobmsg_add_string(&bb, "service", bbfdm_ctx->config.service_name); + + ubus_send_event(bbfdm_ctx->ubus_ctx, "dmservice.sync_complete", bb.head); + blob_buf_free(&bb); +} + static void perform_uci_sync_op(struct bbfdm_context *bbfdm_ctx) { DM_MAP_OBJ *dynamic_obj = INTERNAL_ROOT_TREE; @@ -1123,8 +1131,10 @@ static void bbfdm_apply_event_cb(struct ubus_context *ctx __attribute__((unused) struct blob_attr *tb[2] = {NULL, NULL}; blobmsg_parse(p, 2, tb, blob_data(msg), blob_len(msg)); - if (!tb[0] || !tb[1]) + if (!tb[0] || !tb[1]) { + send_sync_completed(bbfdm_ctx); return; + } const char *proto = blobmsg_get_string(tb[0]); struct blob_attr *attr = NULL; @@ -1174,6 +1184,8 @@ static void bbfdm_apply_event_cb(struct ubus_context *ctx __attribute__((unused) snprintf(bbfdm_ctx->uci_change_proto, sizeof(bbfdm_ctx->uci_change_proto), "%s", proto); perform_uci_sync_op(bbfdm_ctx); } + + send_sync_completed(bbfdm_ctx); } static int register_bbfdm_apply_event(struct bbfdm_context *bbfdm_ctx) diff --git a/libbbfdm-ubus/get.c b/libbbfdm-ubus/get.c index 6e46d128..a983f2c3 100644 --- a/libbbfdm-ubus/get.c +++ b/libbbfdm-ubus/get.c @@ -19,27 +19,12 @@ void bbfdm_get(bbfdm_data_t *data, int method) struct pathNode *pn = NULL; int fault = 0; - LIST_HEAD(temp_list); - if (method == BBF_INSTANCES) { - // referesh reference db - struct dmctx bbf_ctx = { - .in_param = ROOT_NODE, - .dm_type = data->bbf_ctx.dm_type - }; - - bbf_init(&bbf_ctx); - bbfdm_cmd_exec(&bbf_ctx, BBF_REFERENCES_DB); - list_splice_tail_init(bbf_ctx.modified_uci_head, &temp_list); - bbf_cleanup(&bbf_ctx); + bbfdm_refresh_references(data->bbf_ctx.dm_type, NULL); } bbf_init(&data->bbf_ctx); - if (!list_empty(&temp_list)) { - list_splice_tail_init(&temp_list, data->bbf_ctx.modified_uci_head); - } - void *array = blobmsg_open_array(&data->bbf_ctx.bb, "results"); list_for_each_entry(pn, data->plist, list) { @@ -79,10 +64,5 @@ void bbfdm_get(bbfdm_data_t *data, int method) ubus_send_reply(data->ctx, data->req, data->bbf_ctx.bb.head); } - // Apply all bbfdm dmmap changes - if (data->bbf_ctx.dm_type == BBFDM_BOTH) { - dmuci_commit_bbfdm(); - } - bbf_cleanup(&data->bbf_ctx); } diff --git a/utilities/src/ubus/bbf_config.c b/utilities/src/ubus/bbf_config.c index 613779ab..f31c5760 100644 --- a/utilities/src/ubus/bbf_config.c +++ b/utilities/src/ubus/bbf_config.c @@ -58,6 +58,7 @@ struct bbf_config_async_req { struct ubus_request_data req; struct uloop_timeout timeout; struct blob_attr *services; + struct ubus_event_handler sync_ev; struct config_package package[MAX_PACKAGE_NUM]; struct list_head changed_uci_list; }; @@ -465,12 +466,12 @@ wait: return false; } -static void send_bbf_apply_event(int idx, struct list_head *changed_uci_list) +static int send_bbf_apply_event(int idx, struct list_head *changed_uci_list) { char protocol[16] = {0}; if (changed_uci_list == NULL || list_empty(changed_uci_list)) - return; + return -1; struct ubus_context *ctx; struct blob_buf bb = {0}; @@ -501,7 +502,7 @@ static void send_bbf_apply_event(int idx, struct list_head *changed_uci_list) if (ctx == NULL) { ULOG_ERR("Can't create UBUS context for 'bbfdm.apply' event"); blob_buf_free(&bb); - return; + return -1; } ULOG_INFO("Sending bbfdm.apply event"); @@ -509,6 +510,8 @@ static void send_bbf_apply_event(int idx, struct list_head *changed_uci_list) ubus_send_event(ctx, "bbfdm.apply", bb.head); blob_buf_free(&bb); ubus_free(ctx); + + return 0; } static void send_reply(struct ubus_context *ctx, struct ubus_request_data *req, const char *message, const char *description) @@ -523,17 +526,111 @@ static void send_reply(struct ubus_context *ctx, struct ubus_request_data *req, blob_buf_free(&bb); } -static void complete_deferred_request(struct bbf_config_async_req *async_req) +static void sync_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev, + const char *type, struct blob_attr *msg) { - if (!async_req) + if (msg == NULL || ev == NULL) return; + struct bbf_config_async_req *async_req = container_of(ev, struct bbf_config_async_req, sync_ev); + if (async_req == NULL) + return; + + // validate if the event received from core service + const struct blobmsg_policy p[1] = { + { "service", BLOBMSG_TYPE_STRING } + }; + + struct blob_attr *tb[1] = {0}; + if (blobmsg_parse(p, 1, tb, blob_data(msg), blob_len(msg)) != 0) + return; + + if (!tb[0] || strcmp("core", blobmsg_get_string(tb[0])) != 0) { + return; + } + + uloop_timeout_cancel(&(async_req->timeout)); + // Send the response send_reply(async_req->ctx, &async_req->req, "status", "ok"); // Complete the deferred request and send the response ubus_complete_deferred_request(async_req->ctx, &async_req->req, 0); + ubus_unregister_event_handler(async_req->ctx, &(async_req->sync_ev)); + + // Free the allocated memory + FREE(async_req->services); + FREE(async_req); + + ULOG_INFO("Commit handler exit"); +} + +static void sync_listen_timeout(struct uloop_timeout *timeout) +{ + struct bbf_config_async_req *async_req = container_of(timeout, struct bbf_config_async_req, timeout); + if (async_req == NULL) + return; + + ULOG_INFO("Timeout occurred for sync_complete event from core"); + + // Send the response + send_reply(async_req->ctx, &async_req->req, "status", "ok"); + + // Complete the deferred request and send the response + ubus_complete_deferred_request(async_req->ctx, &async_req->req, 0); + + ubus_unregister_event_handler(async_req->ctx, &(async_req->sync_ev)); + + // Free the allocated memory + FREE(async_req->services); + FREE(async_req); + + ULOG_INFO("Commit handler exit"); +} + +static void wait_for_sync_complete_event(struct bbf_config_async_req *async_req) +{ + if (async_req == NULL) + return; + + if (ubus_register_event_handler(async_req->ctx, &(async_req->sync_ev), "dmservice.sync_complete")) { + ULOG_ERR("Failed to register dmservice.sync_complete event handler"); + // Send 'bbf.apply' event + send_bbf_apply_event(async_req->idx, &async_req->changed_uci_list); + goto exit; + } + + uloop_timeout_set(&(async_req->timeout), 5000); + + // Send 'bbf.apply' event + if (0 != send_bbf_apply_event(async_req->idx, &async_req->changed_uci_list)) { + uloop_timeout_cancel(&(async_req->timeout)); + ubus_unregister_event_handler(async_req->ctx, &(async_req->sync_ev)); + goto exit; + } + + return; + +exit: + // Send the response + send_reply(async_req->ctx, &async_req->req, "status", "ok"); + + // Complete the deferred request and send the response + ubus_complete_deferred_request(async_req->ctx, &async_req->req, 0); + + // Free the allocated memory + FREE(async_req->services); + FREE(async_req); + + ULOG_INFO("Commit handler exit"); +} + +static void complete_deferred_request(struct bbf_config_async_req *async_req) +{ + if (!async_req) + return; + // If any uci is changed externally then add it in bbf.apply event struct modi_uci_node *node = NULL, *tmp = NULL; list_for_each_entry_safe(node, tmp, &g_external_changed_uci, list) { @@ -549,17 +646,14 @@ static void complete_deferred_request(struct bbf_config_async_req *async_req) FREE(node); } - // Send 'bbf.apply' event - send_bbf_apply_event(async_req->idx, &async_req->changed_uci_list); - - // Free the allocated memory - FREE(async_req->services); - FREE(async_req); + // Lets wait for sync_complete from core + async_req->timeout.cb = sync_listen_timeout; + async_req->sync_ev.cb = sync_event_handler; // Set internal commit to false g_internal_commit = false; - ULOG_INFO("Commit handler exit"); + wait_for_sync_complete_event(async_req); } static void end_request_callback(struct uloop_timeout *t) @@ -946,27 +1040,22 @@ static int bbf_config_commit_handler(struct ubus_context *ctx, struct ubus_objec FREE(node); } - if (monitor) { + if (monitor && reload) { ULOG_INFO("Deferring request and setting up async completion"); async_req->idx = idx; ubus_defer_request(ctx, req, &async_req->req); async_req->timeout.cb = complete_request_callback; uloop_timeout_set(&async_req->timeout, 2000); } else { - ULOG_INFO("Sending immediate success response"); - send_reply(ctx, req, "status", "ok"); - - // Send 'bbf.apply' event - send_bbf_apply_event(idx, changed_uci); - - // Free the allocated memory - FREE(async_req->services); - FREE(async_req); + async_req->idx = idx; + ubus_defer_request(ctx, req, &async_req->req); + async_req->timeout.cb = sync_listen_timeout; + async_req->sync_ev.cb = sync_event_handler; // Set internal commit to false g_internal_commit = false; - ULOG_INFO("Commit handler exit"); + wait_for_sync_complete_event(async_req); } return 0;