]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-state-file.c
network: add an online state for links and manager
[thirdparty/systemd.git] / src / network / networkd-state-file.c
CommitLineData
3b5a4fc6
YW
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <netinet/in.h>
4#include <linux/if.h>
5
6#include "alloc-util.h"
7#include "dns-domain.h"
8#include "fd-util.h"
9#include "fileio.h"
10#include "fs-util.h"
11#include "network-internal.h"
12#include "networkd-link.h"
13#include "networkd-manager-bus.h"
14#include "networkd-manager.h"
15#include "networkd-network.h"
16#include "networkd-state-file.h"
17#include "ordered-set.h"
18#include "set.h"
19#include "strv.h"
20#include "tmpfile-util.h"
21
cf453507 22static int ordered_set_put_dns_server(OrderedSet **s, int ifindex, struct in_addr_full *dns) {
3b5a4fc6
YW
23 const char *p;
24 int r;
25
26 assert(s);
27 assert(dns);
28
29 if (dns->ifindex != 0 && dns->ifindex != ifindex)
30 return 0;
31
32 p = in_addr_full_to_string(dns);
33 if (!p)
34 return 0;
35
36 r = ordered_set_put_strdup(s, p);
37 if (r == -EEXIST)
38 return 0;
39
40 return r;
41}
42
cf453507 43static int ordered_set_put_dns_servers(OrderedSet **s, int ifindex, struct in_addr_full **dns, unsigned n) {
3b5a4fc6
YW
44 int r, c = 0;
45
46 assert(s);
47 assert(dns || n == 0);
48
49 for (unsigned i = 0; i < n; i++) {
50 r = ordered_set_put_dns_server(s, ifindex, dns[i]);
51 if (r < 0)
52 return r;
53
54 c += r;
55 }
56
57 return c;
58}
59
cf453507
YW
60static int ordered_set_put_in4_addr(OrderedSet **s, const struct in_addr *address) {
61 _cleanup_free_ char *p = NULL;
3b5a4fc6
YW
62 int r;
63
64 assert(s);
65 assert(address);
66
67 r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
68 if (r < 0)
69 return r;
70
cf453507
YW
71 r = ordered_set_ensure_allocated(s, &string_hash_ops_free);
72 if (r < 0)
73 return r;
74
75 r = ordered_set_consume(*s, TAKE_PTR(p));
3b5a4fc6
YW
76 if (r == -EEXIST)
77 return 0;
78
79 return r;
80}
81
44e1f7e3 82static int ordered_set_put_in4_addrv(
cf453507 83 OrderedSet **s,
44e1f7e3
YW
84 const struct in_addr *addresses,
85 size_t n,
86 bool (*predicate)(const struct in_addr *addr)) {
87
3b5a4fc6
YW
88 int r, c = 0;
89
90 assert(s);
91 assert(n == 0 || addresses);
92
93 for (size_t i = 0; i < n; i++) {
94 if (predicate && !predicate(&addresses[i]))
95 continue;
96 r = ordered_set_put_in4_addr(s, addresses+i);
97 if (r < 0)
98 return r;
99
100 c += r;
101 }
102
103 return c;
104}
105
106int manager_save(Manager *m) {
cf453507 107 _cleanup_ordered_set_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL;
bcdcc596 108 const char *operstate_str, *carrier_state_str, *address_state_str, *ipv4_address_state_str, *ipv6_address_state_str, *online_state_str;
3b5a4fc6
YW
109 LinkOperationalState operstate = LINK_OPERSTATE_OFF;
110 LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
8430841b
L
111 LinkAddressState ipv4_address_state = LINK_ADDRESS_STATE_OFF, ipv6_address_state = LINK_ADDRESS_STATE_OFF,
112 address_state = LINK_ADDRESS_STATE_OFF;
bcdcc596
113 LinkOnlineState online_state;
114 size_t links_offline = 0, links_online = 0;
d23a66f2 115 _cleanup_(unlink_and_freep) char *temp_path = NULL;
3b5a4fc6
YW
116 _cleanup_strv_free_ char **p = NULL;
117 _cleanup_fclose_ FILE *f = NULL;
118 Link *link;
119 int r;
120
121 assert(m);
122 assert(m->state_file);
123
3b5a4fc6
YW
124 HASHMAP_FOREACH(link, m->links) {
125 const struct in_addr *addresses;
126
127 if (link->flags & IFF_LOOPBACK)
128 continue;
129
90afec18
YW
130 operstate = MAX(operstate, link->operstate);
131 carrier_state = MAX(carrier_state, link->carrier_state);
132 address_state = MAX(address_state, link->address_state);
133 ipv4_address_state = MAX(ipv4_address_state, link->ipv4_address_state);
134 ipv6_address_state = MAX(ipv6_address_state, link->ipv6_address_state);
8430841b 135
3b5a4fc6
YW
136 if (!link->network)
137 continue;
138
bcdcc596
139 if (link->network->required_for_online) {
140 if (link->online_state == LINK_ONLINE_STATE_OFFLINE)
141 links_offline++;
142 else if (link->online_state == LINK_ONLINE_STATE_ONLINE)
143 links_online++;
144 }
145
3b5a4fc6 146 /* First add the static configured entries */
f5fbe71d 147 if (link->n_dns != UINT_MAX)
cf453507 148 r = ordered_set_put_dns_servers(&dns, link->ifindex, link->dns, link->n_dns);
3b5a4fc6 149 else
cf453507 150 r = ordered_set_put_dns_servers(&dns, link->ifindex, link->network->dns, link->network->n_dns);
3b5a4fc6
YW
151 if (r < 0)
152 return r;
153
cf453507 154 r = ordered_set_put_strdupv(&ntp, link->ntp ?: link->network->ntp);
3b5a4fc6
YW
155 if (r < 0)
156 return r;
157
cf453507 158 r = ordered_set_put_string_set(&search_domains, link->search_domains ?: link->network->search_domains);
3b5a4fc6
YW
159 if (r < 0)
160 return r;
161
cf453507 162 r = ordered_set_put_string_set(&route_domains, link->route_domains ?: link->network->route_domains);
3b5a4fc6
YW
163 if (r < 0)
164 return r;
165
166 if (!link->dhcp_lease)
167 continue;
168
169 /* Secondly, add the entries acquired via DHCP */
170 if (link->network->dhcp_use_dns) {
171 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
172 if (r > 0) {
cf453507 173 r = ordered_set_put_in4_addrv(&dns, addresses, r, in4_addr_is_non_local);
3b5a4fc6
YW
174 if (r < 0)
175 return r;
176 } else if (r < 0 && r != -ENODATA)
177 return r;
178 }
179
180 if (link->network->dhcp_use_ntp) {
181 r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
182 if (r > 0) {
cf453507 183 r = ordered_set_put_in4_addrv(&ntp, addresses, r, in4_addr_is_non_local);
3b5a4fc6
YW
184 if (r < 0)
185 return r;
186 } else if (r < 0 && r != -ENODATA)
187 return r;
188 }
189
190 if (link->network->dhcp_use_sip) {
191 r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
192 if (r > 0) {
cf453507 193 r = ordered_set_put_in4_addrv(&sip, addresses, r, in4_addr_is_non_local);
3b5a4fc6
YW
194 if (r < 0)
195 return r;
196 } else if (r < 0 && r != -ENODATA)
197 return r;
198 }
199
200 if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
cf453507 201 OrderedSet **target_domains;
3b5a4fc6
YW
202 const char *domainname;
203 char **domains = NULL;
204
cf453507 205 target_domains = (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) ? &search_domains : &route_domains;
3b5a4fc6
YW
206 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
207 if (r >= 0) {
208 r = ordered_set_put_strdup(target_domains, domainname);
209 if (r < 0)
210 return r;
211 } else if (r != -ENODATA)
212 return r;
213
214 r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains);
215 if (r >= 0) {
216 r = ordered_set_put_strdupv(target_domains, domains);
217 if (r < 0)
218 return r;
219 } else if (r != -ENODATA)
220 return r;
221 }
222 }
223
224 if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED)
225 carrier_state = LINK_CARRIER_STATE_CARRIER;
226
bcdcc596
227 online_state = links_online > 0 ?
228 (links_offline > 0 ? LINK_ONLINE_STATE_PARTIAL : LINK_ONLINE_STATE_ONLINE) :
229 (links_offline > 0 ? LINK_ONLINE_STATE_OFFLINE : _LINK_ONLINE_STATE_INVALID);
230
3b5a4fc6
YW
231 operstate_str = link_operstate_to_string(operstate);
232 assert(operstate_str);
233
234 carrier_state_str = link_carrier_state_to_string(carrier_state);
235 assert(carrier_state_str);
236
237 address_state_str = link_address_state_to_string(address_state);
238 assert(address_state_str);
239
8430841b
L
240 ipv4_address_state_str = link_address_state_to_string(ipv4_address_state);
241 assert(ipv4_address_state_str);
242
243 ipv6_address_state_str = link_address_state_to_string(ipv6_address_state);
244 assert(ipv6_address_state_str);
245
3b5a4fc6
YW
246 r = fopen_temporary(m->state_file, &f, &temp_path);
247 if (r < 0)
248 return r;
249
250 (void) fchmod(fileno(f), 0644);
251
252 fprintf(f,
253 "# This is private data. Do not parse.\n"
254 "OPER_STATE=%s\n"
255 "CARRIER_STATE=%s\n"
8430841b
L
256 "ADDRESS_STATE=%s\n"
257 "IPV4_ADDRESS_STATE=%s\n"
258 "IPV6_ADDRESS_STATE=%s\n",
259 operstate_str, carrier_state_str, address_state_str, ipv4_address_state_str, ipv6_address_state_str);
3b5a4fc6 260
bcdcc596
261 online_state_str = link_online_state_to_string(online_state);
262 if (online_state_str)
263 fprintf(f, "ONLINE_STATE=%s\n", online_state_str);
264
3b5a4fc6
YW
265 ordered_set_print(f, "DNS=", dns);
266 ordered_set_print(f, "NTP=", ntp);
267 ordered_set_print(f, "SIP=", sip);
268 ordered_set_print(f, "DOMAINS=", search_domains);
269 ordered_set_print(f, "ROUTE_DOMAINS=", route_domains);
270
271 r = fflush_and_check(f);
272 if (r < 0)
d23a66f2 273 return r;
3b5a4fc6
YW
274
275 r = conservative_rename(temp_path, m->state_file);
276 if (r < 0)
d23a66f2
YW
277 return r;
278
279 temp_path = mfree(temp_path);
3b5a4fc6
YW
280
281 if (m->operational_state != operstate) {
282 m->operational_state = operstate;
283 if (strv_extend(&p, "OperationalState") < 0)
284 log_oom();
285 }
286
287 if (m->carrier_state != carrier_state) {
288 m->carrier_state = carrier_state;
289 if (strv_extend(&p, "CarrierState") < 0)
290 log_oom();
291 }
292
293 if (m->address_state != address_state) {
294 m->address_state = address_state;
295 if (strv_extend(&p, "AddressState") < 0)
296 log_oom();
297 }
298
8430841b
L
299 if (m->ipv4_address_state != ipv4_address_state) {
300 m->ipv4_address_state = ipv4_address_state;
301 if (strv_extend(&p, "IPv4AddressState") < 0)
302 log_oom();
303 }
304
305 if (m->ipv6_address_state != ipv6_address_state) {
306 m->ipv6_address_state = ipv6_address_state;
307 if (strv_extend(&p, "IPv6AddressState") < 0)
308 log_oom();
309 }
310
bcdcc596
311 if (m->online_state != online_state) {
312 m->online_state = online_state;
313 if (strv_extend(&p, "OnlineState") < 0)
314 log_oom();
315 }
316
3b5a4fc6
YW
317 if (p) {
318 r = manager_send_changed_strv(m, p);
319 if (r < 0)
d23a66f2 320 log_warning_errno(r, "Could not emit changed properties, ignoring: %m");
3b5a4fc6
YW
321 }
322
323 m->dirty = false;
324
325 return 0;
3b5a4fc6
YW
326}
327
328static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
329 bool space = false;
330 Link *link;
331
332 assert(f);
333 assert(prefix);
334
335 if (hashmap_isempty(h))
336 return;
337
338 fputs(prefix, f);
339 HASHMAP_FOREACH(link, h) {
340 if (space)
341 fputc(' ', f);
342
343 fprintf(f, "%i", link->ifindex);
344 space = true;
345 }
346
347 fputc('\n', f);
348}
349
350static void link_save_dns(Link *link, FILE *f, struct in_addr_full **dns, unsigned n_dns, bool *space) {
351 for (unsigned j = 0; j < n_dns; j++) {
352 const char *str;
353
354 if (dns[j]->ifindex != 0 && dns[j]->ifindex != link->ifindex)
355 continue;
356
357 str = in_addr_full_to_string(dns[j]);
358 if (!str)
359 continue;
360
361 if (*space)
362 fputc(' ', f);
363 fputs(str, f);
364 *space = true;
365 }
366}
367
368static void serialize_addresses(
369 FILE *f,
370 const char *lvalue,
371 bool *space,
372 char **addresses,
373 sd_dhcp_lease *lease,
374 bool conditional,
375 sd_dhcp_lease_server_type_t what,
376 sd_dhcp6_lease *lease6,
377 bool conditional6,
378 int (*lease6_get_addr)(sd_dhcp6_lease*, const struct in6_addr**),
379 int (*lease6_get_fqdn)(sd_dhcp6_lease*, char ***)) {
3b5a4fc6
YW
380
381 bool _space = false;
44e1f7e3
YW
382 int r;
383
3b5a4fc6
YW
384 if (!space)
385 space = &_space;
386
387 if (lvalue)
388 fprintf(f, "%s=", lvalue);
389 fputstrv(f, addresses, NULL, space);
390
391 if (lease && conditional) {
392 const struct in_addr *lease_addresses;
393
394 r = sd_dhcp_lease_get_servers(lease, what, &lease_addresses);
395 if (r > 0)
396 serialize_in_addrs(f, lease_addresses, r, space, in4_addr_is_non_local);
397 }
398
399 if (lease6 && conditional6 && lease6_get_addr) {
400 const struct in6_addr *in6_addrs;
401
402 r = lease6_get_addr(lease6, &in6_addrs);
403 if (r > 0)
404 serialize_in6_addrs(f, in6_addrs, r, space);
405 }
406
407 if (lease6 && conditional6 && lease6_get_fqdn) {
408 char **in6_hosts;
409
410 r = lease6_get_fqdn(lease6, &in6_hosts);
411 if (r > 0)
412 fputstrv(f, in6_hosts, NULL, space);
413 }
414
415 if (lvalue)
416 fputc('\n', f);
417}
418
419int link_save(Link *link) {
8430841b 420 const char *admin_state, *oper_state, *carrier_state, *address_state, *ipv4_address_state, *ipv6_address_state;
d23a66f2 421 _cleanup_(unlink_and_freep) char *temp_path = NULL;
3b5a4fc6
YW
422 _cleanup_fclose_ FILE *f = NULL;
423 int r;
424
425 assert(link);
426 assert(link->state_file);
427 assert(link->lease_file);
428 assert(link->manager);
429
d23a66f2 430 if (link->state == LINK_STATE_LINGER)
3b5a4fc6 431 return 0;
3b5a4fc6
YW
432
433 link_lldp_save(link);
434
435 admin_state = link_state_to_string(link->state);
436 assert(admin_state);
437
438 oper_state = link_operstate_to_string(link->operstate);
439 assert(oper_state);
440
441 carrier_state = link_carrier_state_to_string(link->carrier_state);
442 assert(carrier_state);
443
444 address_state = link_address_state_to_string(link->address_state);
445 assert(address_state);
446
8430841b
L
447 ipv4_address_state = link_address_state_to_string(link->ipv4_address_state);
448 assert(ipv4_address_state);
449
450 ipv6_address_state = link_address_state_to_string(link->ipv6_address_state);
451 assert(ipv6_address_state);
452
3b5a4fc6
YW
453 r = fopen_temporary(link->state_file, &f, &temp_path);
454 if (r < 0)
d23a66f2 455 return r;
3b5a4fc6
YW
456
457 (void) fchmod(fileno(f), 0644);
458
459 fprintf(f,
460 "# This is private data. Do not parse.\n"
461 "ADMIN_STATE=%s\n"
462 "OPER_STATE=%s\n"
463 "CARRIER_STATE=%s\n"
8430841b
L
464 "ADDRESS_STATE=%s\n"
465 "IPV4_ADDRESS_STATE=%s\n"
466 "IPV6_ADDRESS_STATE=%s\n",
467 admin_state, oper_state, carrier_state, address_state, ipv4_address_state, ipv6_address_state);
3b5a4fc6
YW
468
469 if (link->network) {
470 char **dhcp6_domains = NULL, **dhcp_domains = NULL;
bcdcc596 471 const char *dhcp_domainname = NULL, *online_state, *p;
3b5a4fc6
YW
472 bool space;
473
bcdcc596
474 online_state = link_online_state_to_string(link->online_state);
475 if (online_state)
476 fprintf(f, "ONLINE_STATE=%s\n", online_state);
477
3b5a4fc6
YW
478 fprintf(f, "REQUIRED_FOR_ONLINE=%s\n",
479 yes_no(link->network->required_for_online));
480
481 LinkOperationalStateRange st = link->network->required_operstate_for_online;
482 fprintf(f, "REQUIRED_OPER_STATE_FOR_ONLINE=%s%s%s\n",
483 strempty(link_operstate_to_string(st.min)),
484 st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? ":" : "",
485 st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? strempty(link_operstate_to_string(st.max)) : "");
486
8430841b
L
487 fprintf(f, "REQUIRED_FAMILY_FOR_ONLINE=%s\n",
488 link_required_address_family_to_string(link->network->required_family_for_online));
489
3b5a4fc6
YW
490 fprintf(f, "ACTIVATION_POLICY=%s\n",
491 activation_policy_to_string(link->network->activation_policy));
492
493 fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
494
495 /************************************************************/
496
497 fputs("DNS=", f);
498 space = false;
f5fbe71d 499 if (link->n_dns != UINT_MAX)
3b5a4fc6
YW
500 link_save_dns(link, f, link->dns, link->n_dns, &space);
501 else
502 link_save_dns(link, f, link->network->dns, link->network->n_dns, &space);
503
504 serialize_addresses(f, NULL, &space,
505 NULL,
506 link->dhcp_lease,
507 link->network->dhcp_use_dns,
508 SD_DHCP_LEASE_DNS,
509 link->dhcp6_lease,
510 link->network->dhcp6_use_dns,
511 sd_dhcp6_lease_get_dns,
512 NULL);
513
514 /* Make sure to flush out old entries before we use the NDisc data */
515 ndisc_vacuum(link);
516
517 if (link->network->ipv6_accept_ra_use_dns && link->ndisc_rdnss) {
518 NDiscRDNSS *dd;
519
520 SET_FOREACH(dd, link->ndisc_rdnss)
521 serialize_in6_addrs(f, &dd->address, 1, &space);
522 }
523
524 fputc('\n', f);
525
526 /************************************************************/
527
528 serialize_addresses(f, "NTP", NULL,
529 link->ntp ?: link->network->ntp,
530 link->dhcp_lease,
531 link->network->dhcp_use_ntp,
532 SD_DHCP_LEASE_NTP,
533 link->dhcp6_lease,
534 link->network->dhcp6_use_ntp,
535 sd_dhcp6_lease_get_ntp_addrs,
536 sd_dhcp6_lease_get_ntp_fqdn);
537
538 serialize_addresses(f, "SIP", NULL,
539 NULL,
540 link->dhcp_lease,
541 link->network->dhcp_use_sip,
542 SD_DHCP_LEASE_SIP,
543 NULL, false, NULL, NULL);
544
545 /************************************************************/
546
f225a338
YW
547 if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO && link->dhcp_lease) {
548 (void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname);
549 (void) sd_dhcp_lease_get_search_domains(link->dhcp_lease, &dhcp_domains);
3b5a4fc6 550 }
f225a338
YW
551 if (link->network->dhcp6_use_domains != DHCP_USE_DOMAINS_NO && link->dhcp6_lease)
552 (void) sd_dhcp6_lease_get_domains(link->dhcp6_lease, &dhcp6_domains);
3b5a4fc6
YW
553
554 fputs("DOMAINS=", f);
555 space = false;
556 ORDERED_SET_FOREACH(p, link->search_domains ?: link->network->search_domains)
557 fputs_with_space(f, p, NULL, &space);
558
559 if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) {
560 if (dhcp_domainname)
561 fputs_with_space(f, dhcp_domainname, NULL, &space);
562 if (dhcp_domains)
563 fputstrv(f, dhcp_domains, NULL, &space);
564 if (dhcp6_domains)
565 fputstrv(f, dhcp6_domains, NULL, &space);
566 }
567
568 if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_YES) {
569 NDiscDNSSL *dd;
570
571 SET_FOREACH(dd, link->ndisc_dnssl)
572 fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
573 }
574
575 fputc('\n', f);
576
577 /************************************************************/
578
579 fputs("ROUTE_DOMAINS=", f);
580 space = false;
581 ORDERED_SET_FOREACH(p, link->route_domains ?: link->network->route_domains)
582 fputs_with_space(f, p, NULL, &space);
583
584 if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) {
585 if (dhcp_domainname)
586 fputs_with_space(f, dhcp_domainname, NULL, &space);
587 if (dhcp_domains)
588 fputstrv(f, dhcp_domains, NULL, &space);
589 if (dhcp6_domains)
590 fputstrv(f, dhcp6_domains, NULL, &space);
591 }
592
593 if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_ROUTE) {
594 NDiscDNSSL *dd;
595
596 SET_FOREACH(dd, link->ndisc_dnssl)
597 fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
598 }
599
600 fputc('\n', f);
601
602 /************************************************************/
603
604 fprintf(f, "LLMNR=%s\n",
605 resolve_support_to_string(link->llmnr >= 0 ? link->llmnr : link->network->llmnr));
606
607 /************************************************************/
608
609 fprintf(f, "MDNS=%s\n",
610 resolve_support_to_string(link->mdns >= 0 ? link->mdns : link->network->mdns));
611
612 /************************************************************/
613
614 int dns_default_route =
615 link->dns_default_route >= 0 ? link->dns_default_route :
616 link->network->dns_default_route;
617 if (dns_default_route >= 0)
618 fprintf(f, "DNS_DEFAULT_ROUTE=%s\n", yes_no(dns_default_route));
619
620 /************************************************************/
621
622 DnsOverTlsMode dns_over_tls_mode =
623 link->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID ? link->dns_over_tls_mode :
624 link->network->dns_over_tls_mode;
625 if (dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID)
626 fprintf(f, "DNS_OVER_TLS=%s\n", dns_over_tls_mode_to_string(dns_over_tls_mode));
627
628 /************************************************************/
629
630 DnssecMode dnssec_mode =
631 link->dnssec_mode != _DNSSEC_MODE_INVALID ? link->dnssec_mode :
632 link->network->dnssec_mode;
633 if (dnssec_mode != _DNSSEC_MODE_INVALID)
634 fprintf(f, "DNSSEC=%s\n", dnssec_mode_to_string(dnssec_mode));
635
636 /************************************************************/
637
638 Set *nta_anchors = link->dnssec_negative_trust_anchors;
639 if (set_isempty(nta_anchors))
640 nta_anchors = link->network->dnssec_negative_trust_anchors;
641
642 if (!set_isempty(nta_anchors)) {
643 const char *n;
644
645 fputs("DNSSEC_NTA=", f);
646 space = false;
647 SET_FOREACH(n, nta_anchors)
648 fputs_with_space(f, n, NULL, &space);
649 fputc('\n', f);
650 }
651 }
652
653 print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links);
654 print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links);
655
656 if (link->dhcp_lease) {
657 r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
658 if (r < 0)
d23a66f2 659 return r;
3b5a4fc6
YW
660
661 fprintf(f,
662 "DHCP_LEASE=%s\n",
663 link->lease_file);
664 } else
665 (void) unlink(link->lease_file);
666
667 r = link_serialize_dhcp6_client(link, f);
668 if (r < 0)
d23a66f2 669 return r;
3b5a4fc6
YW
670
671 r = fflush_and_check(f);
672 if (r < 0)
d23a66f2 673 return r;
3b5a4fc6
YW
674
675 r = conservative_rename(temp_path, link->state_file);
676 if (r < 0)
d23a66f2 677 return r;
3b5a4fc6 678
d23a66f2 679 temp_path = mfree(temp_path);
3b5a4fc6 680
d23a66f2 681 return 0;
3b5a4fc6
YW
682}
683
684void link_dirty(Link *link) {
685 int r;
686
687 assert(link);
688 assert(link->manager);
689
690 /* The serialized state in /run is no longer up-to-date. */
691
692 /* Also mark manager dirty as link is dirty */
693 link->manager->dirty = true;
694
695 r = set_ensure_put(&link->manager->dirty_links, NULL, link);
696 if (r <= 0)
697 /* Ignore allocation errors and don't take another ref if the link was already dirty */
698 return;
699 link_ref(link);
700}
701
702void link_clean(Link *link) {
703 assert(link);
704 assert(link->manager);
705
706 /* The serialized state in /run is up-to-date */
707
708 link_unref(set_remove(link->manager->dirty_links, link));
709}
710
711int link_save_and_clean(Link *link) {
712 int r;
713
714 r = link_save(link);
715 if (r < 0)
716 return r;
717
718 link_clean(link);
719 return 0;
720}