]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link.c
shared: add minimal firewall manipulation helpers for establishing NAT rules, using...
[thirdparty/systemd.git] / src / network / networkd-link.c
CommitLineData
f579559b
TG
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <netinet/ether.h>
23#include <linux/if.h>
4cc7a82c 24#include <unistd.h>
f579559b 25
0b1831c2 26#include "networkd-link.h"
3be1d7e0 27#include "networkd-netdev.h"
f579559b 28#include "libudev-private.h"
505f8da7 29#include "udev-util.h"
f579559b 30#include "util.h"
505f8da7 31#include "virt.h"
1346b1f0 32#include "bus-util.h"
c6f7c917 33#include "network-internal.h"
ed942a9e 34#include "conf-parser.h"
f579559b 35
fe8db0c5
TG
36#include "dhcp-lease-internal.h"
37
78c958f8
TG
38static bool link_dhcp6_enabled(Link *link) {
39 if (link->flags & IFF_LOOPBACK)
40 return false;
41
42 if (!link->network)
43 return false;
44
45 return IN_SET(link->network->dhcp, DHCP_SUPPORT_V6, DHCP_SUPPORT_BOTH);
46}
47
48static bool link_dhcp4_enabled(Link *link) {
49 if (link->flags & IFF_LOOPBACK)
50 return false;
51
52 if (!link->network)
53 return false;
54
55 return IN_SET(link->network->dhcp, DHCP_SUPPORT_V4, DHCP_SUPPORT_BOTH);
56}
57
58static bool link_dhcp4_server_enabled(Link *link) {
59 if (link->flags & IFF_LOOPBACK)
60 return false;
61
62 if (!link->network)
63 return false;
64
65 return link->network->dhcp_server;
66}
67
68static bool link_ipv4ll_enabled(Link *link) {
69 if (link->flags & IFF_LOOPBACK)
70 return false;
71
72 if (!link->network)
73 return false;
74
75 return link->network->ipv4ll;
76}
77
ce43e484
SS
78static bool link_lldp_enabled(Link *link) {
79 if (link->flags & IFF_LOOPBACK)
80 return false;
81
82 if (!link->network)
83 return false;
84
85 if(link->network->bridge)
86 return false;
87
88 return link->network->lldp;
89}
90
51d18171
TG
91#define FLAG_STRING(string, flag, old, new) \
92 (((old ^ new) & flag) \
93 ? ((old & flag) ? (" -" string) : (" +" string)) \
94 : "")
95
96static int link_update_flags(Link *link, sd_rtnl_message *m) {
97 unsigned flags, unknown_flags_added, unknown_flags_removed, unknown_flags;
98 uint8_t operstate;
99 int r;
100
101 assert(link);
102
103 r = sd_rtnl_message_link_get_flags(m, &flags);
104 if (r < 0) {
79008bdd 105 log_link_warning(link, "Could not get link flags");
51d18171
TG
106 return r;
107 }
108
109 r = sd_rtnl_message_read_u8(m, IFLA_OPERSTATE, &operstate);
110 if (r < 0)
111 /* if we got a message without operstate, take it to mean
112 the state was unchanged */
113 operstate = link->kernel_operstate;
114
115 if ((link->flags == flags) && (link->kernel_operstate == operstate))
116 return 0;
117
118 if (link->flags != flags) {
79008bdd 119 log_link_debug(link, "flags change:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
51d18171
TG
120 FLAG_STRING("LOOPBACK", IFF_LOOPBACK, link->flags, flags),
121 FLAG_STRING("MASTER", IFF_MASTER, link->flags, flags),
122 FLAG_STRING("SLAVE", IFF_SLAVE, link->flags, flags),
123 FLAG_STRING("UP", IFF_UP, link->flags, flags),
124 FLAG_STRING("DORMANT", IFF_DORMANT, link->flags, flags),
125 FLAG_STRING("LOWER_UP", IFF_LOWER_UP, link->flags, flags),
126 FLAG_STRING("RUNNING", IFF_RUNNING, link->flags, flags),
127 FLAG_STRING("MULTICAST", IFF_MULTICAST, link->flags, flags),
128 FLAG_STRING("BROADCAST", IFF_BROADCAST, link->flags, flags),
129 FLAG_STRING("POINTOPOINT", IFF_POINTOPOINT, link->flags, flags),
130 FLAG_STRING("PROMISC", IFF_PROMISC, link->flags, flags),
131 FLAG_STRING("ALLMULTI", IFF_ALLMULTI, link->flags, flags),
132 FLAG_STRING("PORTSEL", IFF_PORTSEL, link->flags, flags),
133 FLAG_STRING("AUTOMEDIA", IFF_AUTOMEDIA, link->flags, flags),
134 FLAG_STRING("DYNAMIC", IFF_DYNAMIC, link->flags, flags),
135 FLAG_STRING("NOARP", IFF_NOARP, link->flags, flags),
136 FLAG_STRING("NOTRAILERS", IFF_NOTRAILERS, link->flags, flags),
137 FLAG_STRING("DEBUG", IFF_DEBUG, link->flags, flags),
138 FLAG_STRING("ECHO", IFF_ECHO, link->flags, flags));
139
140 unknown_flags = ~(IFF_LOOPBACK | IFF_MASTER | IFF_SLAVE | IFF_UP |
141 IFF_DORMANT | IFF_LOWER_UP | IFF_RUNNING |
142 IFF_MULTICAST | IFF_BROADCAST | IFF_POINTOPOINT |
143 IFF_PROMISC | IFF_ALLMULTI | IFF_PORTSEL |
144 IFF_AUTOMEDIA | IFF_DYNAMIC | IFF_NOARP |
145 IFF_NOTRAILERS | IFF_DEBUG | IFF_ECHO);
146 unknown_flags_added = ((link->flags ^ flags) & flags & unknown_flags);
147 unknown_flags_removed = ((link->flags ^ flags) & link->flags & unknown_flags);
148
149 /* link flags are currently at most 18 bits, let's align to
150 * printing 20 */
151 if (unknown_flags_added)
79008bdd 152 log_link_debug(link,
51d18171
TG
153 "unknown link flags gained: %#.5x (ignoring)",
154 unknown_flags_added);
155
156 if (unknown_flags_removed)
79008bdd 157 log_link_debug(link,
51d18171
TG
158 "unknown link flags lost: %#.5x (ignoring)",
159 unknown_flags_removed);
160 }
161
162 link->flags = flags;
163 link->kernel_operstate = operstate;
164
165 link_save(link);
166
167 return 0;
168}
169
505f8da7 170static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
14b746f7 171 _cleanup_link_unref_ Link *link = NULL;
505f8da7 172 uint16_t type;
ca4e095a 173 const char *ifname;
505f8da7 174 int r, ifindex;
f579559b 175
0c2f9b84 176 assert(manager);
505f8da7 177 assert(message);
f579559b
TG
178 assert(ret);
179
505f8da7
TG
180 r = sd_rtnl_message_get_type(message, &type);
181 if (r < 0)
182 return r;
183 else if (type != RTM_NEWLINK)
184 return -EINVAL;
185
186 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
187 if (r < 0)
188 return r;
189 else if (ifindex <= 0)
190 return -EINVAL;
191
192 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &ifname);
193 if (r < 0)
194 return r;
195
f579559b
TG
196 link = new0(Link, 1);
197 if (!link)
198 return -ENOMEM;
199
14b746f7 200 link->n_ref = 1;
5a3eb5a7 201 link->manager = manager;
8434fd5c 202 link->state = LINK_STATE_PENDING;
505f8da7
TG
203 link->ifindex = ifindex;
204 link->ifname = strdup(ifname);
205 if (!link->ifname)
206 return -ENOMEM;
f579559b 207
512922f8
TG
208 r = sd_rtnl_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
209 if (r < 0)
79008bdd 210 log_link_debug(link, "MAC address not found for new device, continuing without");
512922f8 211
3c9b8860
TG
212 r = asprintf(&link->state_file, "/run/systemd/netif/links/%d",
213 link->ifindex);
fe8db0c5 214 if (r < 0)
315db1a8 215 return -ENOMEM;
fe8db0c5 216
3c9b8860
TG
217 r = asprintf(&link->lease_file, "/run/systemd/netif/leases/%d",
218 link->ifindex);
68a8723c
TG
219 if (r < 0)
220 return -ENOMEM;
221
49699bac
SS
222 r = asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d",
223 link->ifindex);
224 if (r < 0)
225 return -ENOMEM;
226
227
d5099efc 228 r = hashmap_ensure_allocated(&manager->links, NULL);
ae06ab10
TG
229 if (r < 0)
230 return r;
231
232 r = hashmap_put(manager->links, INT_TO_PTR(link->ifindex), link);
f579559b
TG
233 if (r < 0)
234 return r;
235
51d18171
TG
236 r = link_update_flags(link, message);
237 if (r < 0)
238 return r;
239
f579559b
TG
240 *ret = link;
241 link = NULL;
242
243 return 0;
244}
245
14b746f7 246static void link_free(Link *link) {
428fd0a7
TG
247 Address *address;
248
f579559b
TG
249 if (!link)
250 return;
251
428fd0a7
TG
252 while ((address = link->addresses)) {
253 LIST_REMOVE(addresses, link->addresses, address);
254 address_free(address);
255 }
256
11bf3cce
LP
257 while ((address = link->pool_addresses)) {
258 LIST_REMOVE(addresses, link->pool_addresses, address);
259 address_free(address);
260 }
261
bfcdba8d 262 sd_dhcp_server_unref(link->dhcp_server);
e5b04c8d 263 sd_dhcp_client_unref(link->dhcp_client);
a6cc569e 264 sd_dhcp_lease_unref(link->dhcp_lease);
f5be5601 265
68a8723c
TG
266 unlink(link->lease_file);
267 free(link->lease_file);
268
49699bac
SS
269 unlink(link->lldp_file);
270 free(link->lldp_file);
271
56cd007a 272 sd_ipv4ll_unref(link->ipv4ll);
4138fb2c 273 sd_dhcp6_client_unref(link->dhcp6_client);
6b66097b 274 sd_icmp6_nd_unref(link->icmp6_router_discovery);
4138fb2c 275
28aeb07f 276 if (link->manager)
ae06ab10 277 hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex));
f579559b 278
c166a070 279 free(link->ifname);
68a8723c
TG
280
281 unlink(link->state_file);
fe8db0c5 282 free(link->state_file);
c166a070 283
b5db00e5
UTL
284 udev_device_unref(link->udev_device);
285
f579559b
TG
286 free(link);
287}
288
14b746f7
TG
289Link *link_unref(Link *link) {
290 if (link && (-- link->n_ref <= 0))
291 link_free(link);
292
293 return NULL;
294}
295
296Link *link_ref(Link *link) {
297 if (link)
298 assert_se(++ link->n_ref >= 2);
299
300 return link;
301}
302
11a7f229
TG
303int link_get(Manager *m, int ifindex, Link **ret) {
304 Link *link;
11a7f229
TG
305
306 assert(m);
11a7f229
TG
307 assert(ifindex);
308 assert(ret);
309
ae06ab10 310 link = hashmap_get(m->links, INT_TO_PTR(ifindex));
11a7f229
TG
311 if (!link)
312 return -ENODEV;
313
314 *ret = link;
315
316 return 0;
317}
318
370e9930
TG
319void link_drop(Link *link) {
320 if (!link || link->state == LINK_STATE_LINGER)
321 return;
322
323 link->state = LINK_STATE_LINGER;
324
79008bdd 325 log_link_debug(link, "link removed");
370e9930
TG
326
327 link_unref(link);
328
329 return;
330}
331
57bd6899
TG
332static void link_enter_unmanaged(Link *link) {
333 assert(link);
334
79008bdd 335 log_link_debug(link, "unmanaged");
57bd6899
TG
336
337 link->state = LINK_STATE_UNMANAGED;
338
339 link_save(link);
340}
341
111bb8f9
TG
342static int link_stop_clients(Link *link) {
343 int r = 0, k;
344
345 assert(link);
346 assert(link->manager);
347 assert(link->manager->event);
348
349 if (!link->network)
350 return 0;
351
ba179154 352 if (link->dhcp_client) {
111bb8f9
TG
353 k = sd_dhcp_client_stop(link->dhcp_client);
354 if (k < 0) {
79008bdd 355 log_link_warning(link, "Could not stop DHCPv4 client: %s",
3c9b8860 356 strerror(-r));
111bb8f9
TG
357 r = k;
358 }
359 }
360
ba179154 361 if (link->ipv4ll) {
111bb8f9
TG
362 k = sd_ipv4ll_stop(link->ipv4ll);
363 if (k < 0) {
79008bdd 364 log_link_warning(link, "Could not stop IPv4 link-local: %s",
3c9b8860 365 strerror(-r));
111bb8f9 366 r = k;
dd43110f
TG
367 }
368 }
369
ba179154 370 if(link->icmp6_router_discovery) {
1873a3d3
PF
371
372 if (link->dhcp6_client) {
373 k = sd_dhcp6_client_stop(link->dhcp6_client);
374 if (k < 0) {
79008bdd 375 log_link_warning(link, "Could not stop DHCPv6 client: %s",
3c9b8860 376 strerror(-r));
1873a3d3
PF
377 r = k;
378 }
379 }
4138fb2c 380
1873a3d3 381 k = sd_icmp6_nd_stop(link->icmp6_router_discovery);
4138fb2c 382 if (k < 0) {
79008bdd 383 log_link_warning(link,
3c9b8860
TG
384 "Could not stop ICMPv6 router discovery: %s",
385 strerror(-r));
4138fb2c
PF
386 r = k;
387 }
388 }
389
ce43e484
SS
390 if (link->lldp) {
391
392 k = sd_lldp_stop(link->lldp);
393 if (k < 0) {
394 log_link_warning(link, "Could not stop LLDP : %s",
395 strerror(-r));
396 r = k;
397 }
398 }
399
111bb8f9
TG
400 return r;
401}
402
b22d8a00 403void link_enter_failed(Link *link) {
ef1ba606 404 assert(link);
f882c247 405
370e9930 406 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
2139694e
TG
407 return;
408
79008bdd 409 log_link_warning(link, "failed");
449f7554 410
ef1ba606 411 link->state = LINK_STATE_FAILED;
fe8db0c5 412
111bb8f9
TG
413 link_stop_clients(link);
414
fe8db0c5 415 link_save(link);
f882c247
TG
416}
417
4f434938
LP
418static Address* link_find_dhcp_server_address(Link *link) {
419 Address *address;
420
421 assert(link);
422 assert(link->network);
423
424 /* The the first statically configured address if there is any */
425 LIST_FOREACH(addresses, address, link->network->static_addresses) {
426
427 if (address->family != AF_INET)
428 continue;
429
af93291c 430 if (in_addr_is_null(address->family, &address->in_addr))
4f434938
LP
431 continue;
432
433 return address;
434 }
435
436 /* If that didn't work, find a suitable address we got from the pool */
437 LIST_FOREACH(addresses, address, link->pool_addresses) {
438 if (address->family != AF_INET)
439 continue;
440
441 return address;
442 }
443
444 return NULL;
445}
446
dd43110f
TG
447static int link_enter_configured(Link *link) {
448 int r;
449
450 assert(link);
451 assert(link->network);
452 assert(link->state == LINK_STATE_SETTING_ROUTES);
453
78c958f8 454 if (link_dhcp4_server_enabled(link) &&
7c16313f 455 !sd_dhcp_server_is_running(link->dhcp_server)) {
4f434938
LP
456 struct in_addr pool_start;
457 Address *address;
458
459 address = link_find_dhcp_server_address(link);
460 if (!address) {
79008bdd 461 log_link_warning(link,
3c9b8860 462 "Failed to find suitable address for DHCPv4 server instance.");
4f434938
LP
463 link_enter_failed(link);
464 return 0;
465 }
466
79008bdd 467 log_link_debug(link, "offering DHCPv4 leases");
dd43110f 468
3c9b8860
TG
469 r = sd_dhcp_server_set_address(link->dhcp_server,
470 &address->in_addr.in,
471 address->prefixlen);
4f434938
LP
472 if (r < 0)
473 return r;
474
475 /* offer 32 addresses starting from the address following the server address */
476 pool_start.s_addr = htobe32(be32toh(address->in_addr.in.s_addr) + 1);
477 r = sd_dhcp_server_set_lease_pool(link->dhcp_server,
478 &pool_start, 32);
479 if (r < 0)
480 return r;
481
482 /* TODO:
483 r = sd_dhcp_server_set_router(link->dhcp_server,
484 &main_address->in_addr.in);
485 if (r < 0)
486 return r;
487
488 r = sd_dhcp_server_set_prefixlen(link->dhcp_server,
489 main_address->prefixlen);
490 if (r < 0)
491 return r;
492 */
493
dd43110f
TG
494 r = sd_dhcp_server_start(link->dhcp_server);
495 if (r < 0) {
79008bdd 496 log_link_warning(link, "could not start DHCPv4 server "
dd43110f
TG
497 "instance: %s", strerror(-r));
498
499 link_enter_failed(link);
500
501 return 0;
502 }
503 }
504
79008bdd 505 log_link_info(link, "link configured");
dd43110f
TG
506
507 link->state = LINK_STATE_CONFIGURED;
508
509 link_save(link);
510
511 return 0;
512}
513
3c9b8860
TG
514void link_client_handler(Link *link) {
515 assert(link);
516 assert(link->network);
517
518 if (!link->static_configured)
519 return;
520
78c958f8 521 if (link_ipv4ll_enabled(link))
3c9b8860
TG
522 if (!link->ipv4ll_address ||
523 !link->ipv4ll_route)
524 return;
525
78c958f8 526 if (link_dhcp4_enabled(link) && !link->dhcp4_configured)
3c9b8860
TG
527 return;
528
9fdaa992
TG
529 if (link->state != LINK_STATE_CONFIGURED)
530 link_enter_configured(link);
3c9b8860
TG
531
532 return;
533}
534
f882c247 535static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 536 _cleanup_link_unref_ Link *link = userdata;
f882c247
TG
537 int r;
538
3c9b8860 539 assert(link->link_messages > 0);
370e9930
TG
540 assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
541 LINK_STATE_SETTING_ROUTES, LINK_STATE_FAILED,
542 LINK_STATE_LINGER));
f882c247 543
3c9b8860 544 link->link_messages --;
f882c247 545
77a008c0 546 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
f882c247
TG
547 return 1;
548
549 r = sd_rtnl_message_get_errno(m);
c166a070 550 if (r < 0 && r != -EEXIST)
6c861f0a 551 log_link_warning_errno(link, -r, "%-*s: could not set route: %m", IFNAMSIZ, link->ifname);
f882c247 552
3c9b8860 553 if (link->link_messages == 0) {
79008bdd 554 log_link_debug(link, "routes set");
3c9b8860
TG
555 link->static_configured = true;
556 link_client_handler(link);
dd3efc09 557 }
f882c247
TG
558
559 return 1;
560}
561
562static int link_enter_set_routes(Link *link) {
a6cc569e 563 Route *rt;
f882c247
TG
564 int r;
565
566 assert(link);
567 assert(link->network);
ef1ba606 568 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
f882c247 569
ef1ba606 570 link->state = LINK_STATE_SETTING_ROUTES;
f882c247 571
3d3d4255 572 LIST_FOREACH(routes, rt, link->network->static_routes) {
a6cc569e 573 r = route_configure(rt, link, &route_handler);
dd3efc09 574 if (r < 0) {
79008bdd 575 log_link_warning(link,
3c9b8860 576 "could not set routes: %s",
b1666580 577 strerror(-r));
3c9b8860 578 link_enter_failed(link);
a6cc569e
TG
579 return r;
580 }
581
3c9b8860 582 link->link_messages ++;
8ddbeaa2 583 }
f5be5601 584
3c9b8860
TG
585 if (link->link_messages == 0) {
586 link->static_configured = true;
587 link_client_handler(link);
431ca2ce 588 } else
79008bdd 589 log_link_debug(link, "setting routes");
f882c247
TG
590
591 return 0;
592}
593
b22d8a00 594int link_route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 595 _cleanup_link_unref_ Link *link = userdata;
5c1d3fc9
UTL
596 int r;
597
598 assert(m);
599 assert(link);
600 assert(link->ifname);
601
5da8149f 602 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
5c1d3fc9
UTL
603 return 1;
604
605 r = sd_rtnl_message_get_errno(m);
b90b025a 606 if (r < 0 && r != -ESRCH)
6c861f0a 607 log_link_warning_errno(link, -r, "%-*s: could not drop route: %m", IFNAMSIZ, link->ifname);
5c1d3fc9 608
5bdd314c 609 return 1;
5c1d3fc9
UTL
610}
611
f882c247 612static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 613 _cleanup_link_unref_ Link *link = userdata;
f882c247
TG
614 int r;
615
4958aee4 616 assert(rtnl);
f5be5601
TG
617 assert(m);
618 assert(link);
619 assert(link->ifname);
3c9b8860 620 assert(link->link_messages > 0);
370e9930
TG
621 assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
622 LINK_STATE_FAILED, LINK_STATE_LINGER));
f882c247 623
3c9b8860 624 link->link_messages --;
f882c247 625
5da8149f 626 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
f882c247
TG
627 return 1;
628
629 r = sd_rtnl_message_get_errno(m);
c166a070 630 if (r < 0 && r != -EEXIST)
6c861f0a 631 log_link_warning_errno(link, -r, "%-*s: could not set address: %m", IFNAMSIZ, link->ifname);
45af44d4
TG
632 else if (r >= 0)
633 link_rtnl_process_address(rtnl, m, link->manager);
f882c247 634
3c9b8860 635 if (link->link_messages == 0) {
79008bdd 636 log_link_debug(link, "addresses set");
ef1ba606 637 link_enter_set_routes(link);
dd3efc09 638 }
f882c247
TG
639
640 return 1;
641}
642
643static int link_enter_set_addresses(Link *link) {
a6cc569e 644 Address *ad;
f882c247
TG
645 int r;
646
647 assert(link);
648 assert(link->network);
f5be5601 649 assert(link->state != _LINK_STATE_INVALID);
f882c247 650
ef1ba606 651 link->state = LINK_STATE_SETTING_ADDRESSES;
f882c247 652
3d3d4255 653 LIST_FOREACH(addresses, ad, link->network->static_addresses) {
a6cc569e 654 r = address_configure(ad, link, &address_handler);
dd3efc09 655 if (r < 0) {
79008bdd 656 log_link_warning(link,
3c9b8860 657 "could not set addresses: %s",
a6cc569e 658 strerror(-r));
f5be5601
TG
659 link_enter_failed(link);
660 return r;
661 }
662
3c9b8860 663 link->link_messages ++;
f882c247
TG
664 }
665
3c9b8860 666 if (link->link_messages == 0) {
431ca2ce
TG
667 link_enter_set_routes(link);
668 } else
79008bdd 669 log_link_debug(link, "setting addresses");
431ca2ce 670
f882c247
TG
671 return 0;
672}
673
b22d8a00 674int link_address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 675 _cleanup_link_unref_ Link *link = userdata;
ff254138
TG
676 int r;
677
678 assert(m);
679 assert(link);
680 assert(link->ifname);
681
5da8149f 682 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
ff254138
TG
683 return 1;
684
685 r = sd_rtnl_message_get_errno(m);
b90b025a 686 if (r < 0 && r != -EADDRNOTAVAIL)
6c861f0a 687 log_link_warning_errno(link, -r, "%-*s: could not drop address: %m", IFNAMSIZ, link->ifname);
ff254138 688
5bdd314c 689 return 1;
ff254138
TG
690}
691
b98b483b
AR
692static int link_set_bridge_fdb(const Link *const link) {
693 FdbEntry *fdb_entry;
694 int r = 0;
695
696 LIST_FOREACH(static_fdb_entries, fdb_entry, link->network->static_fdb_entries) {
697 r = fdb_entry_configure(link->manager->rtnl, fdb_entry, link->ifindex);
698 if(r < 0) {
699 log_link_error(link, "Failed to add MAC entry to static MAC table: %s", strerror(-r));
700 break;
701 }
702 }
703
704 return r;
705}
706
e1853b00
SS
707static int link_set_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
708 _cleanup_link_unref_ Link *link = userdata;
709 int r;
710
00e8d83a 711 log_link_debug(link, "set link");
e1853b00
SS
712
713 r = sd_rtnl_message_get_errno(m);
714 if (r < 0 && r != -EEXIST) {
00e8d83a 715 log_link_struct(link, LOG_ERR,
e1853b00
SS
716 "MESSAGE=%-*s: could not join netdev: %s",
717 IFNAMSIZ,
718 link->ifname, strerror(-r),
719 "ERRNO=%d", -r,
720 NULL);
721 link_enter_failed(link);
722 return 1;
723 }
724
725 return 0;
726}
727
3c9b8860
TG
728static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata,
729 sd_bus_error *ret_error) {
5da8149f 730 _cleanup_link_unref_ Link *link = userdata;
1346b1f0
TG
731 int r;
732
b226d99b
TG
733 assert(link);
734
5da8149f 735 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
370e9930 736 return 1;
370e9930 737
1346b1f0 738 r = sd_bus_message_get_errno(m);
70b34f5d 739 if (r > 0)
79008bdd 740 log_link_warning(link, "Could not set hostname: %s",
3c9b8860 741 strerror(r));
1346b1f0
TG
742
743 return 1;
744}
745
3c9b8860 746int link_set_hostname(Link *link, const char *hostname) {
1346b1f0
TG
747 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
748 int r = 0;
749
b226d99b
TG
750 assert(link);
751 assert(link->manager);
1346b1f0
TG
752 assert(hostname);
753
79008bdd 754 log_link_debug(link, "Setting transient hostname: '%s'", hostname);
1346b1f0 755
3c9b8860
TG
756 if (!link->manager->bus) {
757 /* TODO: replace by assert when we can rely on kdbus */
79008bdd 758 log_link_info(link,
3c9b8860 759 "Not connected to system bus, ignoring transient hostname.");
bcbca829
TG
760 return 0;
761 }
762
1346b1f0 763 r = sd_bus_message_new_method_call(
b226d99b 764 link->manager->bus,
151b9b96 765 &m,
1346b1f0
TG
766 "org.freedesktop.hostname1",
767 "/org/freedesktop/hostname1",
768 "org.freedesktop.hostname1",
151b9b96 769 "SetHostname");
1346b1f0
TG
770 if (r < 0)
771 return r;
772
773 r = sd_bus_message_append(m, "sb", hostname, false);
774 if (r < 0)
775 return r;
776
3c9b8860
TG
777 r = sd_bus_call_async(link->manager->bus, NULL, m, set_hostname_handler,
778 link, 0);
5da8149f 779 if (r < 0) {
79008bdd 780 log_link_error(link, "Could not set transient hostname: %s",
3c9b8860 781 strerror(-r));
5da8149f
TG
782 return r;
783 }
b226d99b
TG
784
785 link_ref(link);
1346b1f0 786
5da8149f 787 return 0;
1346b1f0
TG
788}
789
4f882b2a 790static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 791 _cleanup_link_unref_ Link *link = userdata;
4f882b2a
TG
792 int r;
793
794 assert(m);
795 assert(link);
796 assert(link->ifname);
797
5da8149f 798 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
4f882b2a
TG
799 return 1;
800
801 r = sd_rtnl_message_get_errno(m);
c9ccc19f 802 if (r < 0)
6c861f0a 803 log_link_warning_errno(link, -r, "%-*s: could not set MTU: %m", IFNAMSIZ, link->ifname);
4f882b2a
TG
804
805 return 1;
806}
807
3c9b8860 808int link_set_mtu(Link *link, uint32_t mtu) {
cf6a8911 809 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
4f882b2a
TG
810 int r;
811
812 assert(link);
813 assert(link->manager);
814 assert(link->manager->rtnl);
815
79008bdd 816 log_link_debug(link, "setting MTU: %" PRIu32, mtu);
4f882b2a 817
151b9b96
LP
818 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
819 RTM_SETLINK, link->ifindex);
4f882b2a 820 if (r < 0) {
79008bdd 821 log_link_error(link, "Could not allocate RTM_SETLINK message");
4f882b2a
TG
822 return r;
823 }
824
825 r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
826 if (r < 0) {
79008bdd 827 log_link_error(link, "Could not append MTU: %s", strerror(-r));
4f882b2a
TG
828 return r;
829 }
830
3c9b8860
TG
831 r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link,
832 0, NULL);
4f882b2a 833 if (r < 0) {
79008bdd 834 log_link_error(link,
3c9b8860
TG
835 "Could not send rtnetlink message: %s",
836 strerror(-r));
4f882b2a
TG
837 return r;
838 }
839
ae941762 840 link_ref(link);
b226d99b 841
4f882b2a
TG
842 return 0;
843}
844
e1853b00
SS
845static int link_set_bridge(Link *link) {
846 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
847 int r;
848
849 assert(link);
850 assert(link->network);
851
852 if(link->network->cost == 0)
853 return 0;
854
855 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
856 RTM_SETLINK, link->ifindex);
857 if (r < 0) {
00e8d83a 858 log_link_error(link, "Could not allocate RTM_SETLINK message");
e1853b00
SS
859 return r;
860 }
861
862 r = sd_rtnl_message_link_set_family(req, PF_BRIDGE);
863 if (r < 0) {
00e8d83a 864 log_link_error(link,
e1853b00
SS
865 "Could not set message family %s", strerror(-r));
866 return r;
867 }
868
869 r = sd_rtnl_message_open_container(req, IFLA_PROTINFO);
870 if (r < 0) {
00e8d83a 871 log_link_error(link,
e1853b00
SS
872 "Could not append IFLA_PROTINFO attribute: %s",
873 strerror(-r));
874 return r;
875 }
876
877 if(link->network->cost != 0) {
878 r = sd_rtnl_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost);
879 if (r < 0) {
00e8d83a 880 log_link_error(link,
e1853b00
SS
881 "Could not append IFLA_BRPORT_COST attribute: %s",
882 strerror(-r));
883 return r;
884 }
885 }
886
887 r = sd_rtnl_message_close_container(req);
888 if (r < 0) {
00e8d83a 889 log_link_error(link,
e1853b00
SS
890 "Could not append IFLA_LINKINFO attribute: %s",
891 strerror(-r));
892 return r;
893 }
894
895 r = sd_rtnl_call_async(link->manager->rtnl, req, link_set_handler, link, 0, NULL);
896 if (r < 0) {
00e8d83a 897 log_link_error(link,
e1853b00
SS
898 "Could not send rtnetlink message: %s",
899 strerror(-r));
900 return r;
901 }
902
903 link_ref(link);
904
905 return r;
906}
907
49699bac
SS
908static void lldp_handler(sd_lldp *lldp, int event, void *userdata) {
909 Link *link = userdata;
910 int r;
911
912 assert(link);
913 assert(link->network);
914 assert(link->manager);
915
916 if (event != UPDATE_INFO)
917 return;
918
919 r = sd_lldp_save(link->lldp, link->lldp_file);
920 if (r < 0)
921 log_link_warning(link, "could not save LLDP");
922
923}
924
ff254138
TG
925static int link_acquire_conf(Link *link) {
926 int r;
927
928 assert(link);
929 assert(link->network);
ff254138
TG
930 assert(link->manager);
931 assert(link->manager->event);
932
78c958f8 933 if (link_ipv4ll_enabled(link)) {
eb34d4af 934 assert(link->ipv4ll);
ff254138 935
79008bdd 936 log_link_debug(link, "acquiring IPv4 link-local address");
5c1d3fc9
UTL
937
938 r = sd_ipv4ll_start(link->ipv4ll);
124fa2c6 939 if (r < 0) {
79008bdd 940 log_link_warning(link, "could not acquire IPv4 "
124fa2c6 941 "link-local address");
ff254138 942 return r;
124fa2c6 943 }
5c1d3fc9
UTL
944 }
945
78c958f8 946 if (link_dhcp4_enabled(link)) {
eb34d4af 947 assert(link->dhcp_client);
ff254138 948
79008bdd 949 log_link_debug(link, "acquiring DHCPv4 lease");
ab47d620 950
5c1d3fc9 951 r = sd_dhcp_client_start(link->dhcp_client);
124fa2c6 952 if (r < 0) {
79008bdd 953 log_link_warning(link, "could not acquire DHCPv4 "
124fa2c6 954 "lease");
5c1d3fc9 955 return r;
124fa2c6 956 }
5c1d3fc9 957 }
ff254138 958
78c958f8 959 if (link_dhcp6_enabled(link)) {
4138fb2c
PF
960 assert(link->icmp6_router_discovery);
961
79008bdd 962 log_link_debug(link, "discovering IPv6 routers");
4138fb2c
PF
963
964 r = sd_icmp6_router_solicitation_start(link->icmp6_router_discovery);
965 if (r < 0) {
79008bdd 966 log_link_warning(link,
3c9b8860 967 "could not start IPv6 router discovery");
4138fb2c
PF
968 return r;
969 }
970 }
971
ce43e484
SS
972 if (link_lldp_enabled(link)) {
973 assert(link->lldp);
974
975 log_link_debug(link, "Starting LLDP");
976
977 r = sd_lldp_start(link->lldp);
978 if (r < 0) {
979 log_link_warning(link, "could not start LLDP ");
980 return r;
981 }
982 }
983
ff254138
TG
984 return 0;
985}
986
a61bb41c 987bool link_has_carrier(Link *link) {
deb2e523
TG
988 /* see Documentation/networking/operstates.txt in the kernel sources */
989
a61bb41c 990 if (link->kernel_operstate == IF_OPER_UP)
deb2e523
TG
991 return true;
992
a61bb41c 993 if (link->kernel_operstate == IF_OPER_UNKNOWN)
deb2e523 994 /* operstate may not be implemented, so fall back to flags */
a61bb41c 995 if ((link->flags & IFF_LOWER_UP) && !(link->flags & IFF_DORMANT))
deb2e523
TG
996 return true;
997
998 return false;
999}
1000
dd3efc09 1001static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 1002 _cleanup_link_unref_ Link *link = userdata;
dd3efc09
TG
1003 int r;
1004
1746cf2a
TG
1005 assert(link);
1006
5da8149f 1007 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1746cf2a
TG
1008 return 1;
1009
dd3efc09 1010 r = sd_rtnl_message_get_errno(m);
45ad2c13 1011 if (r < 0) {
9b86b393
TG
1012 /* we warn but don't fail the link, as it may
1013 be brought up later */
6c861f0a 1014 log_link_warning_errno(link, -r, "%-*s: could not bring up interface: %m", IFNAMSIZ, link->ifname);
45ad2c13
TG
1015 }
1016
f882c247
TG
1017 return 1;
1018}
1019
1020static int link_up(Link *link) {
cf6a8911 1021 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
f579559b
TG
1022 int r;
1023
f882c247 1024 assert(link);
c106cc36 1025 assert(link->network);
f882c247
TG
1026 assert(link->manager);
1027 assert(link->manager->rtnl);
1028
79008bdd 1029 log_link_debug(link, "bringing link up");
449f7554 1030
151b9b96
LP
1031 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
1032 RTM_SETLINK, link->ifindex);
f579559b 1033 if (r < 0) {
79008bdd 1034 log_link_error(link, "Could not allocate RTM_SETLINK message");
f579559b
TG
1035 return r;
1036 }
1037
5d4795f3 1038 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
fc25d7f8 1039 if (r < 0) {
79008bdd 1040 log_link_error(link, "Could not set link flags: %s",
3c9b8860 1041 strerror(-r));
fc25d7f8
TG
1042 return r;
1043 }
1044
c106cc36
TG
1045 if (link->network->mac) {
1046 r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, link->network->mac);
1047 if (r < 0) {
1048 log_link_error(link, "Could not set MAC address: %s", strerror(-r));
1049 return r;
1050 }
1051 }
1052
1053 if (link->network->mtu) {
1054 r = sd_rtnl_message_append_u32(req, IFLA_MTU, link->network->mtu);
1055 if (r < 0) {
1056 log_link_error(link, "Could not set MTU: %s", strerror(-r));
1057 return r;
1058 }
1059 }
1060
3c9b8860
TG
1061 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link,
1062 0, NULL);
f579559b 1063 if (r < 0) {
79008bdd 1064 log_link_error(link,
3c9b8860
TG
1065 "Could not send rtnetlink message: %s",
1066 strerror(-r));
f579559b
TG
1067 return r;
1068 }
1069
b226d99b
TG
1070 link_ref(link);
1071
f882c247
TG
1072 return 0;
1073}
1074
3f265037 1075static int link_joined(Link *link) {
f882c247
TG
1076 int r;
1077
ef1ba606 1078 assert(link);
f5be5601 1079 assert(link->network);
dd3efc09 1080
505f8da7
TG
1081 if (!(link->flags & IFF_UP)) {
1082 r = link_up(link);
1083 if (r < 0) {
1084 link_enter_failed(link);
1085 return r;
1086 }
ef1ba606 1087 }
f882c247 1088
e1853b00
SS
1089 if(link->network->bridge) {
1090 r = link_set_bridge(link);
1091 if (r < 0) {
00e8d83a 1092 log_link_error(link,
e1853b00
SS
1093 "Could not set bridge message: %s",
1094 strerror(-r));
1095 }
1096 }
1097
fb6730c4 1098 return link_enter_set_addresses(link);
02b59d57
TG
1099}
1100
3c9b8860
TG
1101static int netdev_join_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
1102 void *userdata) {
5da8149f 1103 _cleanup_link_unref_ Link *link = userdata;
02b59d57
TG
1104 int r;
1105
1746cf2a 1106 assert(link);
ef1ba606 1107 assert(link->network);
02b59d57 1108
52433f6b
TG
1109 link->enslaving --;
1110
5da8149f 1111 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
02b59d57
TG
1112 return 1;
1113
1114 r = sd_rtnl_message_get_errno(m);
856f962c 1115 if (r < 0 && r != -EEXIST) {
6c861f0a 1116 log_link_error_errno(link, -r, "%-*s: could not join netdev: %m", IFNAMSIZ, link->ifname);
ef1ba606
TG
1117 link_enter_failed(link);
1118 return 1;
ba179154 1119 } else
79008bdd 1120 log_link_debug(link, "joined netdev");
02b59d57 1121
856f962c 1122 if (link->enslaving <= 0)
3f265037 1123 link_joined(link);
02b59d57
TG
1124
1125 return 1;
1126}
1127
3f265037 1128static int link_enter_join_netdev(Link *link) {
6a0a2f86 1129 NetDev *netdev;
672682a6 1130 Iterator i;
02b59d57
TG
1131 int r;
1132
1133 assert(link);
1134 assert(link->network);
8434fd5c 1135 assert(link->state == LINK_STATE_PENDING);
02b59d57 1136
52433f6b 1137 link->state = LINK_STATE_ENSLAVING;
02b59d57 1138
fe8db0c5
TG
1139 link_save(link);
1140
7951dea2
SS
1141 if (!link->network->bridge &&
1142 !link->network->bond &&
6a0a2f86 1143 hashmap_isempty(link->network->stacked_netdevs))
3f265037 1144 return link_joined(link);
02b59d57 1145
d9c67ea1 1146 if (link->network->bond) {
6c861f0a 1147 log_link_struct(link, LOG_DEBUG,
97578344 1148 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1149 IFNAMSIZ,
af4e9e2c 1150 link->ifname, link->network->bond->ifname,
aa9f1140 1151 NETDEVIF(link->network->bond),
52433f6b 1152 NULL);
449f7554 1153
3f265037 1154 r = netdev_join(link->network->bond, link, &netdev_join_handler);
52433f6b 1155 if (r < 0) {
6c861f0a 1156 log_link_struct(link, LOG_WARNING,
3f265037 1157 "MESSAGE=%-*s: could not join netdev '%s': %s",
987efa17 1158 IFNAMSIZ,
3c9b8860
TG
1159 link->ifname, link->network->bond->ifname,
1160 strerror(-r),
aa9f1140 1161 NETDEVIF(link->network->bond),
52433f6b
TG
1162 NULL);
1163 link_enter_failed(link);
1164 return r;
1165 }
1166
0ad6148e
MO
1167 link->enslaving ++;
1168 }
1169
d9c67ea1 1170 if (link->network->bridge) {
6c861f0a 1171 log_link_struct(link, LOG_DEBUG,
97578344 1172 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1173 IFNAMSIZ,
af4e9e2c 1174 link->ifname, link->network->bridge->ifname,
aa9f1140 1175 NETDEVIF(link->network->bridge),
0ad6148e
MO
1176 NULL);
1177
3c9b8860
TG
1178 r = netdev_join(link->network->bridge, link,
1179 &netdev_join_handler);
0ad6148e 1180 if (r < 0) {
6c861f0a 1181 log_link_struct(link, LOG_WARNING,
3f265037 1182 "MESSAGE=%-*s: could not join netdev '%s': %s",
987efa17 1183 IFNAMSIZ,
3c9b8860
TG
1184 link->ifname, link->network->bridge->ifname,
1185 strerror(-r),
aa9f1140 1186 NETDEVIF(link->network->bridge),
0ad6148e
MO
1187 NULL);
1188 link_enter_failed(link);
1189 return r;
1190 }
1191
52433f6b
TG
1192 link->enslaving ++;
1193 }
1194
6a0a2f86 1195 HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) {
6c861f0a 1196 log_link_struct(link, LOG_DEBUG,
97578344 1197 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1198 IFNAMSIZ,
3c9b8860
TG
1199 link->ifname, netdev->ifname, NETDEVIF(netdev),
1200 NULL);
7951dea2 1201
6a0a2f86 1202 r = netdev_join(netdev, link, &netdev_join_handler);
7951dea2 1203 if (r < 0) {
6c861f0a 1204 log_link_struct(link, LOG_WARNING,
3f265037 1205 "MESSAGE=%-*s: could not join netdev '%s': %s",
987efa17 1206 IFNAMSIZ,
3c9b8860
TG
1207 link->ifname, netdev->ifname,
1208 strerror(-r),
6a0a2f86 1209 NETDEVIF(netdev), NULL);
326cb406
SS
1210 link_enter_failed(link);
1211 return r;
1212 }
1213
326cb406
SS
1214 link->enslaving ++;
1215 }
1216
ef1ba606
TG
1217 return 0;
1218}
1219
a748b692 1220static int link_configure(Link *link) {
02b59d57
TG
1221 int r;
1222
ef1ba606 1223 assert(link);
b22d8a00 1224 assert(link->network);
8434fd5c 1225 assert(link->state == LINK_STATE_PENDING);
a748b692 1226
b98b483b
AR
1227 r = link_set_bridge_fdb(link);
1228 if (r < 0)
1229 return r;
1230
78c958f8 1231 if (link_ipv4ll_enabled(link)) {
b22d8a00 1232 r = ipv4ll_configure(link);
eb34d4af
TG
1233 if (r < 0)
1234 return r;
1235 }
1236
78c958f8 1237 if (link_dhcp4_enabled(link)) {
3c9b8860 1238 r = dhcp4_configure(link);
eb34d4af
TG
1239 if (r < 0)
1240 return r;
eb34d4af
TG
1241 }
1242
78c958f8 1243 if (link_dhcp4_server_enabled(link)) {
dd43110f
TG
1244 r = sd_dhcp_server_new(&link->dhcp_server, link->ifindex);
1245 if (r < 0)
1246 return r;
1247
1248 r = sd_dhcp_server_attach_event(link->dhcp_server, NULL, 0);
1249 if (r < 0)
1250 return r;
dd43110f
TG
1251 }
1252
78c958f8 1253 if (link_dhcp6_enabled(link)) {
5c79bd79 1254 r = icmp6_configure(link);
4138fb2c
PF
1255 if (r < 0)
1256 return r;
1257 }
1258
ce43e484
SS
1259 if (link_lldp_enabled(link)) {
1260 r = sd_lldp_new(link->ifindex, link->ifname, &link->mac, &link->lldp);
1261 if (r < 0)
1262 return r;
1263
1264 r = sd_lldp_attach_event(link->lldp, NULL, 0);
1265 if (r < 0)
1266 return r;
49699bac
SS
1267
1268 r = sd_lldp_set_callback(link->lldp,
1269 lldp_handler, link);
1270 if (r < 0)
1271 return r;
ce43e484
SS
1272 }
1273
a61bb41c 1274 if (link_has_carrier(link)) {
1e9be60b
TG
1275 r = link_acquire_conf(link);
1276 if (r < 0)
1277 return r;
cc544d5f 1278 }
1e9be60b 1279
3f265037 1280 return link_enter_join_netdev(link);
505f8da7
TG
1281}
1282
3c9b8860
TG
1283static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m,
1284 void *userdata) {
5da8149f 1285 _cleanup_link_unref_ Link *link = userdata;
505f8da7 1286 Network *network;
505f8da7
TG
1287 int r;
1288
1289 assert(link);
1290 assert(link->ifname);
1291 assert(link->manager);
1292
8434fd5c 1293 if (link->state != LINK_STATE_PENDING)
5da8149f 1294 return 1;
505f8da7 1295
79008bdd 1296 log_link_debug(link, "link state is up-to-date");
505f8da7 1297
3c9b8860
TG
1298 r = network_get(link->manager, link->udev_device, link->ifname,
1299 &link->mac, &network);
57bd6899
TG
1300 if (r == -ENOENT) {
1301 link_enter_unmanaged(link);
5da8149f 1302 return 1;
57bd6899
TG
1303 } else if (r < 0)
1304 return r;
505f8da7 1305
bd2efe92 1306 if (link->flags & IFF_LOOPBACK) {
78c958f8 1307 if (network->ipv4ll)
79008bdd 1308 log_link_debug(link, "ignoring IPv4LL for loopback link");
78c958f8
TG
1309
1310 if (network->dhcp != DHCP_SUPPORT_NONE)
79008bdd 1311 log_link_debug(link, "ignoring DHCP clients for loopback link");
78c958f8
TG
1312
1313 if (network->dhcp_server)
79008bdd 1314 log_link_debug(link, "ignoring DHCP server for loopback link");
bd2efe92
TG
1315 }
1316
505f8da7
TG
1317 r = network_apply(link->manager, network, link);
1318 if (r < 0)
1319 return r;
1320
a748b692
TG
1321 r = link_configure(link);
1322 if (r < 0)
1323 return r;
1324
5da8149f 1325 return 1;
505f8da7
TG
1326}
1327
4f561e8e
TG
1328int link_initialized(Link *link, struct udev_device *device) {
1329 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
1330 int r;
1331
1332 assert(link);
1333 assert(link->manager);
1334 assert(link->manager->rtnl);
1335 assert(device);
1336
8434fd5c 1337 if (link->state != LINK_STATE_PENDING)
4f561e8e
TG
1338 return 0;
1339
679b3605
TG
1340 if (link->udev_device)
1341 return 0;
1342
79008bdd 1343 log_link_debug(link, "udev initialized link");
4f561e8e
TG
1344
1345 link->udev_device = udev_device_ref(device);
1346
3c9b8860
TG
1347 /* udev has initialized the link, but we don't know if we have yet
1348 * processed the NEWLINK messages with the latest state. Do a GETLINK,
1349 * when it returns we know that the pending NEWLINKs have already been
1350 * processed and that we are up-to-date */
4f561e8e 1351
3c9b8860
TG
1352 r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_GETLINK,
1353 link->ifindex);
4f561e8e
TG
1354 if (r < 0)
1355 return r;
1356
3c9b8860
TG
1357 r = sd_rtnl_call_async(link->manager->rtnl, req,
1358 link_initialized_and_synced, link, 0, NULL);
4f561e8e
TG
1359 if (r < 0)
1360 return r;
1361
5da8149f
TG
1362 link_ref(link);
1363
4f561e8e
TG
1364 return 0;
1365}
1366
45af44d4 1367int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
fbbeb65a
TG
1368 Manager *m = userdata;
1369 Link *link = NULL;
1370 uint16_t type;
1371 _cleanup_address_free_ Address *address = NULL;
428fd0a7 1372 Address *ad;
fbbeb65a 1373 char buf[INET6_ADDRSTRLEN];
c6d3b303
TG
1374 char valid_buf[FORMAT_TIMESPAN_MAX];
1375 const char *valid_str = NULL;
428fd0a7 1376 bool address_dropped = false;
fbbeb65a
TG
1377 int r, ifindex;
1378
1379 assert(rtnl);
1380 assert(message);
1381 assert(m);
1382
45af44d4
TG
1383 if (sd_rtnl_message_is_error(message)) {
1384 r = sd_rtnl_message_get_errno(message);
1385 if (r < 0)
1386 log_warning_errno(r, "rtnl: failed to receive address: %m");
1387
1388 return 0;
1389 }
1390
fbbeb65a
TG
1391 r = sd_rtnl_message_get_type(message, &type);
1392 if (r < 0) {
1393 log_warning("rtnl: could not get message type");
1394 return 0;
1395 }
1396
1397 r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
45af44d4
TG
1398 if (r < 0) {
1399 log_warning_errno(r, "rtnl: could not get ifindex: %m");
1400 return 0;
1401 } else if (ifindex <= 0) {
1402 log_warning("rtnl: received address message with invalid ifindex: %d", ifindex);
fbbeb65a
TG
1403 return 0;
1404 } else {
1405 r = link_get(m, ifindex, &link);
1406 if (r < 0 || !link) {
1e19f352 1407 log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex);
fbbeb65a
TG
1408 return 0;
1409 }
1410 }
1411
1412 r = address_new_dynamic(&address);
1413 if (r < 0)
393c0c5e 1414 return r;
fbbeb65a
TG
1415
1416 r = sd_rtnl_message_addr_get_family(message, &address->family);
1417 if (r < 0 || !IN_SET(address->family, AF_INET, AF_INET6)) {
79008bdd 1418 log_link_warning(link,
3c9b8860 1419 "rtnl: received address with invalid family, ignoring");
fbbeb65a
TG
1420 return 0;
1421 }
1422
1423 r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen);
1424 if (r < 0) {
79008bdd 1425 log_link_warning(link,
3c9b8860 1426 "rtnl: received address with invalid prefixlen, ignoring");
e375dcde
TG
1427 return 0;
1428 }
1429
1430 r = sd_rtnl_message_addr_get_scope(message, &address->scope);
1431 if (r < 0) {
79008bdd 1432 log_link_warning(link,
3c9b8860 1433 "rtnl: received address with invalid scope, ignoring");
fbbeb65a
TG
1434 return 0;
1435 }
1436
81163121
TG
1437 r = sd_rtnl_message_addr_get_flags(message, &address->flags);
1438 if (r < 0) {
79008bdd 1439 log_link_warning(link,
81163121
TG
1440 "rtnl: received address with invalid flags, ignoring");
1441 return 0;
1442 }
1443
fbbeb65a
TG
1444 switch (address->family) {
1445 case AF_INET:
3c9b8860
TG
1446 r = sd_rtnl_message_read_in_addr(message, IFA_LOCAL,
1447 &address->in_addr.in);
fbbeb65a 1448 if (r < 0) {
79008bdd 1449 log_link_warning(link,
3c9b8860 1450 "rtnl: received address without valid address, ignoring");
fbbeb65a
TG
1451 return 0;
1452 }
1453
1454 break;
1455
1456 case AF_INET6:
3c9b8860
TG
1457 r = sd_rtnl_message_read_in6_addr(message, IFA_ADDRESS,
1458 &address->in_addr.in6);
fbbeb65a 1459 if (r < 0) {
79008bdd 1460 log_link_warning(link,
3c9b8860 1461 "rtnl: received address without valid address, ignoring");
fbbeb65a
TG
1462 return 0;
1463 }
1464
1465 break;
1466
1467 default:
1468 assert_not_reached("invalid address family");
1469 }
1470
3c9b8860
TG
1471 if (!inet_ntop(address->family, &address->in_addr, buf,
1472 INET6_ADDRSTRLEN)) {
79008bdd 1473 log_link_warning(link, "could not print address");
fbbeb65a
TG
1474 return 0;
1475 }
1476
c6d3b303
TG
1477 r = sd_rtnl_message_read_cache_info(message, IFA_CACHEINFO,
1478 &address->cinfo);
1479 if (r >= 0) {
1480 if (address->cinfo.ifa_valid == CACHE_INFO_INFINITY_LIFE_TIME)
1481 valid_str = "ever";
1482 else
1483 valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
1484 address->cinfo.ifa_valid * USEC_PER_SEC,
1485 USEC_PER_SEC);
1486 }
1487
428fd0a7
TG
1488 LIST_FOREACH(addresses, ad, link->addresses) {
1489 if (address_equal(ad, address)) {
1490 LIST_REMOVE(addresses, link->addresses, ad);
1491
1492 address_free(ad);
1493
1494 address_dropped = true;
1495
1496 break;
1497 }
1498 }
1499
fbbeb65a
TG
1500 switch (type) {
1501 case RTM_NEWADDR:
428fd0a7 1502 if (!address_dropped)
79008bdd 1503 log_link_debug(link, "added address: %s/%u (valid for %s)",
b1d6dcf5 1504 buf, address->prefixlen, valid_str);
393c0c5e 1505 else
79008bdd 1506 log_link_debug(link, "updated address: %s/%u (valid for %s)",
b1d6dcf5 1507 buf, address->prefixlen, valid_str);
fbbeb65a 1508
428fd0a7
TG
1509 LIST_PREPEND(addresses, link->addresses, address);
1510 address = NULL;
1511
f5602be9
TG
1512 link_save(link);
1513
428fd0a7 1514 break;
fbbeb65a 1515 case RTM_DELADDR:
f5602be9 1516 if (address_dropped) {
79008bdd 1517 log_link_debug(link, "removed address: %s/%u (valid for %s)",
b1d6dcf5 1518 buf, address->prefixlen, valid_str);
428fd0a7 1519
f5602be9 1520 link_save(link);
393c0c5e 1521 } else
79008bdd 1522 log_link_warning(link,
c6d3b303 1523 "removing non-existent address: %s/%u (valid for %s)",
b1d6dcf5 1524 buf, address->prefixlen, valid_str);
f5602be9 1525
fbbeb65a
TG
1526 break;
1527 default:
1528 assert_not_reached("Received invalid RTNL message type");
1529 }
1530
1531 return 1;
1532}
1533
505f8da7
TG
1534int link_add(Manager *m, sd_rtnl_message *message, Link **ret) {
1535 Link *link;
1536 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
1537 char ifindex_str[2 + DECIMAL_STR_MAX(int)];
1538 int r;
1539
1540 assert(m);
fbbeb65a 1541 assert(m->rtnl);
505f8da7
TG
1542 assert(message);
1543 assert(ret);
1544
1545 r = link_new(m, message, ret);
1546 if (r < 0)
1547 return r;
1548
1549 link = *ret;
1550
79008bdd 1551 log_link_debug(link, "link %d added", link->ifindex);
505f8da7
TG
1552
1553 if (detect_container(NULL) <= 0) {
1554 /* not in a container, udev will be around */
ae06ab10 1555 sprintf(ifindex_str, "n%d", link->ifindex);
505f8da7
TG
1556 device = udev_device_new_from_device_id(m->udev, ifindex_str);
1557 if (!device) {
79008bdd 1558 log_link_warning(link,
3c9b8860 1559 "could not find udev device: %m");
9fecce80 1560 return -errno;
505f8da7
TG
1561 }
1562
3c4cb064 1563 if (udev_device_get_is_initialized(device) <= 0) {
505f8da7 1564 /* not yet ready */
79008bdd 1565 log_link_debug(link, "link pending udev initialization...");
505f8da7 1566 return 0;
3c4cb064 1567 }
505f8da7 1568
4f561e8e
TG
1569 r = link_initialized(link, device);
1570 if (r < 0)
1571 return r;
1572 } else {
5da8149f
TG
1573 /* we are calling a callback directly, so must take a ref */
1574 link_ref(link);
1575
4f561e8e
TG
1576 r = link_initialized_and_synced(m->rtnl, NULL, link);
1577 if (r < 0)
1578 return r;
1579 }
505f8da7 1580
a748b692
TG
1581 return 0;
1582}
1583
22936833 1584int link_update(Link *link, sd_rtnl_message *m) {
c49b33ac 1585 struct ether_addr mac;
ca4e095a 1586 const char *ifname;
afe7fd56 1587 uint32_t mtu;
a61bb41c 1588 bool had_carrier, carrier_gained, carrier_lost;
22936833
TG
1589 int r;
1590
dd3efc09 1591 assert(link);
b8941f74 1592 assert(link->ifname);
22936833
TG
1593 assert(m);
1594
7619683b
TG
1595 if (link->state == LINK_STATE_LINGER) {
1596 link_ref(link);
79008bdd 1597 log_link_info(link, "link readded");
7619683b
TG
1598 link->state = LINK_STATE_ENSLAVING;
1599 }
1600
b8941f74
TG
1601 r = sd_rtnl_message_read_string(m, IFLA_IFNAME, &ifname);
1602 if (r >= 0 && !streq(ifname, link->ifname)) {
79008bdd 1603 log_link_info(link, "renamed to %s", ifname);
b8941f74
TG
1604
1605 free(link->ifname);
1606 link->ifname = strdup(ifname);
1607 if (!link->ifname)
1608 return -ENOMEM;
1609 }
1610
afe7fd56
TG
1611 r = sd_rtnl_message_read_u32(m, IFLA_MTU, &mtu);
1612 if (r >= 0 && mtu > 0) {
1613 link->mtu = mtu;
1614 if (!link->original_mtu) {
1615 link->original_mtu = mtu;
79008bdd 1616 log_link_debug(link, "saved original MTU: %"
afe7fd56
TG
1617 PRIu32, link->original_mtu);
1618 }
1619
1620 if (link->dhcp_client) {
3c9b8860
TG
1621 r = sd_dhcp_client_set_mtu(link->dhcp_client,
1622 link->mtu);
afe7fd56 1623 if (r < 0) {
79008bdd 1624 log_link_warning(link,
3c9b8860 1625 "Could not update MTU in DHCP client: %s",
afe7fd56
TG
1626 strerror(-r));
1627 return r;
1628 }
1629 }
9842de0d 1630 }
69629de9 1631
e9189a1f
TG
1632 /* The kernel may broadcast NEWLINK messages without the MAC address
1633 set, simply ignore them. */
c49b33ac 1634 r = sd_rtnl_message_read_ether_addr(m, IFLA_ADDRESS, &mac);
e9189a1f 1635 if (r >= 0) {
3c9b8860
TG
1636 if (memcmp(link->mac.ether_addr_octet, mac.ether_addr_octet,
1637 ETH_ALEN)) {
c49b33ac 1638
3c9b8860
TG
1639 memcpy(link->mac.ether_addr_octet, mac.ether_addr_octet,
1640 ETH_ALEN);
c49b33ac 1641
79008bdd 1642 log_link_debug(link, "MAC address: "
20861203
TG
1643 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
1644 mac.ether_addr_octet[0],
1645 mac.ether_addr_octet[1],
1646 mac.ether_addr_octet[2],
1647 mac.ether_addr_octet[3],
1648 mac.ether_addr_octet[4],
1649 mac.ether_addr_octet[5]);
c49b33ac 1650
20861203
TG
1651 if (link->ipv4ll) {
1652 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
1653 if (r < 0) {
79008bdd 1654 log_link_warning(link,
3c9b8860 1655 "Could not update MAC address in IPv4LL client: %s",
20861203
TG
1656 strerror(-r));
1657 return r;
1658 }
c49b33ac 1659 }
c49b33ac 1660
20861203 1661 if (link->dhcp_client) {
3c9b8860 1662 r = sd_dhcp_client_set_mac(link->dhcp_client,
76253e73
DW
1663 (const uint8_t *) &link->mac,
1664 sizeof (link->mac),
1665 ARPHRD_ETHER);
20861203 1666 if (r < 0) {
79008bdd 1667 log_link_warning(link,
3c9b8860 1668 "Could not update MAC address in DHCP client: %s",
20861203
TG
1669 strerror(-r));
1670 return r;
1671 }
c49b33ac 1672 }
4138fb2c
PF
1673
1674 if (link->dhcp6_client) {
1675 r = sd_dhcp6_client_set_mac(link->dhcp6_client,
76253e73
DW
1676 (const uint8_t *) &link->mac,
1677 sizeof (link->mac),
1678 ARPHRD_ETHER);
4138fb2c 1679 if (r < 0) {
79008bdd 1680 log_link_warning(link,
3c9b8860 1681 "Could not update MAC address in DHCPv6 client: %s",
4138fb2c
PF
1682 strerror(-r));
1683 return r;
1684 }
1685 }
c49b33ac 1686 }
4f882b2a
TG
1687 }
1688
a61bb41c
TG
1689 had_carrier = link_has_carrier(link);
1690
1691 r = link_update_flags(link, m);
1692 if (r < 0)
1693 return r;
1694
1695 carrier_gained = !had_carrier && link_has_carrier(link);
1696 carrier_lost = had_carrier && !link_has_carrier(link);
1697
1698 if (carrier_gained) {
79008bdd 1699 log_link_info(link, "gained carrier");
a61bb41c
TG
1700
1701 if (link->network) {
1702 r = link_acquire_conf(link);
1703 if (r < 0) {
1704 link_enter_failed(link);
1705 return r;
1706 }
1707 }
1708 } else if (carrier_lost) {
79008bdd 1709 log_link_info(link, "lost carrier");
a61bb41c
TG
1710
1711 r = link_stop_clients(link);
1712 if (r < 0) {
1713 link_enter_failed(link);
1714 return r;
1715 }
1716 }
1717
1718 return 0;
dd3efc09 1719}
fe8db0c5 1720
e375dcde
TG
1721static void link_update_operstate(Link *link) {
1722
1723 assert(link);
1724
1725 if (link->kernel_operstate == IF_OPER_DORMANT)
1726 link->operstate = LINK_OPERSTATE_DORMANT;
a61bb41c 1727 else if (link_has_carrier(link)) {
e375dcde
TG
1728 Address *address;
1729 uint8_t scope = RT_SCOPE_NOWHERE;
1730
1731 /* if we have carrier, check what addresses we have */
1732 LIST_FOREACH(addresses, address, link->addresses) {
81163121
TG
1733 if (address->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))
1734 continue;
1735
e375dcde
TG
1736 if (address->scope < scope)
1737 scope = address->scope;
1738 }
1739
1740 if (scope < RT_SCOPE_SITE)
1741 /* universally accessible addresses found */
1742 link->operstate = LINK_OPERSTATE_ROUTABLE;
1743 else if (scope < RT_SCOPE_HOST)
1744 /* only link or site local addresses found */
1745 link->operstate = LINK_OPERSTATE_DEGRADED;
1746 else
1747 /* no useful addresses found */
1748 link->operstate = LINK_OPERSTATE_CARRIER;
54cba0b1 1749 } else if (link->flags & IFF_UP)
d3df0e39 1750 link->operstate = LINK_OPERSTATE_NO_CARRIER;
54cba0b1 1751 else
d3df0e39 1752 link->operstate = LINK_OPERSTATE_OFF;
e375dcde
TG
1753}
1754
fe8db0c5 1755int link_save(Link *link) {
68a8723c 1756 _cleanup_free_ char *temp_path = NULL;
fe8db0c5 1757 _cleanup_fclose_ FILE *f = NULL;
e375dcde 1758 const char *admin_state, *oper_state;
fe8db0c5
TG
1759 int r;
1760
1761 assert(link);
1762 assert(link->state_file);
68a8723c 1763 assert(link->lease_file);
bbf7c048
TG
1764 assert(link->manager);
1765
e375dcde
TG
1766 link_update_operstate(link);
1767
bbf7c048
TG
1768 r = manager_save(link->manager);
1769 if (r < 0)
1770 return r;
fe8db0c5 1771
370e9930
TG
1772 if (link->state == LINK_STATE_LINGER) {
1773 unlink(link->state_file);
1774 return 0;
1775 }
1776
deb2e523
TG
1777 admin_state = link_state_to_string(link->state);
1778 assert(admin_state);
1779
e375dcde
TG
1780 oper_state = link_operstate_to_string(link->operstate);
1781 assert(oper_state);
deb2e523 1782
fe8db0c5
TG
1783 r = fopen_temporary(link->state_file, &f, &temp_path);
1784 if (r < 0)
c2d6bd61 1785 return r;
fe8db0c5
TG
1786
1787 fchmod(fileno(f), 0644);
1788
1789 fprintf(f,
1790 "# This is private data. Do not parse.\n"
deb2e523 1791 "ADMIN_STATE=%s\n"
6dcaa6f5
TG
1792 "OPER_STATE=%s\n",
1793 admin_state, oper_state);
fe8db0c5 1794
bcb7a07e 1795 if (link->network) {
ea352b40
LP
1796 char **address, **domain;
1797 bool space;
b0e39c82 1798
adc5b2e2
TG
1799 fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
1800
b0e39c82 1801 fputs("DNS=", f);
ea352b40
LP
1802 space = false;
1803 STRV_FOREACH(address, link->network->dns) {
1804 if (space)
1805 fputc(' ', f);
1806 fputs(*address, f);
1807 space = true;
1808 }
d5314fff 1809
b0e39c82
TG
1810 if (link->network->dhcp_dns &&
1811 link->dhcp_lease) {
1812 const struct in_addr *addresses;
1813
1814 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
1815 if (r > 0) {
ea352b40
LP
1816 if (space)
1817 fputc(' ', f);
b0e39c82 1818 serialize_in_addrs(f, addresses, r);
b0e39c82
TG
1819 }
1820 }
1821
b0e39c82
TG
1822 fputs("\n", f);
1823
1824 fprintf(f, "NTP=");
ea352b40
LP
1825 space = false;
1826 STRV_FOREACH(address, link->network->ntp) {
1827 if (space)
1828 fputc(' ', f);
1829 fputs(*address, f);
1830 space = true;
1831 }
d5314fff 1832
b0e39c82
TG
1833 if (link->network->dhcp_ntp &&
1834 link->dhcp_lease) {
1835 const struct in_addr *addresses;
1836
1837 r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
1838 if (r > 0) {
ea352b40
LP
1839 if (space)
1840 fputc(' ', f);
b0e39c82 1841 serialize_in_addrs(f, addresses, r);
b0e39c82
TG
1842 }
1843 }
1844
b0e39c82 1845 fputs("\n", f);
bd8f6538 1846
6192b846 1847 fprintf(f, "DOMAINS=");
ea352b40
LP
1848 space = false;
1849 STRV_FOREACH(domain, link->network->domains) {
1850 if (space)
1851 fputc(' ', f);
1852 fputs(*domain, f);
1853 space = true;
1854 }
d5314fff 1855
ad0734e8 1856 if (link->network->dhcp_domains &&
9b4d1882
TG
1857 link->dhcp_lease) {
1858 const char *domainname;
1859
1860 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
6192b846 1861 if (r >= 0) {
ea352b40
LP
1862 if (space)
1863 fputc(' ', f);
6192b846 1864 fputs(domainname, f);
6192b846 1865 }
9b4d1882
TG
1866 }
1867
6192b846
TG
1868 fputs("\n", f);
1869
67272d15
TG
1870 fprintf(f, "WILDCARD_DOMAIN=%s\n",
1871 yes_no(link->network->wildcard_domain));
1872
3c9b8860
TG
1873 fprintf(f, "LLMNR=%s\n",
1874 llmnr_support_to_string(link->network->llmnr));
bcb7a07e 1875 }
7374f9d8 1876
fe8db0c5 1877 if (link->dhcp_lease) {
d9876a52
TG
1878 assert(link->network);
1879
1dc24d5f 1880 r = sd_dhcp_lease_save(link->dhcp_lease, link->lease_file);
fe8db0c5 1881 if (r < 0)
c2d6bd61 1882 goto fail;
fe8db0c5 1883
7374f9d8 1884 fprintf(f,
b0e39c82
TG
1885 "DHCP_LEASE=%s\n",
1886 link->lease_file);
deb2e523 1887 } else
68a8723c 1888 unlink(link->lease_file);
fe8db0c5 1889
49699bac
SS
1890 if (link->lldp) {
1891 assert(link->network);
1892
1893 r = sd_lldp_save(link->lldp, link->lldp_file);
1894 if (r < 0)
1895 goto fail;
1896
1897 fprintf(f,
1898 "LLDP_FILE=%s\n",
1899 link->lldp_file);
1900 } else
1901 unlink(link->lldp_file);
1902
c2d6bd61
LP
1903 r = fflush_and_check(f);
1904 if (r < 0)
1905 goto fail;
fe8db0c5 1906
c2d6bd61 1907 if (rename(temp_path, link->state_file) < 0) {
fe8db0c5 1908 r = -errno;
c2d6bd61 1909 goto fail;
fe8db0c5
TG
1910 }
1911
c2d6bd61 1912 return 0;
c2d6bd61 1913fail:
79008bdd 1914 log_link_error(link, "Failed to save link data to %s: %s", link->state_file, strerror(-r));
c2d6bd61
LP
1915 unlink(link->state_file);
1916 unlink(temp_path);
fe8db0c5
TG
1917 return r;
1918}
1919
1920static const char* const link_state_table[_LINK_STATE_MAX] = {
8434fd5c 1921 [LINK_STATE_PENDING] = "pending",
fe8db0c5
TG
1922 [LINK_STATE_ENSLAVING] = "configuring",
1923 [LINK_STATE_SETTING_ADDRESSES] = "configuring",
1924 [LINK_STATE_SETTING_ROUTES] = "configuring",
1925 [LINK_STATE_CONFIGURED] = "configured",
57bd6899 1926 [LINK_STATE_UNMANAGED] = "unmanaged",
fe8db0c5 1927 [LINK_STATE_FAILED] = "failed",
370e9930 1928 [LINK_STATE_LINGER] = "linger",
fe8db0c5
TG
1929};
1930
1931DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState);
e375dcde
TG
1932
1933static const char* const link_operstate_table[_LINK_OPERSTATE_MAX] = {
d3df0e39
TG
1934 [LINK_OPERSTATE_OFF] = "off",
1935 [LINK_OPERSTATE_NO_CARRIER] = "no-carrier",
e375dcde
TG
1936 [LINK_OPERSTATE_DORMANT] = "dormant",
1937 [LINK_OPERSTATE_CARRIER] = "carrier",
1938 [LINK_OPERSTATE_DEGRADED] = "degraded",
1939 [LINK_OPERSTATE_ROUTABLE] = "routable",
1940};
1941
1942DEFINE_STRING_TABLE_LOOKUP(link_operstate, LinkOperationalState);