1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "networkd-address.h"
4 #include "networkd-address-label.h"
5 #include "networkd-bridge-fdb.h"
6 #include "networkd-bridge-mdb.h"
7 #include "networkd-dhcp-server.h"
8 #include "networkd-ipv6-proxy-ndp.h"
9 #include "networkd-manager.h"
10 #include "networkd-neighbor.h"
11 #include "networkd-nexthop.h"
12 #include "networkd-route.h"
13 #include "networkd-routing-policy-rule.h"
14 #include "networkd-queue.h"
15 #include "networkd-setlink.h"
17 static void request_free_object(RequestType type
, void *object
) {
19 case REQUEST_TYPE_ACTIVATE_LINK
:
21 case REQUEST_TYPE_ADDRESS
:
24 case REQUEST_TYPE_ADDRESS_LABEL
:
25 address_label_free(object
);
27 case REQUEST_TYPE_BRIDGE_FDB
:
28 bridge_fdb_free(object
);
30 case REQUEST_TYPE_BRIDGE_MDB
:
31 bridge_mdb_free(object
);
33 case REQUEST_TYPE_CREATE_STACKED_NETDEV
:
35 case REQUEST_TYPE_DHCP_SERVER
:
37 case REQUEST_TYPE_IPV6_PROXY_NDP
:
40 case REQUEST_TYPE_NEIGHBOR
:
41 neighbor_free(object
);
43 case REQUEST_TYPE_NEXTHOP
:
46 case REQUEST_TYPE_ROUTE
:
49 case REQUEST_TYPE_ROUTING_POLICY_RULE
:
50 routing_policy_rule_free(object
);
52 case REQUEST_TYPE_SET_LINK
:
53 case REQUEST_TYPE_UP_DOWN
:
56 assert_not_reached("invalid request type.");
60 static Request
*request_free(Request
*req
) {
64 if (req
->link
&& req
->link
->manager
)
65 /* To prevent from triggering assertions in hash functions, remove this request before
66 * freeing object below. */
67 ordered_set_remove(req
->link
->manager
->request_queue
, req
);
69 /* on_free() may use object. So, let's call this earlier. */
71 if (req
->consume_object
)
72 request_free_object(req
->type
, req
->object
);
73 link_unref(req
->link
);
78 DEFINE_TRIVIAL_CLEANUP_FUNC(Request
*, request_free
);
80 void request_drop(Request
*req
) {
81 if (req
->message_counter
)
82 (*req
->message_counter
)--;
87 static void request_hash_func(const Request
*req
, struct siphash
*state
) {
92 siphash24_compress(&req
->link
->ifindex
, sizeof(req
->link
->ifindex
), state
);
93 siphash24_compress(&req
->type
, sizeof(req
->type
), state
);
96 case REQUEST_TYPE_ACTIVATE_LINK
:
98 case REQUEST_TYPE_ADDRESS
:
99 address_hash_func(req
->address
, state
);
101 case REQUEST_TYPE_ADDRESS_LABEL
:
102 case REQUEST_TYPE_BRIDGE_FDB
:
103 case REQUEST_TYPE_BRIDGE_MDB
:
104 case REQUEST_TYPE_CREATE_STACKED_NETDEV
:
105 /* TODO: Currently, these types do not have any specific hash and compare functions.
106 * Fortunately, all these objects are 'static', thus we can use the trivial functions. */
107 trivial_hash_func(req
->object
, state
);
109 case REQUEST_TYPE_DHCP_SERVER
:
110 /* This type does not have object. */
112 case REQUEST_TYPE_IPV6_PROXY_NDP
:
113 in6_addr_hash_func(req
->ipv6_proxy_ndp
, state
);
115 case REQUEST_TYPE_NEIGHBOR
:
116 neighbor_hash_func(req
->neighbor
, state
);
118 case REQUEST_TYPE_NEXTHOP
:
119 nexthop_hash_func(req
->nexthop
, state
);
121 case REQUEST_TYPE_ROUTE
:
122 route_hash_func(req
->route
, state
);
124 case REQUEST_TYPE_ROUTING_POLICY_RULE
:
125 routing_policy_rule_hash_func(req
->rule
, state
);
127 case REQUEST_TYPE_SET_LINK
: {
128 trivial_hash_func(req
->set_link_operation_ptr
, state
);
131 case REQUEST_TYPE_UP_DOWN
:
134 assert_not_reached("invalid request type.");
138 static int request_compare_func(const struct Request
*a
, const struct Request
*b
) {
146 r
= CMP(a
->link
->ifindex
, b
->link
->ifindex
);
150 r
= CMP(a
->type
, b
->type
);
155 case REQUEST_TYPE_ACTIVATE_LINK
:
157 case REQUEST_TYPE_ADDRESS
:
158 return address_compare_func(a
->address
, b
->address
);
159 case REQUEST_TYPE_ADDRESS_LABEL
:
160 case REQUEST_TYPE_BRIDGE_FDB
:
161 case REQUEST_TYPE_BRIDGE_MDB
:
162 case REQUEST_TYPE_CREATE_STACKED_NETDEV
:
163 return trivial_compare_func(a
->object
, b
->object
);
164 case REQUEST_TYPE_DHCP_SERVER
:
166 case REQUEST_TYPE_IPV6_PROXY_NDP
:
167 return in6_addr_compare_func(a
->ipv6_proxy_ndp
, b
->ipv6_proxy_ndp
);
168 case REQUEST_TYPE_NEIGHBOR
:
169 return neighbor_compare_func(a
->neighbor
, b
->neighbor
);
170 case REQUEST_TYPE_NEXTHOP
:
171 return nexthop_compare_func(a
->nexthop
, b
->nexthop
);
172 case REQUEST_TYPE_ROUTE
:
173 return route_compare_func(a
->route
, b
->route
);
174 case REQUEST_TYPE_ROUTING_POLICY_RULE
:
175 return routing_policy_rule_compare_func(a
->rule
, b
->rule
);
176 case REQUEST_TYPE_SET_LINK
:
177 return trivial_compare_func(a
->set_link_operation_ptr
, b
->set_link_operation_ptr
);
178 case REQUEST_TYPE_UP_DOWN
:
181 assert_not_reached("invalid request type.");
185 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
189 request_compare_func
,
192 int link_queue_request(
197 unsigned *message_counter
,
198 link_netlink_message_handler_t netlink_handler
,
201 _cleanup_(request_freep
) Request
*req
= NULL
;
206 assert(link
->manager
);
207 assert(type
>= 0 && type
< _REQUEST_TYPE_MAX
);
209 REQUEST_TYPE_ACTIVATE_LINK
,
210 REQUEST_TYPE_DHCP_SERVER
,
211 REQUEST_TYPE_SET_LINK
,
212 REQUEST_TYPE_UP_DOWN
) ||
214 assert(type
== REQUEST_TYPE_DHCP_SERVER
|| netlink_handler
);
216 req
= new(Request
, 1);
219 request_free_object(type
, object
);
224 .link
= link_ref(link
),
227 .consume_object
= consume_object
,
228 .message_counter
= message_counter
,
229 .netlink_handler
= netlink_handler
,
232 existing
= ordered_set_get(link
->manager
->request_queue
, req
);
234 /* To prevent from removing the existing request. */
235 req
->link
= link_unref(req
->link
);
242 r
= ordered_set_ensure_put(&link
->manager
->request_queue
, &request_hash_ops
, req
);
246 if (req
->message_counter
)
247 (*req
->message_counter
)++;
256 int manager_process_requests(sd_event_source
*s
, void *userdata
) {
257 Manager
*manager
= userdata
;
263 bool processed
= false;
266 ORDERED_SET_FOREACH(req
, manager
->request_queue
) {
268 case REQUEST_TYPE_ACTIVATE_LINK
:
269 r
= request_process_activation(req
);
271 case REQUEST_TYPE_ADDRESS
:
272 r
= request_process_address(req
);
274 case REQUEST_TYPE_ADDRESS_LABEL
:
275 r
= request_process_address_label(req
);
277 case REQUEST_TYPE_BRIDGE_FDB
:
278 r
= request_process_bridge_fdb(req
);
280 case REQUEST_TYPE_BRIDGE_MDB
:
281 r
= request_process_bridge_mdb(req
);
283 case REQUEST_TYPE_CREATE_STACKED_NETDEV
:
284 r
= request_process_create_stacked_netdev(req
);
286 case REQUEST_TYPE_DHCP_SERVER
:
287 r
= request_process_dhcp_server(req
);
289 case REQUEST_TYPE_IPV6_PROXY_NDP
:
290 r
= request_process_ipv6_proxy_ndp_address(req
);
292 case REQUEST_TYPE_NEIGHBOR
:
293 r
= request_process_neighbor(req
);
295 case REQUEST_TYPE_NEXTHOP
:
296 r
= request_process_nexthop(req
);
298 case REQUEST_TYPE_ROUTE
:
299 r
= request_process_route(req
);
301 case REQUEST_TYPE_ROUTING_POLICY_RULE
:
302 r
= request_process_routing_policy_rule(req
);
304 case REQUEST_TYPE_SET_LINK
:
305 r
= request_process_set_link(req
);
307 case REQUEST_TYPE_UP_DOWN
:
308 r
= request_process_link_up_or_down(req
);
314 link_enter_failed(req
->link
);
316 ordered_set_remove(manager
->request_queue
, req
);