Added a mechanism to recover blacklisted services

This commit is contained in:
Amin Ben Romdhane 2025-06-12 15:54:21 +02:00
parent 4bfeedf7bc
commit 22cc348d27
5 changed files with 152 additions and 9 deletions

View file

@ -15,6 +15,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <time.h>
#include <libubus.h>
#include <libubox/blobmsg_json.h>
@ -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, &registered_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();

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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)