]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-setlink.c
network: increment reference counters of Link and Request before processing requests
[thirdparty/systemd.git] / src / network / networkd-setlink.c
CommitLineData
0fa8ee6c
YW
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
93fabc10
YW
3#include <netinet/in.h>
4#include <linux/if.h>
7558f9e7 5#include <linux/if_arp.h>
ad851cae 6#include <linux/if_bridge.h>
93fabc10 7
0fa8ee6c 8#include "missing_network.h"
a8840714 9#include "netif-util.h"
0fa8ee6c 10#include "netlink-util.h"
3b6a3bde 11#include "networkd-address.h"
7558f9e7 12#include "networkd-can.h"
0fa8ee6c
YW
13#include "networkd-link.h"
14#include "networkd-manager.h"
15#include "networkd-queue.h"
9b682672 16#include "networkd-setlink.h"
0fa8ee6c 17
1362bd6c
YW
18static int get_link_default_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
19 return link_getlink_handler_internal(rtnl, m, link, "Failed to sync link information");
20}
21
440d40dc
YW
22static int get_link_master_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
23 if (get_link_default_handler(rtnl, m, link) > 0)
24 link->master_set = true;
25 return 0;
26}
27
baa95d22
YW
28static int get_link_update_flag_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
29 assert(link);
30 assert(link->set_flags_messages > 0);
31
32 link->set_flags_messages--;
33
34 return get_link_default_handler(rtnl, m, link);
35}
36
1362bd6c
YW
37static int set_link_handler_internal(
38 sd_netlink *rtnl,
39 sd_netlink_message *m,
80d62d4f 40 Request *req,
1362bd6c 41 Link *link,
1362bd6c
YW
42 bool ignore,
43 link_netlink_message_handler_t get_link_handler) {
44
0fa8ee6c
YW
45 int r;
46
47 assert(m);
80d62d4f 48 assert(req);
0fa8ee6c 49 assert(link);
0fa8ee6c 50
0fa8ee6c
YW
51 r = sd_netlink_message_get_errno(m);
52 if (r < 0) {
53 const char *error_msg;
54
eb93dc9b 55 error_msg = strjoina("Failed to set ", request_type_to_string(req->type), ignore ? ", ignoring" : "");
0fa8ee6c
YW
56 log_link_message_warning_errno(link, m, r, error_msg);
57
58 if (!ignore)
59 link_enter_failed(link);
80d62d4f 60 return 0;
0fa8ee6c
YW
61 }
62
eb93dc9b 63 log_link_debug(link, "%s set.", request_type_to_string(req->type));
1362bd6c
YW
64
65 if (get_link_handler) {
66 r = link_call_getlink(link, get_link_handler);
67 if (r < 0) {
68 link_enter_failed(link);
80d62d4f 69 return 0;
1362bd6c
YW
70 }
71 }
72
73 if (link->set_link_messages == 0)
74 link_check_ready(link);
75
0fa8ee6c
YW
76 return 1;
77}
78
80d62d4f 79static int link_set_addrgen_mode_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
8e00e24c
YW
80 int r;
81
80d62d4f 82 r = set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, NULL);
8e00e24c
YW
83 if (r <= 0)
84 return r;
85
86 r = link_drop_ipv6ll_addresses(link);
87 if (r < 0) {
88 log_link_warning_errno(link, r, "Failed to drop IPv6LL addresses: %m");
89 link_enter_failed(link);
90 }
91
92 return 0;
93}
94
80d62d4f
YW
95static int link_set_bond_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
96 return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, NULL);
5062b859
YW
97}
98
80d62d4f
YW
99static int link_set_bridge_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
100 return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, NULL);
7d5b232f
YW
101}
102
80d62d4f
YW
103static int link_set_bridge_vlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
104 return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, NULL);
8252fb44
YW
105}
106
80d62d4f
YW
107static int link_set_can_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
108 return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, NULL);
7558f9e7
YW
109}
110
80d62d4f
YW
111static int link_set_flags_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
112 return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, get_link_default_handler);
93fabc10
YW
113}
114
80d62d4f
YW
115static int link_set_group_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
116 return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, NULL);
cc4c8fb1
YW
117}
118
80d62d4f
YW
119static int link_set_ipoib_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
120 return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, NULL);
72e65e6f
YW
121}
122
80d62d4f
YW
123static int link_set_mac_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
124 return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, get_link_default_handler);
a8e5e27c
YW
125}
126
80d62d4f 127static int link_set_mac_allow_retry_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
d05c332c
YW
128 int r;
129
130 assert(m);
131 assert(link);
d05c332c
YW
132
133 r = sd_netlink_message_get_errno(m);
134 if (r == -EBUSY) {
135 /* Most real network devices refuse to set its hardware address with -EBUSY when its
136 * operstate is not down. See, eth_prepare_mac_addr_change() in net/ethernet/eth.c
137 * of kernel. */
138
139 log_link_message_debug_errno(link, m, r, "Failed to set MAC address, retrying again: %m");
140
141 r = link_request_to_set_mac(link, /* allow_retry = */ false);
142 if (r < 0)
143 link_enter_failed(link);
144
145 return 0;
146 }
147
80d62d4f 148 return link_set_mac_handler(rtnl, m, req, link, userdata);
d05c332c
YW
149}
150
80d62d4f
YW
151static int link_set_master_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
152 return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, get_link_master_handler);
d24bf1b5
YW
153}
154
80d62d4f 155static int link_unset_master_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
c347a982 156 /* Some devices do not support setting master ifindex. Let's ignore error on unsetting master ifindex. */
80d62d4f 157 return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, get_link_master_handler);
c347a982
YW
158}
159
80d62d4f 160static int link_set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
0fa8ee6c
YW
161 int r;
162
80d62d4f 163 r = set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, get_link_default_handler);
0fa8ee6c
YW
164 if (r <= 0)
165 return r;
166
167 /* The kernel resets ipv6 mtu after changing device mtu;
168 * we must set this here, after we've set device mtu */
169 r = link_set_ipv6_mtu(link);
170 if (r < 0)
171 log_link_warning_errno(link, r, "Failed to set IPv6 MTU, ignoring: %m");
172
0fa8ee6c
YW
173 return 0;
174}
175
bb2f88ff 176static int link_configure_fill_message(
0fa8ee6c 177 Link *link,
bb2f88ff 178 sd_netlink_message *req,
eb93dc9b 179 RequestType type,
bb2f88ff 180 void *userdata) {
0fa8ee6c
YW
181 int r;
182
eb93dc9b
YW
183 switch (type) {
184 case REQUEST_TYPE_SET_LINK_ADDRESS_GENERATION_MODE:
80f2647d 185 r = ipv6ll_addrgen_mode_fill_message(req, PTR_TO_UINT8(userdata));
8e00e24c 186 if (r < 0)
bb2f88ff 187 return r;
8e00e24c 188 break;
eb93dc9b 189 case REQUEST_TYPE_SET_LINK_BOND:
5062b859
YW
190 r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_ACK);
191 if (r < 0)
bb2f88ff 192 return r;
5062b859
YW
193
194 r = sd_netlink_message_open_container(req, IFLA_LINKINFO);
195 if (r < 0)
bb2f88ff 196 return r;
5062b859
YW
197
198 r = sd_netlink_message_open_container_union(req, IFLA_INFO_DATA, "bond");
199 if (r < 0)
bb2f88ff 200 return r;
5062b859
YW
201
202 if (link->network->active_slave) {
203 r = sd_netlink_message_append_u32(req, IFLA_BOND_ACTIVE_SLAVE, link->ifindex);
204 if (r < 0)
bb2f88ff 205 return r;
5062b859
YW
206 }
207
208 if (link->network->primary_slave) {
209 r = sd_netlink_message_append_u32(req, IFLA_BOND_PRIMARY, link->ifindex);
210 if (r < 0)
bb2f88ff 211 return r;
5062b859
YW
212 }
213
214 r = sd_netlink_message_close_container(req);
215 if (r < 0)
bb2f88ff 216 return r;
5062b859
YW
217
218 r = sd_netlink_message_close_container(req);
219 if (r < 0)
bb2f88ff 220 return r;
5062b859
YW
221
222 break;
eb93dc9b 223 case REQUEST_TYPE_SET_LINK_BRIDGE:
7d5b232f
YW
224 r = sd_rtnl_message_link_set_family(req, AF_BRIDGE);
225 if (r < 0)
bb2f88ff 226 return r;
7d5b232f
YW
227
228 r = sd_netlink_message_open_container(req, IFLA_PROTINFO);
229 if (r < 0)
bb2f88ff 230 return r;
7d5b232f
YW
231
232 if (link->network->use_bpdu >= 0) {
233 r = sd_netlink_message_append_u8(req, IFLA_BRPORT_GUARD, link->network->use_bpdu);
234 if (r < 0)
bb2f88ff 235 return r;
7d5b232f
YW
236 }
237
238 if (link->network->hairpin >= 0) {
239 r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MODE, link->network->hairpin);
240 if (r < 0)
bb2f88ff 241 return r;
7d5b232f
YW
242 }
243
97f27f8a
SW
244 if (link->network->isolated >= 0) {
245 r = sd_netlink_message_append_u8(req, IFLA_BRPORT_ISOLATED, link->network->isolated);
246 if (r < 0)
247 return r;
248 }
249
7d5b232f
YW
250 if (link->network->fast_leave >= 0) {
251 r = sd_netlink_message_append_u8(req, IFLA_BRPORT_FAST_LEAVE, link->network->fast_leave);
252 if (r < 0)
bb2f88ff 253 return r;
7d5b232f
YW
254 }
255
256 if (link->network->allow_port_to_be_root >= 0) {
257 r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROTECT, link->network->allow_port_to_be_root);
258 if (r < 0)
bb2f88ff 259 return r;
7d5b232f
YW
260 }
261
262 if (link->network->unicast_flood >= 0) {
263 r = sd_netlink_message_append_u8(req, IFLA_BRPORT_UNICAST_FLOOD, link->network->unicast_flood);
264 if (r < 0)
bb2f88ff 265 return r;
7d5b232f
YW
266 }
267
268 if (link->network->multicast_flood >= 0) {
269 r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MCAST_FLOOD, link->network->multicast_flood);
270 if (r < 0)
bb2f88ff 271 return r;
7d5b232f
YW
272 }
273
274 if (link->network->multicast_to_unicast >= 0) {
275 r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MCAST_TO_UCAST, link->network->multicast_to_unicast);
276 if (r < 0)
bb2f88ff 277 return r;
7d5b232f
YW
278 }
279
280 if (link->network->neighbor_suppression >= 0) {
281 r = sd_netlink_message_append_u8(req, IFLA_BRPORT_NEIGH_SUPPRESS, link->network->neighbor_suppression);
282 if (r < 0)
bb2f88ff 283 return r;
7d5b232f
YW
284 }
285
286 if (link->network->learning >= 0) {
287 r = sd_netlink_message_append_u8(req, IFLA_BRPORT_LEARNING, link->network->learning);
288 if (r < 0)
bb2f88ff 289 return r;
7d5b232f
YW
290 }
291
292 if (link->network->bridge_proxy_arp >= 0) {
293 r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROXYARP, link->network->bridge_proxy_arp);
294 if (r < 0)
bb2f88ff 295 return r;
7d5b232f
YW
296 }
297
298 if (link->network->bridge_proxy_arp_wifi >= 0) {
299 r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROXYARP_WIFI, link->network->bridge_proxy_arp_wifi);
300 if (r < 0)
bb2f88ff 301 return r;
7d5b232f
YW
302 }
303
304 if (link->network->cost != 0) {
305 r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost);
306 if (r < 0)
bb2f88ff 307 return r;
7d5b232f
YW
308 }
309
310 if (link->network->priority != LINK_BRIDGE_PORT_PRIORITY_INVALID) {
311 r = sd_netlink_message_append_u16(req, IFLA_BRPORT_PRIORITY, link->network->priority);
312 if (r < 0)
bb2f88ff 313 return r;
7d5b232f
YW
314 }
315
316 if (link->network->multicast_router != _MULTICAST_ROUTER_INVALID) {
317 r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MULTICAST_ROUTER, link->network->multicast_router);
318 if (r < 0)
bb2f88ff 319 return r;
7d5b232f
YW
320 }
321
322 r = sd_netlink_message_close_container(req);
323 if (r < 0)
bb2f88ff 324 return r;
7d5b232f 325 break;
eb93dc9b 326 case REQUEST_TYPE_SET_LINK_BRIDGE_VLAN:
8252fb44
YW
327 r = sd_rtnl_message_link_set_family(req, AF_BRIDGE);
328 if (r < 0)
bb2f88ff 329 return r;
8252fb44
YW
330
331 r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
332 if (r < 0)
bb2f88ff 333 return r;
8252fb44 334
571bf1aa 335 if (link->master_ifindex <= 0) {
7802194a 336 /* master needs BRIDGE_FLAGS_SELF flag */
8252fb44
YW
337 r = sd_netlink_message_append_u16(req, IFLA_BRIDGE_FLAGS, BRIDGE_FLAGS_SELF);
338 if (r < 0)
bb2f88ff 339 return r;
8252fb44
YW
340 }
341
342 r = bridge_vlan_append_info(link, req, link->network->pvid, link->network->br_vid_bitmap, link->network->br_untagged_bitmap);
343 if (r < 0)
bb2f88ff 344 return r;
8252fb44
YW
345
346 r = sd_netlink_message_close_container(req);
347 if (r < 0)
bb2f88ff 348 return r;
8252fb44
YW
349
350 break;
eb93dc9b 351 case REQUEST_TYPE_SET_LINK_CAN:
7558f9e7
YW
352 r = can_set_netlink_message(link, req);
353 if (r < 0)
bb2f88ff 354 return r;
7558f9e7 355 break;
eb93dc9b 356 case REQUEST_TYPE_SET_LINK_FLAGS: {
93fabc10
YW
357 unsigned ifi_change = 0, ifi_flags = 0;
358
359 if (link->network->arp >= 0) {
360 ifi_change |= IFF_NOARP;
361 SET_FLAG(ifi_flags, IFF_NOARP, link->network->arp == 0);
362 }
363
364 if (link->network->multicast >= 0) {
365 ifi_change |= IFF_MULTICAST;
366 SET_FLAG(ifi_flags, IFF_MULTICAST, link->network->multicast);
367 }
368
369 if (link->network->allmulticast >= 0) {
370 ifi_change |= IFF_ALLMULTI;
371 SET_FLAG(ifi_flags, IFF_ALLMULTI, link->network->allmulticast);
372 }
373
374 if (link->network->promiscuous >= 0) {
375 ifi_change |= IFF_PROMISC;
376 SET_FLAG(ifi_flags, IFF_PROMISC, link->network->promiscuous);
377 }
378
379 r = sd_rtnl_message_link_set_flags(req, ifi_flags, ifi_change);
380 if (r < 0)
bb2f88ff 381 return r;
93fabc10
YW
382
383 break;
384 }
eb93dc9b 385 case REQUEST_TYPE_SET_LINK_GROUP:
10af8bb2 386 r = sd_netlink_message_append_u32(req, IFLA_GROUP, (uint32_t) link->network->group);
cc4c8fb1 387 if (r < 0)
bb2f88ff 388 return r;
cc4c8fb1 389 break;
eb93dc9b 390 case REQUEST_TYPE_SET_LINK_MAC:
a8840714 391 r = netlink_message_append_hw_addr(req, IFLA_ADDRESS, &link->requested_hw_addr);
a8e5e27c 392 if (r < 0)
bb2f88ff 393 return r;
a8e5e27c 394 break;
eb93dc9b 395 case REQUEST_TYPE_SET_LINK_IPOIB:
72e65e6f
YW
396 r = ipoib_set_netlink_message(link, req);
397 if (r < 0)
bb2f88ff 398 return r;
72e65e6f 399 break;
eb93dc9b 400 case REQUEST_TYPE_SET_LINK_MASTER:
d24bf1b5
YW
401 r = sd_netlink_message_append_u32(req, IFLA_MASTER, PTR_TO_UINT32(userdata));
402 if (r < 0)
bb2f88ff 403 return r;
d24bf1b5 404 break;
eb93dc9b 405 case REQUEST_TYPE_SET_LINK_MTU:
0fa8ee6c
YW
406 r = sd_netlink_message_append_u32(req, IFLA_MTU, PTR_TO_UINT32(userdata));
407 if (r < 0)
bb2f88ff 408 return r;
0fa8ee6c
YW
409 break;
410 default:
04499a70 411 assert_not_reached();
0fa8ee6c
YW
412 }
413
bb2f88ff
ZJS
414 return 0;
415}
416
80d62d4f
YW
417static int link_configure(Link *link, Request *req) {
418 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
bb2f88ff
ZJS
419 int r;
420
421 assert(link);
422 assert(link->manager);
423 assert(link->manager->rtnl);
80d62d4f
YW
424 assert(req);
425
eb93dc9b 426 log_link_debug(link, "Setting %s", request_type_to_string(req->type));
bb2f88ff 427
eb93dc9b 428 if (req->type == REQUEST_TYPE_SET_LINK_BOND)
80d62d4f 429 r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, link->master_ifindex);
eb93dc9b 430 else if (IN_SET(req->type, REQUEST_TYPE_SET_LINK_CAN, REQUEST_TYPE_SET_LINK_IPOIB))
80d62d4f 431 r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, link->ifindex);
bb2f88ff 432 else
80d62d4f 433 r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_SETLINK, link->ifindex);
bb2f88ff 434 if (r < 0)
80d62d4f 435 return r;
bb2f88ff 436
eb93dc9b 437 r = link_configure_fill_message(link, m, req->type, req->userdata);
0fa8ee6c 438 if (r < 0)
80d62d4f 439 return r;
0fa8ee6c 440
80d62d4f 441 return request_call_netlink_async(link->manager->rtnl, m, req);
0fa8ee6c
YW
442}
443
d24bf1b5
YW
444static bool netdev_is_ready(NetDev *netdev) {
445 assert(netdev);
446
447 if (netdev->state != NETDEV_STATE_READY)
448 return false;
449 if (netdev->ifindex == 0)
450 return false;
451
452 return true;
453}
454
e5192864 455static int link_is_ready_to_set_link(Link *link, Request *req) {
d24bf1b5 456 int r;
0fa8ee6c 457
e5192864
YW
458 assert(link);
459 assert(link->manager);
460 assert(link->network);
0fa8ee6c
YW
461 assert(req);
462
a48ffe47 463 if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
0fa8ee6c
YW
464 return false;
465
eb93dc9b
YW
466 switch (req->type) {
467 case REQUEST_TYPE_SET_LINK_BOND:
468 case REQUEST_TYPE_SET_LINK_BRIDGE:
57aef9d7
YW
469 if (!link->master_set)
470 return false;
eb93dc9b 471
57aef9d7
YW
472 if (link->network->keep_master && link->master_ifindex <= 0)
473 return false;
474 break;
eb93dc9b
YW
475
476 case REQUEST_TYPE_SET_LINK_BRIDGE_VLAN:
440d40dc
YW
477 if (!link->master_set)
478 return false;
eb93dc9b 479
57aef9d7
YW
480 if (link->network->keep_master && link->master_ifindex <= 0 && !streq_ptr(link->kind, "bridge"))
481 return false;
eb93dc9b 482
440d40dc 483 break;
eb93dc9b
YW
484
485 case REQUEST_TYPE_SET_LINK_CAN:
baa95d22
YW
486 /* Do not check link->set_flgas_messages here, as it is ok even if link->flags
487 * is outdated, and checking the counter causes a deadlock. */
7558f9e7
YW
488 if (FLAGS_SET(link->flags, IFF_UP)) {
489 /* The CAN interface must be down to configure bitrate, etc... */
cae162a7 490 r = link_down_now(link);
e5192864
YW
491 if (r < 0)
492 return r;
7558f9e7
YW
493 }
494 break;
eb93dc9b
YW
495
496 case REQUEST_TYPE_SET_LINK_MAC:
d05c332c 497 if (req->netlink_handler == link_set_mac_handler) {
36edc2c9 498 /* This is the second attempt to set hardware address. On the first attempt
d05c332c 499 * req->netlink_handler points to link_set_mac_allow_retry_handler().
36edc2c9 500 * The first attempt failed as the interface was up. */
cae162a7 501 r = link_down_now(link);
e5192864
YW
502 if (r < 0)
503 return r;
d05c332c
YW
504 }
505 break;
eb93dc9b
YW
506
507 case REQUEST_TYPE_SET_LINK_MASTER: {
d24bf1b5 508 uint32_t m = 0;
5329a379
YW
509 Request req_mac = {
510 .link = link,
eb93dc9b 511 .type = REQUEST_TYPE_SET_LINK_MAC,
5329a379 512 };
d24bf1b5 513
d24bf1b5
YW
514 if (link->network->batadv) {
515 if (!netdev_is_ready(link->network->batadv))
516 return false;
517 m = link->network->batadv->ifindex;
518 } else if (link->network->bond) {
5329a379
YW
519 if (ordered_set_contains(link->manager->request_queue, &req_mac))
520 return false;
d24bf1b5
YW
521 if (!netdev_is_ready(link->network->bond))
522 return false;
523 m = link->network->bond->ifindex;
524
baa95d22
YW
525 /* Do not check link->set_flgas_messages here, as it is ok even if link->flags
526 * is outdated, and checking the counter causes a deadlock. */
d24bf1b5
YW
527 if (FLAGS_SET(link->flags, IFF_UP)) {
528 /* link must be down when joining to bond master. */
cae162a7 529 r = link_down_now(link);
e5192864
YW
530 if (r < 0)
531 return r;
d24bf1b5
YW
532 }
533 } else if (link->network->bridge) {
5329a379
YW
534 if (ordered_set_contains(link->manager->request_queue, &req_mac))
535 return false;
d24bf1b5
YW
536 if (!netdev_is_ready(link->network->bridge))
537 return false;
538 m = link->network->bridge->ifindex;
539 } else if (link->network->vrf) {
540 if (!netdev_is_ready(link->network->vrf))
541 return false;
542 m = link->network->vrf->ifindex;
543 }
544
545 req->userdata = UINT32_TO_PTR(m);
546 break;
547 }
eb93dc9b 548 case REQUEST_TYPE_SET_LINK_MTU: {
c3747f90
YW
549 Request req_ipoib = {
550 .link = link,
eb93dc9b 551 .type = REQUEST_TYPE_SET_LINK_IPOIB,
c3747f90
YW
552 };
553
554 return !ordered_set_contains(link->manager->request_queue, &req_ipoib);
555 }
d24bf1b5
YW
556 default:
557 break;
558 }
559
0fa8ee6c
YW
560 return true;
561}
562
eb93dc9b 563int link_process_set_link(Request *req, Link *link, void *userdata) {
0fa8ee6c
YW
564 int r;
565
566 assert(req);
eb93dc9b 567 assert(link);
9b682672 568
e5192864
YW
569 r = link_is_ready_to_set_link(link, req);
570 if (r <= 0)
571 return r;
0fa8ee6c 572
e5192864 573 r = link_configure(link, req);
0fa8ee6c 574 if (r < 0)
eb93dc9b 575 return log_link_warning_errno(link, r, "Failed to set %s", request_type_to_string(req->type));
0fa8ee6c
YW
576
577 return 1;
578}
579
580static int link_request_set_link(
581 Link *link,
eb93dc9b 582 RequestType type,
80d62d4f 583 request_netlink_handler_t netlink_handler,
0fa8ee6c
YW
584 Request **ret) {
585
586 Request *req;
587 int r;
588
589 assert(link);
0fa8ee6c
YW
590 assert(netlink_handler);
591
eb93dc9b 592 r = link_queue_request(link, type, NULL, false,
0fa8ee6c
YW
593 &link->set_link_messages, netlink_handler, &req);
594 if (r < 0)
eb93dc9b
YW
595 return log_link_warning_errno(link, r, "Failed to request to set %s: %m",
596 request_type_to_string(type));
0fa8ee6c 597
eb93dc9b 598 log_link_debug(link, "Requested to set %s", request_type_to_string(type));
0fa8ee6c
YW
599
600 if (ret)
601 *ret = req;
602 return 0;
603}
604
8e00e24c 605int link_request_to_set_addrgen_mode(Link *link) {
80f2647d 606 IPv6LinkLocalAddressGenMode mode;
8e00e24c 607 Request *req;
8e00e24c
YW
608 int r;
609
610 assert(link);
611 assert(link->network);
612
613 if (!socket_ipv6_is_supported())
614 return 0;
615
80f2647d 616 mode = link_get_ipv6ll_addrgen_mode(link);
8e00e24c 617
05b8fc49
YW
618 if (mode == link->ipv6ll_address_gen_mode)
619 return 0;
620
77d65e56
JG
621 /* If the link is already up, then changing the mode by netlink does not take effect until the
622 * link goes down. Hence, we need to reset the interface. However, setting the mode by sysctl
623 * does not need that. Let's use the sysctl interface when the link is already up.
624 * See also issue #22424. */
625 if (mode != IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE &&
626 FLAGS_SET(link->flags, IFF_UP)) {
627 r = link_set_ipv6ll_addrgen_mode(link, mode);
628 if (r < 0)
629 log_link_warning_errno(link, r, "Cannot set IPv6 address generation mode, ignoring: %m");
630
631 return 0;
632 }
8e00e24c 633
eb93dc9b
YW
634 r = link_request_set_link(link, REQUEST_TYPE_SET_LINK_ADDRESS_GENERATION_MODE,
635 link_set_addrgen_mode_handler,
636 &req);
8e00e24c
YW
637 if (r < 0)
638 return r;
639
640 req->userdata = UINT8_TO_PTR(mode);
641 return 0;
642}
643
5062b859
YW
644int link_request_to_set_bond(Link *link) {
645 assert(link);
646 assert(link->network);
647
57aef9d7
YW
648 if (!link->network->bond) {
649 Link *master;
650
651 if (!link->network->keep_master)
652 return 0;
653
654 if (link_get_master(link, &master) < 0)
655 return 0;
656
657 if (!streq_ptr(master->kind, "bond"))
658 return 0;
659 }
5062b859 660
eb93dc9b
YW
661 return link_request_set_link(link, REQUEST_TYPE_SET_LINK_BOND,
662 link_set_bond_handler, NULL);
5062b859
YW
663}
664
7d5b232f
YW
665int link_request_to_set_bridge(Link *link) {
666 assert(link);
667 assert(link->network);
668
57aef9d7
YW
669 if (!link->network->bridge) {
670 Link *master;
671
672 if (!link->network->keep_master)
673 return 0;
674
675 if (link_get_master(link, &master) < 0)
676 return 0;
677
678 if (!streq_ptr(master->kind, "bridge"))
679 return 0;
680 }
7d5b232f 681
eb93dc9b
YW
682 return link_request_set_link(link, REQUEST_TYPE_SET_LINK_BRIDGE,
683 link_set_bridge_handler,
684 NULL);
7d5b232f
YW
685}
686
8252fb44
YW
687int link_request_to_set_bridge_vlan(Link *link) {
688 assert(link);
689 assert(link->network);
690
691 if (!link->network->use_br_vlan)
692 return 0;
693
57aef9d7
YW
694 if (!link->network->bridge && !streq_ptr(link->kind, "bridge")) {
695 Link *master;
696
697 if (!link->network->keep_master)
698 return 0;
699
700 if (link_get_master(link, &master) < 0)
701 return 0;
702
703 if (!streq_ptr(master->kind, "bridge"))
704 return 0;
705 }
8252fb44 706
eb93dc9b
YW
707 return link_request_set_link(link, REQUEST_TYPE_SET_LINK_BRIDGE_VLAN,
708 link_set_bridge_vlan_handler,
709 NULL);
8252fb44
YW
710}
711
7558f9e7
YW
712int link_request_to_set_can(Link *link) {
713 assert(link);
714 assert(link->network);
715
716 if (link->iftype != ARPHRD_CAN)
717 return 0;
718
719 if (!streq_ptr(link->kind, "can"))
720 return 0;
721
eb93dc9b
YW
722 return link_request_set_link(link, REQUEST_TYPE_SET_LINK_CAN,
723 link_set_can_handler,
724 NULL);
7558f9e7
YW
725}
726
93fabc10
YW
727int link_request_to_set_flags(Link *link) {
728 assert(link);
729 assert(link->network);
730
731 if (link->network->arp < 0 &&
732 link->network->multicast < 0 &&
733 link->network->allmulticast < 0 &&
734 link->network->promiscuous < 0)
735 return 0;
736
eb93dc9b
YW
737 return link_request_set_link(link, REQUEST_TYPE_SET_LINK_FLAGS,
738 link_set_flags_handler,
739 NULL);
93fabc10
YW
740}
741
cc4c8fb1
YW
742int link_request_to_set_group(Link *link) {
743 assert(link);
744 assert(link->network);
745
10af8bb2 746 if (link->network->group < 0)
cc4c8fb1
YW
747 return 0;
748
eb93dc9b
YW
749 return link_request_set_link(link, REQUEST_TYPE_SET_LINK_GROUP,
750 link_set_group_handler,
751 NULL);
cc4c8fb1
YW
752}
753
d05c332c 754int link_request_to_set_mac(Link *link, bool allow_retry) {
a8840714
YW
755 int r;
756
a8e5e27c
YW
757 assert(link);
758 assert(link->network);
759
a8840714 760 if (link->network->hw_addr.length == 0)
a8e5e27c
YW
761 return 0;
762
a8840714 763 link->requested_hw_addr = link->network->hw_addr;
45aa0e84 764 r = net_verify_hardware_address(link->ifname, /* is_static = */ true,
a8840714
YW
765 link->iftype, &link->hw_addr, &link->requested_hw_addr);
766 if (r < 0)
767 return r;
5388e103 768
a8840714 769 if (hw_addr_equal(&link->hw_addr, &link->requested_hw_addr))
5388e103
YW
770 return 0;
771
eb93dc9b 772 return link_request_set_link(link, REQUEST_TYPE_SET_LINK_MAC,
d05c332c
YW
773 allow_retry ? link_set_mac_allow_retry_handler : link_set_mac_handler,
774 NULL);
a8e5e27c
YW
775}
776
72e65e6f
YW
777int link_request_to_set_ipoib(Link *link) {
778 assert(link);
779 assert(link->network);
780
781 if (link->iftype != ARPHRD_INFINIBAND)
782 return 0;
783
784 if (link->network->ipoib_mode < 0 &&
785 link->network->ipoib_umcast < 0)
786 return 0;
787
eb93dc9b
YW
788 return link_request_set_link(link, REQUEST_TYPE_SET_LINK_IPOIB,
789 link_set_ipoib_handler,
790 NULL);
72e65e6f
YW
791}
792
d24bf1b5
YW
793int link_request_to_set_master(Link *link) {
794 assert(link);
c347a982 795 assert(link->network);
d24bf1b5 796
57aef9d7
YW
797 if (link->network->keep_master) {
798 link->master_set = true;
799 return 0;
800 }
801
440d40dc
YW
802 link->master_set = false;
803
c347a982 804 if (link->network->batadv || link->network->bond || link->network->bridge || link->network->vrf)
eb93dc9b
YW
805 return link_request_set_link(link, REQUEST_TYPE_SET_LINK_MASTER,
806 link_set_master_handler,
807 NULL);
c347a982 808 else
eb93dc9b
YW
809 return link_request_set_link(link, REQUEST_TYPE_SET_LINK_MASTER,
810 link_unset_master_handler,
811 NULL);
d24bf1b5
YW
812}
813
0fa8ee6c 814int link_request_to_set_mtu(Link *link, uint32_t mtu) {
717ba5fc
YW
815 const char *origin;
816 uint32_t min_mtu;
eb93dc9b 817 Request *req;
0fa8ee6c
YW
818 int r;
819
820 assert(link);
717ba5fc
YW
821 assert(link->network);
822
823 min_mtu = link->min_mtu;
824 origin = "the minimum MTU of the interface";
825 if (link_ipv6_enabled(link)) {
826 /* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes on the interface. Bump up
827 * MTU bytes to IPV6_MTU_MIN. */
828 if (min_mtu < IPV6_MIN_MTU) {
829 min_mtu = IPV6_MIN_MTU;
830 origin = "the minimum IPv6 MTU";
831 }
832 if (min_mtu < link->network->ipv6_mtu) {
833 min_mtu = link->network->ipv6_mtu;
834 origin = "the requested IPv6 MTU in IPv6MTUBytes=";
835 }
836 }
837
838 if (mtu < min_mtu) {
839 log_link_warning(link, "Bumping the requested MTU %"PRIu32" to %s (%"PRIu32")",
840 mtu, origin, min_mtu);
841 mtu = min_mtu;
842 }
0fa8ee6c 843
717ba5fc
YW
844 if (mtu > link->max_mtu) {
845 log_link_warning(link, "Reducing the requested MTU %"PRIu32" to the interface's maximum MTU %"PRIu32".",
846 mtu, link->max_mtu);
847 mtu = link->max_mtu;
0fa8ee6c
YW
848 }
849
850 if (link->mtu == mtu)
851 return 0;
852
eb93dc9b
YW
853 r = link_request_set_link(link, REQUEST_TYPE_SET_LINK_MTU,
854 link_set_mtu_handler,
855 &req);
0fa8ee6c
YW
856 if (r < 0)
857 return r;
858
859 req->userdata = UINT32_TO_PTR(mtu);
860 return 0;
861}
862
863static bool link_reduces_vlan_mtu(Link *link) {
864 /* See netif_reduces_vlan_mtu() in kernel. */
865 return streq_ptr(link->kind, "macsec");
866}
867
868static uint32_t link_get_requested_mtu_by_stacked_netdevs(Link *link) {
869 uint32_t mtu = 0;
870 NetDev *dev;
871
872 HASHMAP_FOREACH(dev, link->network->stacked_netdevs)
873 if (dev->kind == NETDEV_KIND_VLAN && dev->mtu > 0)
874 /* See vlan_dev_change_mtu() in kernel. */
875 mtu = MAX(mtu, link_reduces_vlan_mtu(link) ? dev->mtu + 4 : dev->mtu);
876
877 else if (dev->kind == NETDEV_KIND_MACVLAN && dev->mtu > mtu)
878 /* See macvlan_change_mtu() in kernel. */
879 mtu = dev->mtu;
880
881 return mtu;
882}
883
884int link_configure_mtu(Link *link) {
885 uint32_t mtu;
886
887 assert(link);
888 assert(link->network);
889
890 if (link->network->mtu > 0)
891 return link_request_to_set_mtu(link, link->network->mtu);
892
893 mtu = link_get_requested_mtu_by_stacked_netdevs(link);
894 if (link->mtu >= mtu)
895 return 0;
896
897 log_link_notice(link, "Bumping MTU bytes from %"PRIu32" to %"PRIu32" because of stacked device. "
898 "If it is not desired, then please explicitly specify MTUBytes= setting.",
899 link->mtu, mtu);
900
901 return link_request_to_set_mtu(link, mtu);
902}
112a0972 903
b1d9c504
YW
904static int link_up_dsa_slave(Link *link) {
905 Link *master;
906 int r;
907
908 assert(link);
909
910 /* For older kernels (specifically, older than 9d5ef190e5615a7b63af89f88c4106a5bc127974, kernel-5.12),
911 * it is necessary to bring up a DSA slave that its master interface is already up. And bringing up
912 * the slave fails with -ENETDOWN. So, let's bring up the master even if it is not managed by us,
913 * and try to bring up the slave after the master becomes up. */
914
915 if (link->dsa_master_ifindex <= 0)
916 return 0;
917
918 if (!streq_ptr(link->driver, "dsa"))
919 return 0;
920
921 if (link_get_by_index(link->manager, link->dsa_master_ifindex, &master) < 0)
922 return 0;
923
924 if (master->state == LINK_STATE_UNMANAGED) {
925 /* If the DSA master interface is unmanaged, then it will never become up.
926 * Let's request to bring up the master. */
927 r = link_request_to_bring_up_or_down(master, /* up = */ true);
928 if (r < 0)
929 return r;
930 }
931
932 r = link_request_to_bring_up_or_down(link, /* up = */ true);
933 if (r < 0)
934 return r;
935
936 return 1;
937}
938
80d62d4f
YW
939static int link_up_or_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
940 bool on_activate, up;
112a0972
YW
941 int r;
942
943 assert(m);
80d62d4f 944 assert(req);
112a0972
YW
945 assert(link);
946
80d62d4f
YW
947 on_activate = req->type == REQUEST_TYPE_ACTIVATE_LINK;
948 up = PTR_TO_INT(req->userdata);
112a0972
YW
949
950 r = sd_netlink_message_get_errno(m);
b1d9c504
YW
951 if (r == -ENETDOWN && up && link_up_dsa_slave(link) > 0)
952 log_link_message_debug_errno(link, m, r, "Could not bring up dsa slave, retrying again after dsa master becomes up");
953 else if (r < 0) {
54cd4bb7
YW
954 const char *error_msg;
955
956 error_msg = up ?
957 (on_activate ? "Could not bring up interface" : "Could not bring up interface, ignoring") :
958 (on_activate ? "Could not bring down interface" : "Could not bring down interface, ignoring");
959
960 log_link_message_warning_errno(link, m, r, error_msg);
961 if (on_activate)
80d62d4f 962 return 0;
54cd4bb7 963 }
112a0972 964
baa95d22
YW
965 r = link_call_getlink(link, get_link_update_flag_handler);
966 if (r < 0) {
967 link_enter_failed(link);
80d62d4f 968 return 0;
baa95d22
YW
969 }
970
80d62d4f
YW
971 link->set_flags_messages++;
972
54cd4bb7 973 if (on_activate) {
112a0972
YW
974 link->activated = true;
975 link_check_ready(link);
976 }
977
978 return 0;
979}
980
68f52063
YW
981static const char *up_or_down(bool up) {
982 return up ? "up" : "down";
983}
984
54ff39f7
YW
985static int link_up_or_down(Link *link, bool up, Request *req) {
986 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
112a0972
YW
987 int r;
988
989 assert(link);
990 assert(link->manager);
991 assert(link->manager->rtnl);
54ff39f7 992 assert(req);
112a0972 993
68f52063 994 log_link_debug(link, "Bringing link %s", up_or_down(up));
112a0972 995
54ff39f7 996 r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_SETLINK, link->ifindex);
112a0972 997 if (r < 0)
a79a8d16 998 return r;
112a0972 999
54ff39f7 1000 r = sd_rtnl_message_link_set_flags(m, up ? IFF_UP : 0, IFF_UP);
112a0972 1001 if (r < 0)
a79a8d16 1002 return r;
112a0972 1003
80d62d4f 1004 return request_call_netlink_async(link->manager->rtnl, m, req);
112a0972
YW
1005}
1006
112a0972
YW
1007static bool link_is_ready_to_activate(Link *link) {
1008 assert(link);
1009
a48ffe47 1010 if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
112a0972
YW
1011 return false;
1012
1013 if (link->set_link_messages > 0)
1014 return false;
1015
1016 return true;
1017}
1018
ff51134c
YW
1019int link_process_activation(Request *req, Link *link, void *userdata) {
1020 bool up = PTR_TO_INT(userdata);
112a0972
YW
1021 int r;
1022
1023 assert(req);
ff51134c 1024 assert(link);
112a0972
YW
1025
1026 if (!link_is_ready_to_activate(link))
1027 return 0;
1028
54ff39f7 1029 r = link_up_or_down(link, up, req);
112a0972 1030 if (r < 0)
a79a8d16 1031 return log_link_warning_errno(link, r, "Failed to activate link: %m");
112a0972
YW
1032
1033 return 1;
1034}
1035
1036int link_request_to_activate(Link *link) {
1037 Request *req;
1038 bool up;
1039 int r;
1040
1041 assert(link);
1042 assert(link->network);
1043
1044 switch (link->network->activation_policy) {
1045 case ACTIVATION_POLICY_BOUND:
112a0972
YW
1046 r = link_handle_bound_to_list(link);
1047 if (r < 0)
1048 return r;
1049 _fallthrough_;
1050 case ACTIVATION_POLICY_MANUAL:
1051 link->activated = true;
1052 link_check_ready(link);
1053 return 0;
1054 case ACTIVATION_POLICY_UP:
1055 case ACTIVATION_POLICY_ALWAYS_UP:
1056 up = true;
1057 break;
1058 case ACTIVATION_POLICY_DOWN:
1059 case ACTIVATION_POLICY_ALWAYS_DOWN:
1060 up = false;
1061 break;
1062 default:
04499a70 1063 assert_not_reached();
112a0972
YW
1064 }
1065
1066 link->activated = false;
1067
baa95d22 1068 r = link_queue_request(link, REQUEST_TYPE_ACTIVATE_LINK, NULL, false, &link->set_flags_messages,
80d62d4f 1069 link_up_or_down_handler, &req);
112a0972
YW
1070 if (r < 0)
1071 return log_link_error_errno(link, r, "Failed to request to activate link: %m");
1072
1073 req->userdata = INT_TO_PTR(up);
1074
1075 log_link_debug(link, "Requested to activate link");
1076 return 0;
1077}
68f52063 1078
b1d9c504 1079static bool link_is_ready_to_bring_up_or_down(Link *link, bool up) {
68f52063
YW
1080 assert(link);
1081
b1d9c504
YW
1082 if (up && link->dsa_master_ifindex > 0) {
1083 Link *master;
1084
3e7bf853 1085 /* The master interface must be up. See comments in link_up_dsa_slave(). */
b1d9c504
YW
1086
1087 if (link_get_by_index(link->manager, link->dsa_master_ifindex, &master) < 0)
1088 return false;
1089
1090 if (!FLAGS_SET(master->flags, IFF_UP))
1091 return false;
1092 }
1093
68f52063
YW
1094 if (link->state == LINK_STATE_UNMANAGED)
1095 return true;
1096
1097 if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
1098 return false;
1099
1100 if (link->set_link_messages > 0)
1101 return false;
1102
1103 if (!link->activated)
1104 return false;
1105
1106 return true;
1107}
1108
ff51134c
YW
1109int link_process_up_or_down(Request *req, Link *link, void *userdata) {
1110 bool up = PTR_TO_INT(userdata);
68f52063
YW
1111 int r;
1112
1113 assert(req);
ff51134c 1114 assert(link);
68f52063 1115
b1d9c504 1116 if (!link_is_ready_to_bring_up_or_down(link, up))
68f52063
YW
1117 return 0;
1118
54ff39f7 1119 r = link_up_or_down(link, up, req);
68f52063 1120 if (r < 0)
a79a8d16 1121 return log_link_warning_errno(link, r, "Failed to bring link %s: %m", up_or_down(up));
68f52063
YW
1122
1123 return 1;
1124}
1125
1126int link_request_to_bring_up_or_down(Link *link, bool up) {
1127 Request *req;
1128 int r;
1129
1130 assert(link);
1131
baa95d22 1132 r = link_queue_request(link, REQUEST_TYPE_UP_DOWN, NULL, false, &link->set_flags_messages,
80d62d4f 1133 link_up_or_down_handler, &req);
68f52063 1134 if (r < 0)
a79a8d16
YW
1135 return log_link_warning_errno(link, r, "Failed to request to bring link %s: %m",
1136 up_or_down(up));
68f52063
YW
1137
1138 req->userdata = INT_TO_PTR(up);
1139
1140 log_link_debug(link, "Requested to bring link %s", up_or_down(up));
1141 return 0;
1142}
63dc6025 1143
cae162a7
YW
1144static int link_down_now_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
1145 int r;
1146
1147 assert(m);
1148 assert(link);
1149 assert(link->set_flags_messages > 0);
1150
1151 link->set_flags_messages--;
1152
1153 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1154 return 0;
1155
1156 r = sd_netlink_message_get_errno(m);
1157 if (r < 0)
1158 log_link_message_warning_errno(link, m, r, "Could not bring down interface, ignoring");
1159
1160 r = link_call_getlink(link, get_link_update_flag_handler);
1161 if (r < 0) {
1162 link_enter_failed(link);
1163 return 0;
1164 }
1165
1166 link->set_flags_messages++;
1167 return 0;
1168}
1169
1170int link_down_now(Link *link) {
1171 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
1172 int r;
1173
1174 assert(link);
1175 assert(link->manager);
1176 assert(link->manager->rtnl);
1177
1178 log_link_debug(link, "Bringing link down");
1179
1180 r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
1181 if (r < 0)
1182 return log_link_warning_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
1183
1184 r = sd_rtnl_message_link_set_flags(req, 0, IFF_UP);
1185 if (r < 0)
1186 return log_link_warning_errno(link, r, "Could not set link flags: %m");
1187
1188 r = netlink_call_async(link->manager->rtnl, NULL, req, link_down_now_handler,
1189 link_netlink_destroy_callback, link);
1190 if (r < 0)
1191 return log_link_warning_errno(link, r, "Could not send rtnetlink message: %m");
1192
1193 link->set_flags_messages++;
1194 link_ref(link);
1195 return 0;
1196}
1197
63dc6025
YW
1198static int link_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
1199 int r;
1200
1201 assert(m);
1202 assert(link);
1203
1204 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1205 return 0;
1206
1207 r = sd_netlink_message_get_errno(m);
1208 if (r < 0)
1209 log_link_message_warning_errno(link, m, r, "Could not remove interface, ignoring");
1210
1211 return 0;
1212}
1213
1214int link_remove(Link *link) {
1215 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
1216 int r;
1217
1218 assert(link);
1219 assert(link->manager);
1220 assert(link->manager->rtnl);
1221
1222 log_link_debug(link, "Removing link.");
1223
1224 r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_DELLINK, link->ifindex);
1225 if (r < 0)
1226 return log_link_debug_errno(link, r, "Could not allocate RTM_DELLINK message: %m");
1227
1228 r = netlink_call_async(link->manager->rtnl, NULL, req, link_remove_handler,
1229 link_netlink_destroy_callback, link);
1230 if (r < 0)
1231 return log_link_debug_errno(link, r, "Could not send rtnetlink message: %m");
1232
1233 link_ref(link);
1234
1235 return 0;
1236}