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