network/queue: introduce RemoveRequest and relevant functions

This is similar to Request, but will be used on removing configuration
(e.g. address, route, and so on).

By using another queue for removing configuration, then we can avoid to
fill the reply callback buffer in sd-netlink by remove message calls.

Follow-up for 4e6a35e2b2.
This commit is contained in:
Yu Watanabe
2024-01-12 09:36:00 +09:00
parent 64b74c86d0
commit 85a6f300c1
4 changed files with 163 additions and 0 deletions
+111
View File
@@ -224,6 +224,10 @@ int manager_process_requests(Manager *manager) {
assert(manager);
/* Process only when no remove request is queued. */
if (!ordered_set_isempty(manager->remove_request_queue))
return 0;
manager->request_queued = false;
ORDERED_SET_FOREACH(req, manager->request_queue) {
@@ -339,3 +343,110 @@ static const char *const request_type_table[_REQUEST_TYPE_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(request_type, RequestType);
static RemoveRequest* remove_request_free(RemoveRequest *req) {
if (!req)
return NULL;
if (req->manager)
ordered_set_remove(req->manager->remove_request_queue, req);
if (req->unref_func)
req->unref_func(req->userdata);
link_unref(req->link);
sd_netlink_unref(req->netlink);
sd_netlink_message_unref(req->message);
return mfree(req);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(RemoveRequest*, remove_request_free);
DEFINE_TRIVIAL_DESTRUCTOR(remove_request_destroy_callback, RemoveRequest, remove_request_free);
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
remove_request_hash_ops,
void,
trivial_hash_func,
trivial_compare_func,
remove_request_free);
int remove_request_add(
Manager *manager,
Link *link,
void *userdata,
mfree_func_t unref_func,
sd_netlink *netlink,
sd_netlink_message *message,
remove_request_netlink_handler_t netlink_handler) {
_cleanup_(remove_request_freep) RemoveRequest *req = NULL;
int r;
assert(manager);
assert(userdata);
assert(netlink);
assert(message);
req = new(RemoveRequest, 1);
if (!req)
return -ENOMEM;
*req = (RemoveRequest) {
.link = link_ref(link), /* link may be NULL, but link_ref() handles it gracefully. */
.userdata = userdata,
.netlink = sd_netlink_ref(netlink),
.message = sd_netlink_message_ref(message),
.netlink_handler = netlink_handler,
};
r = ordered_set_ensure_put(&manager->remove_request_queue, &remove_request_hash_ops, req);
if (r < 0)
return r;
assert(r > 0);
req->manager = manager;
req->unref_func = unref_func;
TAKE_PTR(req);
return 0;
}
int manager_process_remove_requests(Manager *manager) {
RemoveRequest *req;
int r;
assert(manager);
while ((req = ordered_set_first(manager->remove_request_queue))) {
/* Do not make the reply callback queue in sd-netlink full. */
if (netlink_get_reply_callback_count(req->netlink) >= REPLY_CALLBACK_COUNT_THRESHOLD)
return 0;
r = netlink_call_async(
req->netlink, NULL, req->message,
req->netlink_handler,
remove_request_destroy_callback,
req);
if (r < 0) {
_cleanup_(link_unrefp) Link *link = link_ref(req->link);
log_link_warning_errno(link, r, "Failed to call netlink message: %m");
/* First free the request. */
remove_request_free(req);
/* Then, make the link enter the failed state. */
if (link)
link_enter_failed(link);
} else {
/* On success, netlink needs to be unref()ed. Otherwise, the netlink and remove
* request may not freed on shutting down. */
req->netlink = sd_netlink_unref(req->netlink);
ordered_set_remove(manager->remove_request_queue, req);
}
}
return 0;
}