bbfdmd: Prevent repeated async calls to unstable services

This commit is contained in:
Amin Ben Romdhane 2025-05-19 13:52:48 +00:00 committed by IOPSYS Dev
parent cba4ccc25c
commit d017aa025c
No known key found for this signature in database
6 changed files with 97 additions and 10 deletions

View file

@ -27,6 +27,50 @@
extern struct list_head registered_services;
extern int g_log_level;
static void bbfdm_ubus_add_event_cb(struct ubus_context *ctx __attribute__((unused)),
struct ubus_event_handler *ev __attribute__((unused)),
const char *type, struct blob_attr *msg)
{
const struct blobmsg_policy policy = {
"path", BLOBMSG_TYPE_STRING
};
service_entry_t *service = NULL;
struct blob_attr *attr = NULL;
bool service_found = false;
const char *path;
if (type && strcmp(type, "ubus.object.add") != 0)
return;
blobmsg_parse(&policy, 1, &attr, blob_data(msg), blob_len(msg));
if (!attr)
return;
path = blobmsg_data(attr);
if (path && strncmp(path, BBFDM_UBUS_OBJECT".", strlen(BBFDM_UBUS_OBJECT) + 1) == 0) {
BBFDM_ERR("Detected new service registration: '%s'", path);
list_for_each_entry(service, &registered_services, list) {
// Check if the service is present in the registred services list
if (strcmp(service->name, path) == 0) {
service->is_blacklisted = false;
service->consecutive_timeouts = 0;
service_found = true;
BBFDM_ERR("Service '%s' found in registry. Resetting blacklist and timeout counters.", path);
break;
}
if (!service_found) {
BBFDM_ERR("Newly registered service '%s' is not recognized in the registry."
" Possible missing configuration JSON file under '%s'.",
path, BBFDM_MICROSERVICE_INPUT_PATH);
}
}
}
}
static const struct blobmsg_policy bbfdm_policy[] = {
[BBFDM_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
[BBFDM_VALUE] = { .name = "value", .type = BLOBMSG_TYPE_STRING },
@ -72,10 +116,13 @@ static int bbfdm_handler_async(struct ubus_context *ctx, struct ubus_object *obj
list_for_each_entry(service, &registered_services, list) {
if (service->is_blacklisted)
continue;
if (!is_path_match(context->requested_path, requested_proto, service))
continue;
run_async_call(context, service->name, msg);
run_async_call(context, service, msg);
}
context->service_list_processed = true;
@ -117,6 +164,9 @@ static int bbfdm_handler_sync(struct ubus_context *ctx, struct ubus_object *obj,
list_for_each_entry(service, &registered_services, list) {
if (service->is_blacklisted)
continue;
if (!is_path_match(requested_path, requested_proto, service))
continue;
@ -181,6 +231,10 @@ 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,
};
char *cli_argv[4] = {0};
int err = 0, ch, cli_argc = 0, i;
@ -236,11 +290,15 @@ int main(int argc, char **argv)
goto end;
}
if (ubus_register_event_handler(&ubus_ctx, &add_event, "ubus.object.add"))
goto end;
BBFDM_INFO("Waiting on uloop....");
uloop_run();
end:
BBFDM_DEBUG("BBFDMD exits");
ubus_unregister_event_handler(&ubus_ctx, &add_event);
unregister_services();
uloop_done();
ubus_shutdown(&ubus_ctx);

View file

@ -21,6 +21,7 @@
#define MAX_VALUE_LENGTH 1024 * 4
#define SERVICE_CALL_TIMEOUT 10000 // 10 secs
#define SERVICE_CALL_OPERATE_TIMEOUT 1800000 // 30 mins
#define SERVICE_MAX_CONSECUTIVE_TIMEOUTS 10
enum bbfdmd_type_enum {
BBFDMD_NONE = 0,

View file

@ -321,6 +321,16 @@ static void handle_request_timeout(struct uloop_timeout *timeout)
ubus_abort_request(tracker->ctx->ubus_ctx, &tracker->async_request);
tracker->ctx->pending_requests--;
service_entry_t *service = tracker->service;
if (service) {
service->consecutive_timeouts++;
if (service->consecutive_timeouts >= SERVICE_MAX_CONSECUTIVE_TIMEOUTS) {
service->is_blacklisted = true;
BBFDM_ERR("Service '%s' has been blacklisted due to repeated timeouts", service->name);
}
}
if (tracker->ctx->pending_requests == 0 && tracker->ctx->service_list_processed) {
BBFDM_ERR("All requests completed after timeout");
send_response(tracker->ctx);
@ -347,6 +357,9 @@ static void ubus_request_complete(struct ubus_request *req, int ret)
uloop_timeout_cancel(&tracker->timeout);
tracker->ctx->pending_requests--;
if (tracker->service && ret == UBUS_STATUS_OK)
tracker->service->consecutive_timeouts = 0;
if (tracker->ctx->pending_requests == 0 && tracker->ctx->service_list_processed) {
BBFDM_DEBUG("Result Callback: All requests completed");
send_response(tracker->ctx);
@ -355,20 +368,20 @@ static void ubus_request_complete(struct ubus_request *req, int ret)
BBFDM_FREE(tracker);
}
void run_async_call(struct async_request_context *ctx, const char *ubus_obj, struct blob_attr *msg)
void run_async_call(struct async_request_context *ctx, service_entry_t *service, struct blob_attr *msg)
{
struct blob_buf req_buf = {0};
struct blob_attr *attr = NULL;
int remaining = 0;
uint32_t id = 0;
if (!ctx || !ubus_obj || !msg) {
if (!ctx || !service || !msg || !service->name) {
BBFDM_ERR("Invalid arguments");
return;
}
if (ubus_lookup_id(ctx->ubus_ctx, ubus_obj, &id)) {
BBFDM_ERR("Failed to lookup object: %s", ubus_obj);
if (ubus_lookup_id(ctx->ubus_ctx, service->name, &id)) {
BBFDM_ERR("Failed to lookup object: %s", service->name);
return;
}
@ -379,6 +392,7 @@ void run_async_call(struct async_request_context *ctx, const char *ubus_obj, str
}
tracker->ctx = ctx;
tracker->service = service;
ctx->pending_requests++;
ctx->path_matched = true;
@ -389,14 +403,14 @@ void run_async_call(struct async_request_context *ctx, const char *ubus_obj, str
blobmsg_add_field(&req_buf, blobmsg_type(attr), blobmsg_name(attr), blobmsg_data(attr), blobmsg_len(attr));
}
snprintf(tracker->request_name, sizeof(tracker->request_name), "%s->%s", ubus_obj, ctx->ubus_method);
snprintf(tracker->request_name, sizeof(tracker->request_name), "%s->%s", service->name, ctx->ubus_method);
tracker->timeout.cb = handle_request_timeout;
uloop_timeout_set(&tracker->timeout, !strcmp(ctx->ubus_method, "operate") ? SERVICE_CALL_OPERATE_TIMEOUT : SERVICE_CALL_TIMEOUT);
if (g_log_level == LOG_DEBUG) {
char *json_str = blobmsg_format_json_indent(req_buf.head, true, -1);
BBFDM_DEBUG("### ubus call %s %s '%s' ###", ubus_obj, ctx->ubus_method, json_str);
BBFDM_DEBUG("### ubus call %s %s '%s' ###", service->name, ctx->ubus_method, json_str);
BBFDM_FREE(json_str);
}

View file

@ -41,12 +41,13 @@ struct async_request_context {
struct ubus_request_tracker {
struct async_request_context *ctx;
service_entry_t *service;
struct ubus_request async_request;
struct uloop_timeout timeout;
char request_name[128];
};
void run_async_call(struct async_request_context *ctx, const char *ubus_obj, struct blob_attr *msg);
void run_async_call(struct async_request_context *ctx, service_entry_t *service, struct blob_attr *msg);
void send_response(struct async_request_context *ctx);
#endif /* BBFDMD_GET_H */

View file

@ -201,24 +201,35 @@ void list_registered_services(struct blob_buf *bb)
list_for_each_entry(service, &registered_services, list) {
void *table = blobmsg_open_table(bb, NULL);
blobmsg_add_string(bb, "name", service->name ? service->name : "");
blobmsg_add_string(bb, "proto", service->protocol == BBFDMD_USP ? "usp" : service->protocol == BBFDMD_CWMP ? "cwmp" : "both");
blobmsg_add_string(bb, "proto",
service->protocol == BBFDMD_USP ? "usp" :
service->protocol == BBFDMD_CWMP ? "cwmp" : "both");
blobmsg_add_u8(bb, "unified_daemon", service->is_unified);
blobmsg_add_u8(bb, "blacklisted", service->is_blacklisted);
void *objects_array = blobmsg_open_array(bb, "objects");
for (size_t i = 0; i < service->object_count; i++) {
void *obj_table = blobmsg_open_table(bb, NULL);
blobmsg_add_string(bb, "parent_dm", service->objects[i].parent_path);
blobmsg_add_string(bb, "object", service->objects[i].object_name);
if (service->protocol == BBFDMD_USP) {
blobmsg_add_string(bb, "proto", "usp");
} else if (service->protocol == BBFDMD_CWMP) {
blobmsg_add_string(bb, "proto", "cwmp");
} else {
blobmsg_add_string(bb, "proto", service->objects[i].protocol == BBFDMD_USP ? "usp" : service->objects[i].protocol == BBFDMD_CWMP ? "cwmp" : "both");
blobmsg_add_string(bb, "proto",
service->objects[i].protocol == BBFDMD_USP ? "usp" :
service->objects[i].protocol == BBFDMD_CWMP ? "cwmp" : "both");
}
blobmsg_close_table(bb, obj_table);
}
blobmsg_close_array(bb, objects_array);
blobmsg_close_table(bb, table);
}

View file

@ -25,6 +25,8 @@ typedef struct service_entry {
bool is_unified;
size_t object_count;
service_object_t *objects;
int consecutive_timeouts; // Tracks successive timeouts
bool is_blacklisted; // Marks if the service is blacklisted
} service_entry_t;
int register_services(struct ubus_context *ctx);