network: cancel netlink calls for detached requests
Store the asynchronous netlink slot in the Request object and release it
when the request is detached. This cancels the pending callback instead of
keeping the request alive until its reply arrives.
Follow-up for 80d62d4f1a
This commit is contained in:
@@ -22,6 +22,7 @@ static Request* request_detach_impl(Request *req) {
|
||||
|
||||
ordered_set_remove(req->manager->request_queue, req);
|
||||
req->manager = NULL;
|
||||
req->netlink_slot = sd_netlink_slot_unref(req->netlink_slot);
|
||||
return req;
|
||||
}
|
||||
|
||||
@@ -328,6 +329,10 @@ int manager_process_requests(Manager *manager) {
|
||||
static int request_netlink_handler(sd_netlink *nl, sd_netlink_message *m, Request *req) {
|
||||
assert(req);
|
||||
|
||||
assert(req->netlink_slot);
|
||||
assert_se(sd_netlink_slot_set_floating(req->netlink_slot, true) >= 0);
|
||||
req->netlink_slot = sd_netlink_slot_unref(req->netlink_slot);
|
||||
|
||||
if (req->counter) {
|
||||
assert(*req->counter > 0);
|
||||
(*req->counter)--;
|
||||
@@ -350,7 +355,7 @@ int request_call_netlink_async(sd_netlink *nl, sd_netlink_message *m, Request *r
|
||||
assert(m);
|
||||
assert(req);
|
||||
|
||||
r = netlink_call_async(nl, NULL, m, request_netlink_handler, request_destroy_callback, req);
|
||||
r = netlink_call_async(nl, &req->netlink_slot, m, request_netlink_handler, request_destroy_callback, req);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ typedef struct Request {
|
||||
* request, and pass this request to the netlink_call_async(), and set the destroy function
|
||||
* to the slot. */
|
||||
request_netlink_handler_t netlink_handler;
|
||||
sd_netlink_slot *netlink_slot;
|
||||
|
||||
bool waiting_reply;
|
||||
} Request;
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "hashmap.h"
|
||||
#include "hostname-setup.h"
|
||||
#include "netlink-util.h"
|
||||
#include "network-internal.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-queue.h"
|
||||
#include "networkd-route-util.h"
|
||||
#include "ordered-set.h"
|
||||
#include "strv.h"
|
||||
#include "tests.h"
|
||||
#include "vrf.h"
|
||||
@@ -126,6 +133,80 @@ TEST(vrf_table) {
|
||||
ASSERT_EQ(vrf.table, 5678U);
|
||||
}
|
||||
|
||||
static int test_request_process(Request *req, Link *link, void *userdata) {
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
static int test_request_netlink_handler(
|
||||
sd_netlink *rtnl,
|
||||
sd_netlink_message *message,
|
||||
Request *req,
|
||||
Link *link,
|
||||
void *userdata) {
|
||||
|
||||
assert(rtnl);
|
||||
assert(message);
|
||||
assert(req);
|
||||
assert(!link);
|
||||
assert(userdata);
|
||||
|
||||
*(bool*) userdata = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_request_netlink_handler_one(bool detach) {
|
||||
_cleanup_(manager_freep) Manager *manager = NULL;
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
|
||||
bool handler_called = false;
|
||||
unsigned counter = 0;
|
||||
Request *req;
|
||||
|
||||
ASSERT_OK(manager_new(&manager, /* test_mode= */ true));
|
||||
ASSERT_OK(sd_netlink_open(&rtnl));
|
||||
|
||||
ASSERT_OK_POSITIVE(manager_queue_request_full(
|
||||
manager,
|
||||
REQUEST_TYPE_ADDRESS_LABEL,
|
||||
&handler_called,
|
||||
/* free_func= */ NULL,
|
||||
/* hash_func= */ NULL,
|
||||
/* compare_func= */ NULL,
|
||||
test_request_process,
|
||||
&counter,
|
||||
test_request_netlink_handler,
|
||||
&req));
|
||||
ASSERT_EQ(counter, 1U);
|
||||
|
||||
int ifindex = (int) if_nametoindex("lo");
|
||||
ASSERT_GT(ifindex, 0);
|
||||
ASSERT_OK(sd_rtnl_message_new_link(rtnl, &message, RTM_GETLINK, ifindex));
|
||||
ASSERT_OK(request_call_netlink_async(rtnl, message, req));
|
||||
ASSERT_EQ(netlink_get_reply_callback_count(rtnl), 1U);
|
||||
|
||||
if (detach) {
|
||||
request_detach(req);
|
||||
ASSERT_EQ(counter, 0U);
|
||||
ASSERT_EQ(netlink_get_reply_callback_count(rtnl), 0U);
|
||||
}
|
||||
|
||||
ASSERT_OK(sd_netlink_wait(rtnl, 0));
|
||||
ASSERT_OK_POSITIVE(sd_netlink_process(rtnl, /* ret= */ NULL));
|
||||
|
||||
ASSERT_EQ(handler_called, !detach);
|
||||
ASSERT_EQ(counter, 0U);
|
||||
ASSERT_EQ(netlink_get_reply_callback_count(rtnl), 0U);
|
||||
ASSERT_TRUE(ordered_set_isempty(manager->request_queue));
|
||||
}
|
||||
|
||||
TEST(request_netlink_handler_called) {
|
||||
test_request_netlink_handler_one(/* detach= */ false);
|
||||
}
|
||||
|
||||
TEST(request_netlink_handler_detached) {
|
||||
test_request_netlink_handler_one(/* detach= */ true);
|
||||
}
|
||||
|
||||
TEST(manager_enumerate) {
|
||||
_cleanup_(manager_freep) Manager *manager = NULL;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user