1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2017 Intel Corporation. All rights reserved.
6 #include <netinet/icmp6.h>
9 #include "dns-domain.h"
10 #include "networkd-link.h"
11 #include "networkd-manager.h"
12 #include "networkd-network.h"
13 #include "networkd-queue.h"
14 #include "networkd-radv.h"
15 #include "parse-util.h"
16 #include "string-util.h"
17 #include "string-table.h"
20 Prefix
*prefix_free(Prefix
*prefix
) {
24 if (prefix
->network
) {
25 assert(prefix
->section
);
26 hashmap_remove(prefix
->network
->prefixes_by_section
, prefix
->section
);
29 network_config_section_free(prefix
->section
);
30 sd_radv_prefix_unref(prefix
->radv_prefix
);
35 DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix
, prefix_free
);
37 static int prefix_new(Prefix
**ret
) {
38 _cleanup_(prefix_freep
) Prefix
*prefix
= NULL
;
40 prefix
= new0(Prefix
, 1);
44 if (sd_radv_prefix_new(&prefix
->radv_prefix
) < 0)
47 *ret
= TAKE_PTR(prefix
);
52 static int prefix_new_static(Network
*network
, const char *filename
, unsigned section_line
, Prefix
**ret
) {
53 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
54 _cleanup_(prefix_freep
) Prefix
*prefix
= NULL
;
60 assert(section_line
> 0);
62 r
= network_config_section_new(filename
, section_line
, &n
);
66 prefix
= hashmap_get(network
->prefixes_by_section
, n
);
68 *ret
= TAKE_PTR(prefix
);
72 r
= prefix_new(&prefix
);
76 prefix
->network
= network
;
77 prefix
->section
= TAKE_PTR(n
);
79 r
= hashmap_ensure_put(&network
->prefixes_by_section
, &network_config_hash_ops
, prefix
->section
, prefix
);
83 *ret
= TAKE_PTR(prefix
);
88 RoutePrefix
*route_prefix_free(RoutePrefix
*prefix
) {
92 if (prefix
->network
) {
93 assert(prefix
->section
);
94 hashmap_remove(prefix
->network
->route_prefixes_by_section
, prefix
->section
);
97 network_config_section_free(prefix
->section
);
98 sd_radv_route_prefix_unref(prefix
->radv_route_prefix
);
100 return mfree(prefix
);
103 DEFINE_NETWORK_SECTION_FUNCTIONS(RoutePrefix
, route_prefix_free
);
105 static int route_prefix_new(RoutePrefix
**ret
) {
106 _cleanup_(route_prefix_freep
) RoutePrefix
*prefix
= NULL
;
108 prefix
= new0(RoutePrefix
, 1);
112 if (sd_radv_route_prefix_new(&prefix
->radv_route_prefix
) < 0)
115 *ret
= TAKE_PTR(prefix
);
120 static int route_prefix_new_static(Network
*network
, const char *filename
, unsigned section_line
, RoutePrefix
**ret
) {
121 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
122 _cleanup_(route_prefix_freep
) RoutePrefix
*prefix
= NULL
;
128 assert(section_line
> 0);
130 r
= network_config_section_new(filename
, section_line
, &n
);
134 prefix
= hashmap_get(network
->route_prefixes_by_section
, n
);
136 *ret
= TAKE_PTR(prefix
);
140 r
= route_prefix_new(&prefix
);
144 prefix
->network
= network
;
145 prefix
->section
= TAKE_PTR(n
);
147 r
= hashmap_ensure_put(&network
->route_prefixes_by_section
, &network_config_hash_ops
, prefix
->section
, prefix
);
151 *ret
= TAKE_PTR(prefix
);
156 void network_drop_invalid_prefixes(Network
*network
) {
161 HASHMAP_FOREACH(prefix
, network
->prefixes_by_section
)
162 if (section_is_invalid(prefix
->section
))
166 void network_drop_invalid_route_prefixes(Network
*network
) {
171 HASHMAP_FOREACH(prefix
, network
->route_prefixes_by_section
)
172 if (section_is_invalid(prefix
->section
))
173 route_prefix_free(prefix
);
176 void network_adjust_radv(Network
*network
) {
179 /* After this function is called, network->router_prefix_delegation can be treated as a boolean. */
181 if (network
->dhcp6_pd
< 0)
182 /* For backward compatibility. */
183 network
->dhcp6_pd
= FLAGS_SET(network
->router_prefix_delegation
, RADV_PREFIX_DELEGATION_DHCP6
);
185 if (!FLAGS_SET(network
->link_local
, ADDRESS_FAMILY_IPV6
)) {
186 if (network
->router_prefix_delegation
!= RADV_PREFIX_DELEGATION_NONE
)
187 log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link local addressing is disabled. "
188 "Disabling IPv6PrefixDelegation=.", network
->filename
);
190 network
->router_prefix_delegation
= RADV_PREFIX_DELEGATION_NONE
;
193 if (network
->router_prefix_delegation
== RADV_PREFIX_DELEGATION_NONE
) {
194 network
->n_router_dns
= 0;
195 network
->router_dns
= mfree(network
->router_dns
);
196 network
->router_search_domains
= ordered_set_free(network
->router_search_domains
);
199 if (!FLAGS_SET(network
->router_prefix_delegation
, RADV_PREFIX_DELEGATION_STATIC
)) {
200 network
->prefixes_by_section
= hashmap_free_with_destructor(network
->prefixes_by_section
, prefix_free
);
201 network
->route_prefixes_by_section
= hashmap_free_with_destructor(network
->route_prefixes_by_section
, route_prefix_free
);
205 int config_parse_prefix(
207 const char *filename
,
210 unsigned section_line
,
217 Network
*network
= userdata
;
218 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
219 uint8_t prefixlen
= 64;
220 union in_addr_union in6addr
;
229 r
= prefix_new_static(network
, filename
, section_line
, &p
);
233 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &in6addr
, &prefixlen
);
235 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Prefix is invalid, ignoring assignment: %s", rvalue
);
239 r
= sd_radv_prefix_set_prefix(p
->radv_prefix
, &in6addr
.in6
, prefixlen
);
241 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to set radv prefix, ignoring assignment: %s", rvalue
);
250 int config_parse_prefix_flags(
252 const char *filename
,
255 unsigned section_line
,
262 Network
*network
= userdata
;
263 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
272 r
= prefix_new_static(network
, filename
, section_line
, &p
);
276 r
= parse_boolean(rvalue
);
278 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse %s=, ignoring assignment: %s", lvalue
, rvalue
);
282 if (streq(lvalue
, "OnLink"))
283 r
= sd_radv_prefix_set_onlink(p
->radv_prefix
, r
);
284 else if (streq(lvalue
, "AddressAutoconfiguration"))
285 r
= sd_radv_prefix_set_address_autoconfiguration(p
->radv_prefix
, r
);
287 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to set %s=, ignoring assignment: %m", lvalue
);
296 int config_parse_prefix_lifetime(
298 const char *filename
,
301 unsigned section_line
,
308 Network
*network
= userdata
;
309 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
319 r
= prefix_new_static(network
, filename
, section_line
, &p
);
323 r
= parse_sec(rvalue
, &usec
);
325 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Lifetime is invalid, ignoring assignment: %s", rvalue
);
329 /* a value of 0xffffffff represents infinity */
330 if (streq(lvalue
, "PreferredLifetimeSec"))
331 r
= sd_radv_prefix_set_preferred_lifetime(p
->radv_prefix
,
332 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
333 else if (streq(lvalue
, "ValidLifetimeSec"))
334 r
= sd_radv_prefix_set_valid_lifetime(p
->radv_prefix
,
335 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
337 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to set %s=, ignoring assignment: %m", lvalue
);
346 int config_parse_prefix_assign(
348 const char *filename
,
351 unsigned section_line
,
358 Network
*network
= userdata
;
359 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
368 r
= prefix_new_static(network
, filename
, section_line
, &p
);
372 r
= parse_boolean(rvalue
);
374 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
375 "Failed to parse %s=, ignoring assignment: %s",
386 int config_parse_prefix_metric(
388 const char *filename
,
391 unsigned section_line
,
398 Network
*network
= userdata
;
399 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
408 r
= prefix_new_static(network
, filename
, section_line
, &p
);
412 r
= safe_atou32(rvalue
, &p
->route_metric
);
414 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
415 "Failed to parse %s=, ignoring assignment: %s",
425 int config_parse_route_prefix(
427 const char *filename
,
430 unsigned section_line
,
437 Network
*network
= userdata
;
438 _cleanup_(route_prefix_free_or_set_invalidp
) RoutePrefix
*p
= NULL
;
439 uint8_t prefixlen
= 64;
440 union in_addr_union in6addr
;
449 r
= route_prefix_new_static(network
, filename
, section_line
, &p
);
453 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &in6addr
, &prefixlen
);
455 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Route prefix is invalid, ignoring assignment: %s", rvalue
);
459 r
= sd_radv_prefix_set_route_prefix(p
->radv_route_prefix
, &in6addr
.in6
, prefixlen
);
461 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to set route prefix, ignoring assignment: %m");
470 int config_parse_route_prefix_lifetime(
472 const char *filename
,
475 unsigned section_line
,
482 Network
*network
= userdata
;
483 _cleanup_(route_prefix_free_or_set_invalidp
) RoutePrefix
*p
= NULL
;
493 r
= route_prefix_new_static(network
, filename
, section_line
, &p
);
497 r
= parse_sec(rvalue
, &usec
);
499 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
500 "Route lifetime is invalid, ignoring assignment: %s", rvalue
);
504 /* a value of 0xffffffff represents infinity */
505 r
= sd_radv_route_prefix_set_lifetime(p
->radv_route_prefix
, DIV_ROUND_UP(usec
, USEC_PER_SEC
));
507 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
508 "Failed to set route lifetime, ignoring assignment: %m");
517 static int network_get_ipv6_dns(Network
*network
, struct in6_addr
**ret_addresses
, size_t *ret_size
) {
518 _cleanup_free_
struct in6_addr
*addresses
= NULL
;
519 size_t n_addresses
= 0;
522 assert(ret_addresses
);
525 for (size_t i
= 0; i
< network
->n_dns
; i
++) {
526 union in_addr_union
*addr
;
528 if (network
->dns
[i
]->family
!= AF_INET6
)
531 addr
= &network
->dns
[i
]->address
;
533 if (in_addr_is_null(AF_INET6
, addr
) ||
534 in_addr_is_link_local(AF_INET6
, addr
) ||
535 in_addr_is_localhost(AF_INET6
, addr
))
538 if (!GREEDY_REALLOC(addresses
, n_addresses
+ 1))
541 addresses
[n_addresses
++] = addr
->in6
;
544 *ret_addresses
= TAKE_PTR(addresses
);
545 *ret_size
= n_addresses
;
550 static int radv_set_dns(Link
*link
, Link
*uplink
) {
551 _cleanup_free_
struct in6_addr
*dns
= NULL
;
552 usec_t lifetime_usec
;
556 if (!link
->network
->router_emit_dns
)
559 if (link
->network
->router_dns
) {
562 dns
= new(struct in6_addr
, link
->network
->n_router_dns
);
567 for (size_t i
= 0; i
< link
->network
->n_router_dns
; i
++)
568 if (in6_addr_is_null(&link
->network
->router_dns
[i
])) {
569 if (in6_addr_is_set(&link
->ipv6ll_address
))
570 *(p
++) = link
->ipv6ll_address
;
572 *(p
++) = link
->network
->router_dns
[i
];
575 lifetime_usec
= link
->network
->router_dns_lifetime_usec
;
580 lifetime_usec
= SD_RADV_DEFAULT_DNS_LIFETIME_USEC
;
582 r
= network_get_ipv6_dns(link
->network
, &dns
, &n_dns
);
587 assert(uplink
->network
);
589 r
= network_get_ipv6_dns(uplink
->network
, &dns
, &n_dns
);
597 return sd_radv_set_rdnss(link
->radv
,
598 DIV_ROUND_UP(lifetime_usec
, USEC_PER_SEC
),
602 static int radv_set_domains(Link
*link
, Link
*uplink
) {
603 OrderedSet
*search_domains
;
604 usec_t lifetime_usec
;
605 _cleanup_free_
char **s
= NULL
; /* just free() because the strings are owned by the set */
607 if (!link
->network
->router_emit_domains
)
610 search_domains
= link
->network
->router_search_domains
;
611 lifetime_usec
= link
->network
->router_dns_lifetime_usec
;
616 lifetime_usec
= SD_RADV_DEFAULT_DNS_LIFETIME_USEC
;
618 search_domains
= link
->network
->search_domains
;
623 assert(uplink
->network
);
625 search_domains
= uplink
->network
->search_domains
;
633 s
= ordered_set_get_strv(search_domains
);
637 return sd_radv_set_dnssl(link
->radv
,
638 DIV_ROUND_UP(lifetime_usec
, USEC_PER_SEC
),
643 static int radv_find_uplink(Link
*link
, Link
**ret
) {
646 if (link
->network
->router_uplink_name
)
647 return link_get_by_name(link
->manager
, link
->network
->router_uplink_name
, ret
);
649 if (link
->network
->router_uplink_index
> 0)
650 return link_get_by_index(link
->manager
, link
->network
->router_uplink_index
, ret
);
652 if (link
->network
->router_uplink_index
== UPLINK_INDEX_AUTO
) {
653 /* It is not necessary to propagate error in automatic selection. */
654 if (manager_find_uplink(link
->manager
, AF_INET6
, link
, ret
) < 0)
663 static bool link_radv_enabled(Link
*link
) {
666 if (!link_ipv6ll_enabled(link
))
669 return link
->network
->router_prefix_delegation
;
672 static int radv_configure(Link
*link
) {
673 uint16_t router_lifetime
;
680 assert(link
->network
);
685 r
= sd_radv_new(&link
->radv
);
689 r
= sd_radv_attach_event(link
->radv
, link
->manager
->event
, 0);
693 r
= sd_radv_set_mac(link
->radv
, &link
->hw_addr
.ether
);
697 r
= sd_radv_set_ifindex(link
->radv
, link
->ifindex
);
701 r
= sd_radv_set_managed_information(link
->radv
, link
->network
->router_managed
);
705 r
= sd_radv_set_other_information(link
->radv
, link
->network
->router_other_information
);
709 /* a value of UINT16_MAX represents infinity, 0x0 means this host is not a router */
710 if (link
->network
->router_lifetime_usec
== USEC_INFINITY
)
711 router_lifetime
= UINT16_MAX
;
712 else if (link
->network
->router_lifetime_usec
> (UINT16_MAX
- 1) * USEC_PER_SEC
)
713 router_lifetime
= UINT16_MAX
- 1;
715 router_lifetime
= DIV_ROUND_UP(link
->network
->router_lifetime_usec
, USEC_PER_SEC
);
717 r
= sd_radv_set_router_lifetime(link
->radv
, router_lifetime
);
721 if (router_lifetime
> 0) {
722 r
= sd_radv_set_preference(link
->radv
, link
->network
->router_preference
);
727 HASHMAP_FOREACH(p
, link
->network
->prefixes_by_section
) {
728 r
= sd_radv_add_prefix(link
->radv
, p
->radv_prefix
, false);
732 log_link_warning_errno(link
, r
, "[IPv6Prefix] section configured without Prefix= setting, ignoring section.");
739 HASHMAP_FOREACH(q
, link
->network
->route_prefixes_by_section
) {
740 r
= sd_radv_add_route_prefix(link
->radv
, q
->radv_route_prefix
, false);
747 (void) radv_find_uplink(link
, &uplink
);
749 r
= radv_set_dns(link
, uplink
);
751 return log_link_debug_errno(link
, r
, "Could not set RA DNS: %m");
753 r
= radv_set_domains(link
, uplink
);
755 return log_link_debug_errno(link
, r
, "Could not set RA Domains: %m");
760 int radv_update_mac(Link
*link
) {
769 restart
= sd_radv_is_running(link
->radv
);
771 r
= sd_radv_stop(link
->radv
);
775 r
= sd_radv_set_mac(link
->radv
, &link
->hw_addr
.ether
);
780 r
= sd_radv_start(link
->radv
);
788 static int radv_is_ready_to_configure(Link
*link
) {
789 bool needs_uplink
= false;
793 assert(link
->network
);
795 if (!IN_SET(link
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
798 if (in6_addr_is_null(&link
->ipv6ll_address
))
801 if (link
->network
->router_emit_dns
&& !link
->network
->router_dns
) {
802 _cleanup_free_
struct in6_addr
*dns
= NULL
;
805 r
= network_get_ipv6_dns(link
->network
, &dns
, &n_dns
);
809 needs_uplink
= r
== 0;
812 if (link
->network
->router_emit_domains
&&
813 !link
->network
->router_search_domains
&&
814 !link
->network
->search_domains
)
820 if (radv_find_uplink(link
, &uplink
) < 0)
823 if (uplink
&& !uplink
->network
)
830 int request_process_radv(Request
*req
) {
836 assert(req
->type
== REQUEST_TYPE_RADV
);
840 r
= radv_is_ready_to_configure(link
);
844 r
= radv_configure(link
);
846 return log_link_warning_errno(link
, r
, "Failed to configure IPv6 Router Advertisement engine: %m");
848 if (link_has_carrier(link
)) {
849 r
= sd_radv_start(link
->radv
);
851 return log_link_warning_errno(link
, r
, "Failed to start IPv6 Router Advertisement engine: %m");
854 log_link_debug(link
, "IPv6 Router Advertisement engine is configured%s.",
855 link_has_carrier(link
) ? " and started." : "");
859 int link_request_radv(Link
*link
) {
864 if (!link_radv_enabled(link
))
870 r
= link_queue_request(link
, REQUEST_TYPE_RADV
, NULL
, false, NULL
, NULL
, NULL
);
872 return log_link_warning_errno(link
, r
, "Failed to request configuring of the IPv6 Router Advertisement engine: %m");
874 log_link_debug(link
, "Requested configuring of the IPv6 Router Advertisement engine.");
880 const struct in6_addr
*prefix
,
882 uint32_t lifetime_preferred
,
883 uint32_t lifetime_valid
) {
885 _cleanup_(sd_radv_prefix_unrefp
) sd_radv_prefix
*p
= NULL
;
893 r
= sd_radv_prefix_new(&p
);
897 r
= sd_radv_prefix_set_prefix(p
, prefix
, prefix_len
);
901 r
= sd_radv_prefix_set_preferred_lifetime(p
, lifetime_preferred
);
905 r
= sd_radv_prefix_set_valid_lifetime(p
, lifetime_valid
);
909 r
= sd_radv_add_prefix(link
->radv
, p
, true);
910 if (r
< 0 && r
!= -EEXIST
)
916 int config_parse_radv_dns(
918 const char *filename
,
921 unsigned section_line
,
935 if (isempty(rvalue
)) {
937 n
->router_dns
= mfree(n
->router_dns
);
941 for (const char *p
= rvalue
;;) {
942 _cleanup_free_
char *w
= NULL
;
943 union in_addr_union a
;
945 r
= extract_first_word(&p
, &w
, NULL
, 0);
949 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
950 "Failed to extract word, ignoring: %s", rvalue
);
956 if (streq(w
, "_link_local"))
959 r
= in_addr_from_string(AF_INET6
, w
, &a
);
961 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
962 "Failed to parse DNS server address, ignoring: %s", w
);
966 if (in_addr_is_null(AF_INET6
, &a
)) {
967 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
968 "DNS server address is null, ignoring: %s", w
);
974 m
= reallocarray(n
->router_dns
, n
->n_router_dns
+ 1, sizeof(struct in6_addr
));
978 m
[n
->n_router_dns
++] = a
.in6
;
983 int config_parse_radv_search_domains(
985 const char *filename
,
988 unsigned section_line
,
1002 if (isempty(rvalue
)) {
1003 n
->router_search_domains
= ordered_set_free(n
->router_search_domains
);
1007 for (const char *p
= rvalue
;;) {
1008 _cleanup_free_
char *w
= NULL
, *idna
= NULL
;
1010 r
= extract_first_word(&p
, &w
, NULL
, 0);
1014 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1015 "Failed to extract word, ignoring: %s", rvalue
);
1021 r
= dns_name_apply_idna(w
, &idna
);
1023 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1024 "Failed to apply IDNA to domain name '%s', ignoring: %m", w
);
1027 /* transfer ownership to simplify subsequent operations */
1030 r
= ordered_set_ensure_allocated(&n
->router_search_domains
, &string_hash_ops_free
);
1034 r
= ordered_set_consume(n
->router_search_domains
, TAKE_PTR(idna
));
1040 static const char * const radv_prefix_delegation_table
[_RADV_PREFIX_DELEGATION_MAX
] = {
1041 [RADV_PREFIX_DELEGATION_NONE
] = "no",
1042 [RADV_PREFIX_DELEGATION_STATIC
] = "static",
1043 [RADV_PREFIX_DELEGATION_DHCP6
] = "dhcpv6",
1044 [RADV_PREFIX_DELEGATION_BOTH
] = "yes",
1047 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
1048 radv_prefix_delegation
,
1049 RADVPrefixDelegation
,
1050 RADV_PREFIX_DELEGATION_BOTH
);
1052 int config_parse_router_prefix_delegation(
1054 const char *filename
,
1056 const char *section
,
1057 unsigned section_line
,
1064 RADVPrefixDelegation val
, *ra
= data
;
1072 if (streq(lvalue
, "IPv6SendRA")) {
1073 r
= parse_boolean(rvalue
);
1075 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1076 "Invalid %s= setting, ignoring assignment: %s", lvalue
, rvalue
);
1080 /* When IPv6SendRA= is enabled, only static prefixes are sent by default, and users
1081 * need to explicitly enable DHCPv6PrefixDelegation=. */
1082 *ra
= r
? RADV_PREFIX_DELEGATION_STATIC
: RADV_PREFIX_DELEGATION_NONE
;
1086 /* For backward compatibility */
1087 val
= radv_prefix_delegation_from_string(rvalue
);
1089 log_syntax(unit
, LOG_WARNING
, filename
, line
, val
,
1090 "Invalid %s= setting, ignoring assignment: %s", lvalue
, rvalue
);
1098 int config_parse_router_preference(
1100 const char *filename
,
1102 const char *section
,
1103 unsigned section_line
,
1110 Network
*network
= userdata
;
1118 if (streq(rvalue
, "high"))
1119 network
->router_preference
= SD_NDISC_PREFERENCE_HIGH
;
1120 else if (STR_IN_SET(rvalue
, "medium", "normal", "default"))
1121 network
->router_preference
= SD_NDISC_PREFERENCE_MEDIUM
;
1122 else if (streq(rvalue
, "low"))
1123 network
->router_preference
= SD_NDISC_PREFERENCE_LOW
;
1125 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1126 "Invalid router preference, ignoring assignment: %s", rvalue
);