if (r < 0)
return r;
- r = netlink_call_async(netdev->manager->rtnl, NULL, m, req->netlink_handler,
- link_netlink_destroy_callback, link);
+ r = request_call_netlink_async(netdev->manager->rtnl, m, req);
if (r < 0)
return r;
- link_ref(link);
-
netdev->state = NETDEV_STATE_CREATING;
log_netdev_debug(netdev, "Creating");
return 0;
return 1;
}
-static int link_create_stacked_netdev_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int create_stacked_netdev_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
int r;
assert(m);
assert(link);
- assert(link->create_stacked_netdev_messages > 0);
-
- link->create_stacked_netdev_messages--;
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 0;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
link->stacked_netdevs_created = false;
r = link_queue_request(link, REQUEST_TYPE_NETDEV_STACKED, netdev_ref(netdev), true,
&link->create_stacked_netdev_messages,
- link_create_stacked_netdev_handler,
+ create_stacked_netdev_handler,
NULL);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request stacked netdev '%s': %m",
return 0;
}
-static int address_label_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int address_label_configure_handler(
+ sd_netlink *rtnl,
+ sd_netlink_message *m,
+ Request *req,
+ Link *link,
+ void *userdata) {
+
int r;
- assert(rtnl);
assert(m);
assert(link);
- assert(link->ifname);
- assert(link->static_address_label_messages > 0);
-
- link->static_address_label_messages--;
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
if (r < 0)
return r;
- r = netlink_call_async(link->manager->rtnl, NULL, m, req->netlink_handler,
- link_netlink_destroy_callback, link);
- if (r < 0)
- return r;
-
- link_ref(link);
- return 0;
+ return request_call_netlink_async(link->manager->rtnl, m, req);
}
int address_label_process_request(Request *req, Link *link, void *userdata) {
assert(link);
assert(error_msg);
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 0;
-
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, error_msg);
if (r < 0)
return r;
- r = netlink_call_async(link->manager->rtnl, NULL, m, req->netlink_handler, link_netlink_destroy_callback, link);
- if (r < 0)
- return r;
-
- link_ref(link);
- return 0;
+ return request_call_netlink_async(link->manager->rtnl, m, req);
}
static bool address_is_ready_to_configure(Link *link, const Address *address) {
Address *address,
bool consume_object,
unsigned *message_counter,
- link_netlink_message_handler_t netlink_handler,
+ address_netlink_handler_t netlink_handler,
Request **ret) {
Address *acquired, *existing;
log_address_debug(existing, "Requesting", link);
r = link_queue_request(link, REQUEST_TYPE_ADDRESS, existing, false,
- message_counter, netlink_handler, ret);
+ message_counter, (request_netlink_handler_t) netlink_handler, ret);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to request address: %m");
if (r == 0)
return 1;
}
-static int static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
int r;
assert(link);
- assert(link->static_address_messages > 0);
-
- link->static_address_messages--;
r = address_configure_handler_internal(rtnl, m, link, "Failed to set static address");
if (r <= 0)
typedef struct Network Network;
typedef struct Request Request;
typedef int (*address_ready_callback_t)(Address *address);
+typedef int (*address_netlink_handler_t)(
+ sd_netlink *rtnl,
+ sd_netlink_message *m,
+ Request *req,
+ Link *link,
+ Address *address);
struct Address {
Link *link;
Address *address,
bool consume_object,
unsigned *message_counter,
- link_netlink_message_handler_t netlink_handler,
+ address_netlink_handler_t netlink_handler,
Request **ret);
int link_request_static_address(Link *link, Address *address, bool consume);
int link_request_static_addresses(Link *link);
return 0;
}
-static int bridge_fdb_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int bridge_fdb_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
int r;
+ assert(m);
assert(link);
- assert(link->static_bridge_fdb_messages > 0);
-
- link->static_bridge_fdb_messages--;
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 0;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
if (r < 0)
return r;
- r = netlink_call_async(link->manager->rtnl, NULL, m, req->netlink_handler,
- link_netlink_destroy_callback, link);
- if (r < 0)
- return r;
-
- link_ref(link);
- return 0;
+ return request_call_netlink_async(link->manager->rtnl, m, req);
}
static bool bridge_fdb_is_ready_to_configure(BridgeFDB *fdb, Link *link) {
return 0;
}
-static int bridge_mdb_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int bridge_mdb_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
int r;
+ assert(m);
assert(link);
- assert(link->static_bridge_mdb_messages > 0);
-
- link->static_bridge_mdb_messages--;
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 1;
r = sd_netlink_message_get_errno(m);
if (r == -EINVAL && streq_ptr(link->kind, "bridge") && link->master_ifindex <= 0) {
if (r < 0)
return r;
- r = netlink_call_async(link->manager->rtnl, NULL, m, req->netlink_handler,
- link_netlink_destroy_callback, link);
- if (r < 0)
- return r;
-
- link_ref(link);
- return 0;
+ return request_call_netlink_async(link->manager->rtnl, m, req);
}
static bool bridge_mdb_is_ready_to_configure(Link *link) {
return 1;
}
-static int dhcp_pd_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int dhcp_pd_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
int r;
assert(link);
- assert(link->dhcp_pd_messages > 0);
-
- link->dhcp_pd_messages--;
r = route_configure_handler_internal(rtnl, m, link, "Failed to add prefix route for DHCP delegated subnet prefix");
if (r <= 0)
return 0;
}
-static int dhcp_pd_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int dhcp_pd_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
int r;
assert(link);
- assert(link->dhcp_pd_messages > 0);
-
- link->dhcp_pd_messages--;
r = address_configure_handler_internal(rtnl, m, link, "Could not set DHCP-PD address");
if (r <= 0)
(void) link_remove(tunnel);
}
-static int dhcp4_unreachable_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int dhcp4_unreachable_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
int r;
assert(link);
- assert(link->dhcp4_messages > 0);
-
- link->dhcp4_messages--;
r = route_configure_handler_internal(rtnl, m, link, "Failed to set unreachable route for DHCPv4 delegated prefix");
if (r <= 0)
return 1;
}
-static int dhcp6_unreachable_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int dhcp6_unreachable_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
int r;
assert(link);
- assert(link->dhcp6_messages > 0);
-
- link->dhcp6_messages--;
r = route_configure_handler_internal(rtnl, m, link, "Failed to set unreachable route for DHCPv6 delegated prefix");
if (r <= 0)
NetworkConfigSource source,
const union in_addr_union *server_address,
unsigned *counter,
- link_netlink_message_handler_t callback) {
+ route_netlink_handler_t callback) {
_cleanup_(route_freep) Route *route = NULL;
Route *existing;
return dhcp4_request_address_and_routes(link, false);
}
-static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
int r;
+ assert(m);
assert(link);
- assert(link->dhcp4_messages > 0);
-
- link->dhcp4_messages--;
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 1;
r = sd_netlink_message_get_errno(m);
if (r == -ENETUNREACH && !link->dhcp4_route_retrying) {
return link_request_static_routes(link, true);
}
-static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
int r;
assert(link);
- assert(link->dhcp4_messages > 0);
-
- link->dhcp4_messages--;
r = address_configure_handler_internal(rtnl, m, link, "Could not set DHCPv4 address");
if (r <= 0)
return 0;
}
-static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
int r;
assert(link);
- assert(link->dhcp6_messages > 0);
-
- link->dhcp6_messages--;
r = address_configure_handler_internal(rtnl, m, link, "Could not set DHCPv6 address");
if (r <= 0)
return address_remove(existing);
}
-static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
int r;
assert(link);
}
}
-static int ipv6_proxy_ndp_address_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int ipv6_proxy_ndp_address_configure_handler(
+ sd_netlink *rtnl,
+ sd_netlink_message *m,
+ Request *req,
+ Link *link,
+ struct in6_addr *address) {
+
int r;
+ assert(m);
assert(link);
- assert(link->static_ipv6_proxy_ndp_messages > 0);
-
- link->static_ipv6_proxy_ndp_messages--;
r = sd_netlink_message_get_errno(m);
if (r < 0)
if (r < 0)
return r;
- r = netlink_call_async(link->manager->rtnl, NULL, m, req->netlink_handler,
- link_netlink_destroy_callback, link);
- if (r < 0)
- return r;
-
- link_ref(link);
- return 0;
+ return request_call_netlink_async(link->manager->rtnl, m, req);
}
int ipv6_proxy_ndp_address_process_request(Request *req, Link *link, struct in6_addr *address) {
SET_FOREACH(address, link->network->ipv6_proxy_ndp_addresses) {
r = link_queue_request(link, REQUEST_TYPE_IPV6_PROXY_NDP, address, false,
&link->static_ipv6_proxy_ndp_messages,
- ipv6_proxy_ndp_address_configure_handler, NULL);
+ (request_netlink_handler_t) ipv6_proxy_ndp_address_configure_handler,
+ NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to request IPv6 proxy NDP address: %m");
}
return 0;
}
-static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
int r;
assert(link);
- assert(link->ndisc_messages > 0);
-
- link->ndisc_messages--;
r = route_configure_handler_internal(rtnl, m, link, "Could not set NDisc route");
if (r <= 0)
ndisc_route_handler, NULL);
}
-static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
int r;
assert(link);
- assert(link->ndisc_messages > 0);
-
- link->ndisc_messages--;
r = address_configure_handler_internal(rtnl, m, link, "Could not set NDisc address");
if (r <= 0)
if (r < 0)
return r;
- r = netlink_call_async(link->manager->rtnl, NULL, m, req->netlink_handler,
- link_netlink_destroy_callback, link);
- if (r < 0)
- return r;
-
- link_ref(link);
-
- return 0;
+ return request_call_netlink_async(link->manager->rtnl, m, req);
}
int neighbor_process_request(Request *req, Link *link, Neighbor *neighbor) {
return 1;
}
-static int static_neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int static_neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Neighbor *neighbor) {
int r;
assert(m);
assert(link);
- assert(link->static_neighbor_messages > 0);
-
- link->static_neighbor_messages--;
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
return 1;
}
-static int link_request_neighbor(
- Link *link,
- const Neighbor *neighbor,
- unsigned *message_counter,
- link_netlink_message_handler_t netlink_handler,
- Request **ret) {
-
+static int link_request_neighbor(Link *link, const Neighbor *neighbor) {
Neighbor *existing;
int r;
log_neighbor_debug(existing, "Requesting", link);
r = link_queue_request(link, REQUEST_TYPE_NEIGHBOR, existing, false,
- message_counter, netlink_handler, ret);
+ &link->static_neighbor_messages,
+ (request_netlink_handler_t) static_neighbor_configure_handler,
+ NULL);
if (r <= 0)
return r;
link->static_neighbors_configured = false;
HASHMAP_FOREACH(neighbor, link->network->neighbors_by_section) {
- r = link_request_neighbor(link, neighbor, &link->static_neighbor_messages,
- static_neighbor_configure_handler, NULL);
+ r = link_request_neighbor(link, neighbor);
if (r < 0)
return log_link_warning_errno(link, r, "Could not request neighbor: %m");
}
}
}
- r = netlink_call_async(link->manager->rtnl, NULL, m, req->netlink_handler,
- link_netlink_destroy_callback, link);
- if (r < 0)
- return r;
-
- link_ref(link);
- return 0;
+ return request_call_netlink_async(link->manager->rtnl, m, req);
}
-static int static_nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int static_nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, NextHop *nexthop) {
int r;
+ assert(m);
assert(link);
- assert(link->static_nexthop_messages > 0);
-
- link->static_nexthop_messages--;
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
return 1;
}
-static int link_request_nexthop(
- Link *link,
- NextHop *nexthop,
- unsigned *message_counter,
- link_netlink_message_handler_t netlink_handler,
- Request **ret) {
-
+static int link_request_nexthop(Link *link, NextHop *nexthop) {
NextHop *existing;
int r;
log_nexthop_debug(existing, "Requesting", link);
r = link_queue_request(link, REQUEST_TYPE_NEXTHOP, existing, false,
- message_counter, netlink_handler, ret);
+ &link->static_nexthop_messages,
+ (request_netlink_handler_t) static_nexthop_handler,
+ NULL);
if (r <= 0)
return r;
if (only_ipv4 && nh->family != AF_INET)
continue;
- r = link_request_nexthop(link, nh, &link->static_nexthop_messages,
- static_nexthop_handler, NULL);
+ r = link_request_nexthop(link, nh);
if (r < 0)
return log_link_warning_errno(link, r, "Could not request nexthop: %m");
}
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include "netlink-util.h"
#include "networkd-address.h"
#include "networkd-address-label.h"
#include "networkd-bridge-fdb.h"
if (req->consume_object)
request_free_object(req->type, req->object);
+ if (req->counter)
+ (*req->counter)--;
+
link_unref(req->link); /* link may be NULL, but link_unref() can handle it gracefully. */
return mfree(req);
}
DEFINE_TRIVIAL_REF_UNREF_FUNC(Request, request, request_free);
+DEFINE_TRIVIAL_DESTRUCTOR(request_destroy_callback, Request, request_unref);
void request_detach(Manager *manager, Request *req) {
assert(manager);
return;
req->manager = NULL;
-
- if (req->message_counter) {
- assert(*req->message_counter > 0);
- (*req->message_counter)--;
- req->message_counter = NULL; /* To prevent double decrement. */
- }
-
request_unref(req);
}
RequestType type,
void *object,
bool consume_object,
- unsigned *message_counter,
- link_netlink_message_handler_t netlink_handler,
+ unsigned *counter,
+ request_netlink_handler_t netlink_handler,
Request **ret) {
_cleanup_(request_unrefp) Request *req = NULL;
.type = type,
.object = object,
.consume_object = consume_object,
- .message_counter = message_counter,
.netlink_handler = netlink_handler,
};
return r;
req->manager = link->manager;
- if (req->message_counter)
- (*req->message_counter)++;
+ req->counter = counter;
+ if (req->counter)
+ (*req->counter)++;
if (ret)
*ret = req;
default:
return -EINVAL;
}
- if (r < 0) {
- if (req->link)
- link_enter_failed(req->link);
- } else if (r > 0) {
- req->message_counter = NULL;
- request_detach(manager, req);
- processed = true;
- }
+ if (r == 0)
+ continue;
+
+ processed = true;
+ request_detach(manager, req);
+
+ if (r < 0 && req->link)
+ link_enter_failed(req->link);
}
if (!processed)
return 0;
}
+
+static int request_netlink_handler(sd_netlink *nl, sd_netlink_message *m, Request *req) {
+ assert(req);
+
+ if (req->counter) {
+ assert(*req->counter > 0);
+ (*req->counter)--;
+ req->counter = NULL; /* To prevent double decrement on free. */
+ }
+
+ if (req->link && IN_SET(req->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return 0;
+
+ if (req->netlink_handler)
+ return req->netlink_handler(nl, m, req, req->link, req->object);
+
+ return 0;
+}
+
+int request_call_netlink_async(sd_netlink *nl, sd_netlink_message *m, Request *req) {
+ int r;
+
+ assert(nl);
+ assert(m);
+ assert(req);
+
+ r = netlink_call_async(nl, NULL, m, request_netlink_handler, request_destroy_callback, req);
+ if (r < 0)
+ return r;
+
+ request_ref(req);
+ return 0;
+}
#pragma once
#include "sd-event.h"
+#include "sd-netlink.h"
#include "networkd-link.h"
typedef struct RoutingPolicyRule RoutingPolicyRule;
typedef struct QDisc QDisc;
typedef struct TClass TClass;
+typedef struct Request Request;
+
+typedef int (*request_netlink_handler_t)(sd_netlink *nl, sd_netlink_message *m, Request *req, Link *link, void *userdata);
typedef enum RequestType {
REQUEST_TYPE_ACTIVATE_LINK,
_REQUEST_TYPE_INVALID = -EINVAL,
} RequestType;
-typedef struct Request {
+struct Request {
unsigned n_ref;
Manager *manager; /* must be non-NULL */
void *object;
};
void *userdata;
- unsigned *message_counter;
- link_netlink_message_handler_t netlink_handler;
-} Request;
+
+ /* incremented when requested, decremented when request is completed or failed. */
+ unsigned *counter;
+ /* called in netlink handler, the 'counter' is decremented before this is called.
+ * If this is specified, then the 'process' function must increment the reference of this
+ * request, and pass this request to the netlink_call_async(), and set the destroy function
+ * to the slot. */
+ request_netlink_handler_t netlink_handler;
+};
Request *request_ref(Request *req);
Request *request_unref(Request *req);
RequestType type,
void *object,
bool consume_object,
- unsigned *message_counter,
- link_netlink_message_handler_t netlink_handler,
+ unsigned *counter,
+ request_netlink_handler_t netlink_handler,
Request **ret);
int manager_process_requests(sd_event_source *s, void *userdata);
+int request_call_netlink_async(sd_netlink *nl, sd_netlink_message *m, Request *req);
assert(link);
assert(error_msg);
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 0;
-
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not set route");
return r;
}
- r = netlink_call_async(link->manager->rtnl, NULL, m, req->netlink_handler,
- link_netlink_destroy_callback, link);
- if (r < 0)
- return r;
-
- link_ref(link);
- return 0;
+ return request_call_netlink_async(link->manager->rtnl, m, req);
}
static int route_is_ready_to_configure(const Route *route, Link *link) {
Route *route,
bool consume_object,
unsigned *message_counter,
- link_netlink_message_handler_t netlink_handler,
+ route_netlink_handler_t netlink_handler,
Request **ret) {
Route *existing;
log_route_debug(existing, "Requesting", link, link->manager);
r = link_queue_request(link, REQUEST_TYPE_ROUTE, existing, false,
- message_counter, netlink_handler, ret);
+ message_counter, (request_netlink_handler_t) netlink_handler, ret);
if (r <= 0)
return r;
return 1;
}
-static int static_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int static_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
int r;
assert(link);
- assert(link->static_route_messages > 0);
-
- link->static_route_messages--;
r = route_configure_handler_internal(rtnl, m, link, "Could not set route");
if (r <= 0)
log_route_debug(route, "Requesting", link, link->manager);
return link_queue_request(link, REQUEST_TYPE_ROUTE, route, false,
- &link->static_route_messages, static_route_handler, NULL);
+ &link->static_route_messages,
+ (request_netlink_handler_t) static_route_handler,
+ NULL);
}
static int link_request_wireguard_routes(Link *link, bool only_ipv4) {
typedef struct Manager Manager;
typedef struct Network Network;
typedef struct Request Request;
+typedef struct Route Route;
+typedef int (*route_netlink_handler_t)(
+ sd_netlink *rtnl,
+ sd_netlink_message *m,
+ Request *req,
+ Link *link,
+ Route *route);
-typedef struct Route {
+struct Route {
Link *link;
Manager *manager;
Network *network;
usec_t lifetime_usec;
/* Used when kernel does not support RTA_EXPIRES attribute. */
sd_event_source *expire;
-} Route;
+};
void route_hash_func(const Route *route, struct siphash *state);
int route_compare_func(const Route *a, const Route *b);
Route *route,
bool consume_object,
unsigned *message_counter,
- link_netlink_message_handler_t netlink_handler,
+ route_netlink_handler_t netlink_handler,
Request **ret);
int link_request_static_routes(Link *link, bool only_ipv4);
int route_process_request(Request *req, Link *link, Route *route);
if (r < 0)
return r;
- r = netlink_call_async(link->manager->rtnl, NULL, m, req->netlink_handler,
- link_netlink_destroy_callback, link);
- if (r < 0)
- return r;
-
- link_ref(link);
- return 0;
+ return request_call_netlink_async(link->manager->rtnl, m, req);
}
static void manager_mark_routing_policy_rules(Manager *m, bool foreign, const Link *except) {
return 1;
}
-static int static_routing_policy_rule_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int static_routing_policy_rule_configure_handler(
+ sd_netlink *rtnl,
+ sd_netlink_message *m,
+ Request *req,
+ Link *link,
+ RoutingPolicyRule *rule) {
+
int r;
- assert(rtnl);
assert(m);
assert(link);
- assert(link->ifname);
- assert(link->static_routing_policy_rule_messages > 0);
-
- link->static_routing_policy_rule_messages--;
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
return 1;
}
-static int link_request_routing_policy_rule(
- Link *link,
- RoutingPolicyRule *rule,
- unsigned *message_counter,
- link_netlink_message_handler_t netlink_handler,
- Request **ret) {
-
+static int link_request_routing_policy_rule(Link *link, RoutingPolicyRule *rule) {
RoutingPolicyRule *existing;
int r;
log_routing_policy_rule_debug(existing, "Requesting", link, link->manager);
r = link_queue_request(link, REQUEST_TYPE_ROUTING_POLICY_RULE, existing, false,
- message_counter, netlink_handler, ret);
+ &link->static_routing_policy_rule_messages,
+ (request_netlink_handler_t) static_routing_policy_rule_configure_handler,
+ NULL);
if (r <= 0)
return r;
int r;
if (IN_SET(rule->family, AF_INET, AF_INET6))
- return link_request_routing_policy_rule(link, rule,
- &link->static_routing_policy_rule_messages,
- static_routing_policy_rule_configure_handler,
- NULL);
+ return link_request_routing_policy_rule(link, rule);
rule->family = AF_INET;
- r = link_request_routing_policy_rule(link, rule,
- &link->static_routing_policy_rule_messages,
- static_routing_policy_rule_configure_handler,
- NULL);
+ r = link_request_routing_policy_rule(link, rule);
if (r < 0) {
rule->family = AF_UNSPEC;
return r;
}
rule->family = AF_INET6;
- r = link_request_routing_policy_rule(link, rule,
- &link->static_routing_policy_rule_messages,
- static_routing_policy_rule_configure_handler,
- NULL);
+ r = link_request_routing_policy_rule(link, rule);
rule->family = AF_UNSPEC;
return r;
}
static int set_link_handler_internal(
sd_netlink *rtnl,
sd_netlink_message *m,
+ Request *req,
Link *link,
- SetLinkOperation op,
bool ignore,
link_netlink_message_handler_t get_link_handler) {
+ SetLinkOperation op;
int r;
assert(m);
+ assert(req);
assert(link);
- assert(link->set_link_messages > 0);
- assert(op >= 0 && op < _SET_LINK_OPERATION_MAX);
-
- link->set_link_messages--;
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- goto on_error;
+ op = PTR_TO_INT(req->set_link_operation_ptr);
r = sd_netlink_message_get_errno(m);
if (r < 0) {
if (!ignore)
link_enter_failed(link);
- goto on_error;
+ return 0;
}
log_link_debug(link, "%s set.", set_link_operation_to_string(op));
r = link_call_getlink(link, get_link_handler);
if (r < 0) {
link_enter_failed(link);
- goto on_error;
+ return 0;
}
}
link_check_ready(link);
return 1;
-
-on_error:
- switch (op) {
- case SET_LINK_FLAGS:
- assert(link->set_flags_messages > 0);
- link->set_flags_messages--;
- break;
- case SET_LINK_MASTER:
- link->master_set = true;
- break;
- default:
- break;
- }
-
- return 0;
}
-static int link_set_addrgen_mode_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int link_set_addrgen_mode_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
int r;
- r = set_link_handler_internal(rtnl, m, link, SET_LINK_ADDRESS_GENERATION_MODE, /* ignore = */ true, NULL);
+ r = set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, NULL);
if (r <= 0)
return r;
return 0;
}
-static int link_set_bond_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- return set_link_handler_internal(rtnl, m, link, SET_LINK_BOND, /* ignore = */ false, NULL);
+static int link_set_bond_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
+ return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, NULL);
}
-static int link_set_bridge_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- return set_link_handler_internal(rtnl, m, link, SET_LINK_BRIDGE, /* ignore = */ true, NULL);
+static int link_set_bridge_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
+ return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, NULL);
}
-static int link_set_bridge_vlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- return set_link_handler_internal(rtnl, m, link, SET_LINK_BRIDGE_VLAN, /* ignore = */ false, NULL);
+static int link_set_bridge_vlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
+ return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, NULL);
}
-static int link_set_can_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- return set_link_handler_internal(rtnl, m, link, SET_LINK_CAN, /* ignore = */ false, NULL);
+static int link_set_can_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
+ return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, NULL);
}
-static int link_set_flags_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- return set_link_handler_internal(rtnl, m, link, SET_LINK_FLAGS, /* ignore = */ false, get_link_update_flag_handler);
+static int link_set_flags_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
+ return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, get_link_default_handler);
}
-static int link_set_group_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- return set_link_handler_internal(rtnl, m, link, SET_LINK_GROUP, /* ignore = */ false, NULL);
+static int link_set_group_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
+ return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, NULL);
}
-static int link_set_ipoib_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- return set_link_handler_internal(rtnl, m, link, SET_LINK_IPOIB, /* ignore = */ true, NULL);
+static int link_set_ipoib_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
+ return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, NULL);
}
-static int link_set_mac_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- return set_link_handler_internal(rtnl, m, link, SET_LINK_MAC, /* ignore = */ true, get_link_default_handler);
+static int link_set_mac_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
+ return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, get_link_default_handler);
}
-static int link_set_mac_allow_retry_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int link_set_mac_allow_retry_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
int r;
assert(m);
assert(link);
- assert(link->set_link_messages > 0);
-
- link->set_link_messages--;
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 0;
r = sd_netlink_message_get_errno(m);
if (r == -EBUSY) {
return 0;
}
- /* set_link_mac_handler() also decrements set_link_messages, so increment the value once. */
- link->set_link_messages++;
- return link_set_mac_handler(rtnl, m, link);
+ return link_set_mac_handler(rtnl, m, req, link, userdata);
}
-static int link_set_master_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- return set_link_handler_internal(rtnl, m, link, SET_LINK_MASTER, /* ignore = */ false, get_link_master_handler);
+static int link_set_master_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
+ return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, get_link_master_handler);
}
-static int link_unset_master_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int link_unset_master_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
/* Some devices do not support setting master ifindex. Let's ignore error on unsetting master ifindex. */
- return set_link_handler_internal(rtnl, m, link, SET_LINK_MASTER, /* ignore = */ true, get_link_master_handler);
+ return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, get_link_master_handler);
}
-static int link_set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int link_set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
int r;
- r = set_link_handler_internal(rtnl, m, link, SET_LINK_MTU, /* ignore = */ true, get_link_default_handler);
+ r = set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, get_link_default_handler);
if (r <= 0)
return r;
return 0;
}
-static int link_configure(
- Link *link,
- SetLinkOperation op,
- void *userdata,
- link_netlink_message_handler_t callback) {
-
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
+static int link_configure(Link *link, Request *req) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ SetLinkOperation op;
int r;
assert(link);
assert(link->manager);
assert(link->manager->rtnl);
- assert(link->network);
- assert(op >= 0 && op < _SET_LINK_OPERATION_MAX);
- assert(callback);
+ assert(req);
+
+ op = PTR_TO_INT(req->set_link_operation_ptr);
log_link_debug(link, "Setting %s", set_link_operation_to_string(op));
if (op == SET_LINK_BOND)
- r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_NEWLINK, link->master_ifindex);
+ r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, link->master_ifindex);
else if (IN_SET(op, SET_LINK_CAN, SET_LINK_IPOIB))
- r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_NEWLINK, link->ifindex);
+ r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, link->ifindex);
else
- r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
+ r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_SETLINK, link->ifindex);
if (r < 0)
- return log_link_debug_errno(link, r, "Could not allocate netlink message: %m");
+ return r;
- r = link_configure_fill_message(link, req, op, userdata);
+ r = link_configure_fill_message(link, m, op, req->userdata);
if (r < 0)
- return log_link_debug_errno(link, r, "Could not create netlink message: %m");
-
- r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
- link_netlink_destroy_callback, link);
- if (r < 0)
- return log_link_debug_errno(link, r, "Could not send netlink message: %m");
+ return r;
- link_ref(link);
- return 0;
+ return request_call_netlink_async(link->manager->rtnl, m, req);
}
static bool netdev_is_ready(NetDev *netdev) {
if (!link_is_ready_to_call_set_link(req))
return 0;
- r = link_configure(req->link, op, req->userdata, req->netlink_handler);
+ r = link_configure(req->link, req);
if (r < 0)
return log_link_error_errno(req->link, r, "Failed to set %s: %m",
set_link_operation_to_string(op));
- if (op == SET_LINK_FLAGS)
- req->link->set_flags_messages++;
-
return 1;
}
static int link_request_set_link(
Link *link,
SetLinkOperation op,
- link_netlink_message_handler_t netlink_handler,
+ request_netlink_handler_t netlink_handler,
Request **ret) {
Request *req;
return 1;
}
-static int link_up_or_down_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool up, bool on_activate) {
+static int link_up_or_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
+ bool on_activate, up;
int r;
assert(m);
+ assert(req);
assert(link);
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- goto on_error;
+ on_activate = req->type == REQUEST_TYPE_ACTIVATE_LINK;
+ up = PTR_TO_INT(req->userdata);
r = sd_netlink_message_get_errno(m);
if (r == -ENETDOWN && up && link_up_dsa_slave(link) > 0)
log_link_message_warning_errno(link, m, r, error_msg);
if (on_activate)
- goto on_error;
+ return 0;
}
r = link_call_getlink(link, get_link_update_flag_handler);
if (r < 0) {
link_enter_failed(link);
- goto on_error;
+ return 0;
}
+ link->set_flags_messages++;
+
if (on_activate) {
link->activated = true;
link_check_ready(link);
}
- return 1;
-
-on_error:
- assert(link->set_flags_messages > 0);
- link->set_flags_messages--;
-
return 0;
}
-static int link_activate_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- return link_up_or_down_handler_internal(rtnl, m, link, /* up = */ true, /* on_activate = */ true);
-}
-
-static int link_activate_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- return link_up_or_down_handler_internal(rtnl, m, link, /* up = */ false, /* on_activate = */ true);
-}
-
-static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- return link_up_or_down_handler_internal(rtnl, m, link, /* up = */ true, /* on_activate = */ false);
-}
-
-static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- return link_up_or_down_handler_internal(rtnl, m, link, /* up = */ false, /* on_activate = */ false);
-}
-
static const char *up_or_down(bool up) {
return up ? "up" : "down";
}
if (r < 0)
return r;
- r = netlink_call_async(link->manager->rtnl, NULL, m, req->netlink_handler,
- link_netlink_destroy_callback, link);
- if (r < 0)
- return r;
-
- link_ref(link);
-
- return 0;
+ return request_call_netlink_async(link->manager->rtnl, m, req);
}
static bool link_is_ready_to_activate(Link *link) {
link->activated = false;
r = link_queue_request(link, REQUEST_TYPE_ACTIVATE_LINK, NULL, false, &link->set_flags_messages,
- up ? link_activate_up_handler : link_activate_down_handler, &req);
+ link_up_or_down_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request to activate link: %m");
assert(link);
r = link_queue_request(link, REQUEST_TYPE_UP_DOWN, NULL, false, &link->set_flags_messages,
- up ? link_up_handler : link_down_handler, &req);
+ link_up_or_down_handler, &req);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to request to bring link %s: %m",
up_or_down(up));
return -ENOENT;
}
-static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, QDisc *qdisc) {
int r;
+ assert(m);
assert(link);
- assert(link->tc_messages > 0);
- link->tc_messages--;
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
return r;
}
- r = netlink_call_async(link->manager->rtnl, NULL, m, req->netlink_handler, link_netlink_destroy_callback, link);
- if (r < 0)
- return r;
-
- link_ref(link);
- return 0;
+ return request_call_netlink_async(link->manager->rtnl, m, req);
}
static bool qdisc_is_ready_to_configure(QDisc *qdisc, Link *link) {
log_qdisc_debug(existing, link, "Requesting");
r = link_queue_request(link, REQUEST_TYPE_TC_QDISC, existing, false,
- &link->tc_messages, qdisc_handler, NULL);
+ &link->tc_messages,
+ (request_netlink_handler_t) qdisc_handler,
+ NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to request QDisc: %m");
if (r == 0)
strna(tclass_get_tca_kind(tclass)));
}
-static int tclass_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int tclass_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, TClass *tclass) {
int r;
+ assert(m);
assert(link);
- assert(link->tc_messages > 0);
- link->tc_messages--;
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
return r;
}
- r = netlink_call_async(link->manager->rtnl, NULL, m, req->netlink_handler, link_netlink_destroy_callback, link);
- if (r < 0)
- return r;
-
- link_ref(link);
- return 0;
+ return request_call_netlink_async(link->manager->rtnl, m, req);
}
static bool tclass_is_ready_to_configure(TClass *tclass, Link *link) {
log_tclass_debug(existing, link, "Requesting");
r = link_queue_request(link, REQUEST_TYPE_TC_CLASS, existing, false,
- &link->tc_messages, tclass_handler, NULL);
+ &link->tc_messages,
+ (request_netlink_handler_t) tclass_handler,
+ NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to request TClass: %m");
if (r == 0)