From 22cc348d2787a8c927ab1a89b54b9e46464dedb7 Mon Sep 17 00:00:00 2001 From: Amin Ben Romdhane Date: Thu, 12 Jun 2025 15:54:21 +0200 Subject: [PATCH] Added a mechanism to recover blacklisted services --- bbfdmd/ubus/bbfdmd.c | 134 ++++++++++++++++++++++++++++++++++--- bbfdmd/ubus/common.c | 21 ++++++ bbfdmd/ubus/common.h | 3 + dm-service/dm_service.c | 1 + libbbfdm-ubus/bbfdm-ubus.c | 2 +- 5 files changed, 152 insertions(+), 9 deletions(-) diff --git a/bbfdmd/ubus/bbfdmd.c b/bbfdmd/ubus/bbfdmd.c index 8074d2f3..2118b41c 100644 --- a/bbfdmd/ubus/bbfdmd.c +++ b/bbfdmd/ubus/bbfdmd.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -24,9 +25,123 @@ #include "get.h" #include "cli.h" +struct ubus_context g_ubus_ctx = {0}; + extern struct list_head registered_services; extern int g_log_level; +static void schedule_blacklisted_service_recovery(struct ubus_context *ctx); + +static void blacklisted_recovery_timer_cb(struct uloop_timeout *timeout __attribute__((unused))) +{ + schedule_blacklisted_service_recovery(&g_ubus_ctx); +} + +static struct uloop_timeout blacklisted_recovery_timer = { + .cb = blacklisted_recovery_timer_cb +}; + +struct service_request_tracker { + struct ubus_context *ubus_ctx; + service_entry_t *service; + struct ubus_request async_request; + struct uloop_timeout timeout; +}; + +static void service_request_timeout(struct uloop_timeout *timeout) +{ + struct service_request_tracker *tracker = container_of(timeout, struct service_request_tracker, timeout); + if (tracker == NULL) { + BBFDM_ERR("Timeout occurred but tracker is not defined"); + return; + } + + BBFDM_ERR("Timeout occurred for request: '%s get'", tracker->service ? tracker->service->name : "unknown"); + ubus_abort_request(tracker->ubus_ctx, &tracker->async_request); + BBFDM_FREE(tracker); +} + +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); + if (tracker == NULL) { + BBFDM_ERR("Request completed but tracker is not defined"); + return; + } + + BBFDM_DEBUG("Request completed for '%s get' with status: '%d'", tracker->service ? tracker->service->name : "", ret); + uloop_timeout_cancel(&tracker->timeout); + + if (tracker->service && ret == UBUS_STATUS_OK) { + tracker->service->is_blacklisted = false; + tracker->service->consecutive_timeouts = 0; + BBFDM_INFO("Recovered blacklisted service: '%s'", tracker->service->name); + } else { + BBFDM_DEBUG("Service '%s' still unreachable", tracker->service ? tracker->service->name : "unknown"); + } + + BBFDM_FREE(tracker); +} + +static void verify_service(struct ubus_context *ubus_ctx, service_entry_t *service) +{ + struct blob_buf req_buf = {0}; + uint32_t id = 0; + + if (!ubus_ctx || !service || !service->name) { + BBFDM_ERR("Invalid arguments"); + return; + } + + if (ubus_lookup_id(ubus_ctx, service->name, &id)) { + BBFDM_ERR("Failed to lookup object: %s", service->name); + return; + } + + struct service_request_tracker *tracker = (struct service_request_tracker *)calloc(1, sizeof(struct service_request_tracker)); + if (!tracker) { + BBFDM_ERR("Failed to allocate memory for request tracker"); + return; + } + + tracker->ubus_ctx = ubus_ctx; + tracker->service = service; + + tracker->timeout.cb = service_request_timeout; + uloop_timeout_set(&tracker->timeout, SERVICE_CALL_TIMEOUT); + + memset(&req_buf, 0, sizeof(struct blob_buf)); + blob_buf_init(&req_buf, 0); + + blobmsg_add_string(&req_buf, "path", BBFDM_ROOT_OBJECT); + + if (ubus_invoke_async(ubus_ctx, id, "get", req_buf.head, &tracker->async_request)) { + BBFDM_ERR("Failed to invoke async method for object: '%s get'", service->name); + uloop_timeout_cancel(&tracker->timeout); + BBFDM_FREE(tracker); + } else { + tracker->async_request.complete_cb = service_request_complete; + ubus_complete_request_async(ubus_ctx, &tracker->async_request); + } + + blob_buf_free(&req_buf); +} + +static void schedule_blacklisted_service_recovery(struct ubus_context *ubus_ctx) +{ + service_entry_t *service = NULL; + + list_for_each_entry(service, ®istered_services, list) { + if (service->is_blacklisted) { + verify_service(ubus_ctx, service); + } + } + + int next_check_time = rand_in_range(30, 60) * 1000; + BBFDM_DEBUG("Next blacklisted service recovery scheduled in %d msecs", next_check_time); + uloop_timeout_set(&blacklisted_recovery_timer, next_check_time); +} + static void bbfdm_ubus_add_event_cb(struct ubus_context *ctx, struct ubus_event_handler *ev __attribute__((unused)), const char *type, struct blob_attr *msg) { @@ -295,7 +410,6 @@ static void usage(char *prog) int main(int argc, char **argv) { - struct ubus_context ubus_ctx = {0}; struct ubus_event_handler add_event = { .cb = bbfdm_ubus_add_event_cb, }; @@ -334,39 +448,43 @@ int main(int argc, char **argv) setlogmask(LOG_UPTO(g_log_level)); - err = ubus_connect_ctx(&ubus_ctx, NULL); + init_rand_seed(); // Seed the random number generator + + err = ubus_connect_ctx(&g_ubus_ctx, NULL); if (err != UBUS_STATUS_OK) { BBFDM_ERR("Failed to connect to ubus"); return -1; } uloop_init(); - ubus_add_uloop(&ubus_ctx); + ubus_add_uloop(&g_ubus_ctx); - err = register_services(&ubus_ctx); + err = register_services(&g_ubus_ctx); if (err) { BBFDM_ERR("Failed to load micro-services"); goto end; } - err = ubus_add_object(&ubus_ctx, &bbfdm_object); + err = ubus_add_object(&g_ubus_ctx, &bbfdm_object); if (err != UBUS_STATUS_OK) { BBFDM_ERR("Failed to add ubus object: %s", ubus_strerror(err)); goto end; } - if (ubus_register_event_handler(&ubus_ctx, &add_event, "ubus.object.add")) + if (ubus_register_event_handler(&g_ubus_ctx, &add_event, "ubus.object.add")) goto end; + schedule_blacklisted_service_recovery(&g_ubus_ctx); + BBFDM_INFO("Waiting on uloop...."); uloop_run(); end: BBFDM_DEBUG("BBFDMD exits"); - ubus_unregister_event_handler(&ubus_ctx, &add_event); + ubus_unregister_event_handler(&g_ubus_ctx, &add_event); unregister_services(); uloop_done(); - ubus_shutdown(&ubus_ctx); + ubus_shutdown(&g_ubus_ctx); closelog(); diff --git a/bbfdmd/ubus/common.c b/bbfdmd/ubus/common.c index 701c2620..7ee99179 100644 --- a/bbfdmd/ubus/common.c +++ b/bbfdmd/ubus/common.c @@ -16,6 +16,27 @@ int g_log_level = LOG_ERR; +void init_rand_seed(void) +{ + srandom((unsigned int)time(NULL)); +} + +int rand_in_range(int min, int max) +{ + int range; + + if (min >= max) + return -1; + + if (min == (max - 1)) + return min; + + range = max - min; + + return min + ((int)(((double)range) * ((double)random()) / + (((double)RAND_MAX) + 1.0))); +} + unsigned int get_proto_type(const char *proto) { int type = BBFDMD_BOTH; diff --git a/bbfdmd/ubus/common.h b/bbfdmd/ubus/common.h index ae074a5c..77cd07dd 100644 --- a/bbfdmd/ubus/common.h +++ b/bbfdmd/ubus/common.h @@ -31,6 +31,9 @@ enum bbfdmd_type_enum { BBFDMD_BOTH = BBFDMD_CWMP | BBFDMD_USP, }; +void init_rand_seed(void); +int rand_in_range(int min, int max); + unsigned int get_proto_type(const char *proto); void fill_optional_input(struct blob_attr *msg, unsigned int *proto, bool *raw_format); diff --git a/dm-service/dm_service.c b/dm-service/dm_service.c index 7b47e120..84b85267 100644 --- a/dm-service/dm_service.c +++ b/dm-service/dm_service.c @@ -68,6 +68,7 @@ int main(int argc, char **argv) } bbfdm_ubus_set_log_level(log_level); + bbfdm_ubus_load_data_model(NULL); openlog(bbfdm_ctx.config.service_name, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); diff --git a/libbbfdm-ubus/bbfdm-ubus.c b/libbbfdm-ubus/bbfdm-ubus.c index 18955224..acf6a841 100644 --- a/libbbfdm-ubus/bbfdm-ubus.c +++ b/libbbfdm-ubus/bbfdm-ubus.c @@ -767,7 +767,7 @@ int bbfdm_print_data_model_schema(struct bbfdm_context *bbfdm_ctx, const enum bb bbf_cleanup(&bbf_ctx); bbfdm_ctx_cleanup(bbfdm_ctx); - return 0; + return err; } int bbfdm_ubus_regiter_init(struct bbfdm_context *bbfdm_ctx)