1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Tom Gundersen <teg@jklm.no>
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <linux/icmpv6.h>
23 #include "alloc-util.h"
24 #include "conf-parser.h"
25 #include "in-addr-util.h"
26 #include "netlink-util.h"
27 #include "networkd-manager.h"
28 #include "networkd-route.h"
29 #include "parse-util.h"
31 #include "string-util.h"
32 #include "sysctl-util.h"
35 #define ROUTES_DEFAULT_MAX_PER_FAMILY 4096U
37 static unsigned routes_max(void) {
38 static thread_local
unsigned cached
= 0;
40 _cleanup_free_
char *s4
= NULL
, *s6
= NULL
;
41 unsigned val4
= ROUTES_DEFAULT_MAX_PER_FAMILY
, val6
= ROUTES_DEFAULT_MAX_PER_FAMILY
;
46 if (sysctl_read("net/ipv4/route/max_size", &s4
) >= 0) {
48 if (safe_atou(s4
, &val4
) >= 0 &&
50 /* This is the default "no limit" value in the kernel */
51 val4
= ROUTES_DEFAULT_MAX_PER_FAMILY
;
54 if (sysctl_read("net/ipv6/route/max_size", &s6
) >= 0) {
56 (void) safe_atou(s6
, &val6
);
59 cached
= MAX(ROUTES_DEFAULT_MAX_PER_FAMILY
, val4
) +
60 MAX(ROUTES_DEFAULT_MAX_PER_FAMILY
, val6
);
64 int route_new(Route
**ret
) {
65 _cleanup_route_free_ Route
*route
= NULL
;
67 route
= new0(Route
, 1);
71 route
->family
= AF_UNSPEC
;
72 route
->scope
= RT_SCOPE_UNIVERSE
;
73 route
->protocol
= RTPROT_UNSPEC
;
74 route
->type
= RTN_UNICAST
;
75 route
->table
= RT_TABLE_MAIN
;
76 route
->lifetime
= USEC_INFINITY
;
84 int route_new_static(Network
*network
, const char *filename
, unsigned section_line
, Route
**ret
) {
85 _cleanup_network_config_section_free_ NetworkConfigSection
*n
= NULL
;
86 _cleanup_route_free_ Route
*route
= NULL
;
91 assert(!!filename
== (section_line
> 0));
94 r
= network_config_section_new(filename
, section_line
, &n
);
98 route
= hashmap_get(network
->routes_by_section
, n
);
107 if (network
->n_static_routes
>= routes_max())
110 r
= route_new(&route
);
114 route
->protocol
= RTPROT_STATIC
;
120 r
= hashmap_put(network
->routes_by_section
, route
->section
, route
);
125 route
->network
= network
;
126 LIST_PREPEND(routes
, network
->static_routes
, route
);
127 network
->n_static_routes
++;
135 void route_free(Route
*route
) {
139 if (route
->network
) {
140 LIST_REMOVE(routes
, route
->network
->static_routes
, route
);
142 assert(route
->network
->n_static_routes
> 0);
143 route
->network
->n_static_routes
--;
146 hashmap_remove(route
->network
->routes_by_section
, route
->section
);
149 network_config_section_free(route
->section
);
152 set_remove(route
->link
->routes
, route
);
153 set_remove(route
->link
->routes_foreign
, route
);
156 sd_event_source_unref(route
->expire
);
161 static void route_hash_func(const void *b
, struct siphash
*state
) {
162 const Route
*route
= b
;
166 siphash24_compress(&route
->family
, sizeof(route
->family
), state
);
168 switch (route
->family
) {
171 /* Equality of routes are given by the 4-touple
172 (dst_prefix,dst_prefixlen,tos,priority,table) */
173 siphash24_compress(&route
->dst
, FAMILY_ADDRESS_SIZE(route
->family
), state
);
174 siphash24_compress(&route
->dst_prefixlen
, sizeof(route
->dst_prefixlen
), state
);
175 siphash24_compress(&route
->tos
, sizeof(route
->tos
), state
);
176 siphash24_compress(&route
->priority
, sizeof(route
->priority
), state
);
177 siphash24_compress(&route
->table
, sizeof(route
->table
), state
);
181 /* treat any other address family as AF_UNSPEC */
186 static int route_compare_func(const void *_a
, const void *_b
) {
187 const Route
*a
= _a
, *b
= _b
;
189 if (a
->family
< b
->family
)
191 if (a
->family
> b
->family
)
197 if (a
->dst_prefixlen
< b
->dst_prefixlen
)
199 if (a
->dst_prefixlen
> b
->dst_prefixlen
)
207 if (a
->priority
< b
->priority
)
209 if (a
->priority
> b
->priority
)
212 if (a
->table
< b
->table
)
214 if (a
->table
> b
->table
)
217 return memcmp(&a
->dst
, &b
->dst
, FAMILY_ADDRESS_SIZE(a
->family
));
219 /* treat any other address family as AF_UNSPEC */
224 static const struct hash_ops route_hash_ops
= {
225 .hash
= route_hash_func
,
226 .compare
= route_compare_func
229 int route_get(Link
*link
,
231 const union in_addr_union
*dst
,
232 unsigned char dst_prefixlen
,
238 Route route
, *existing
;
246 .dst_prefixlen
= dst_prefixlen
,
248 .priority
= priority
,
252 existing
= set_get(link
->routes
, &route
);
259 existing
= set_get(link
->routes_foreign
, &route
);
269 static int route_add_internal(
273 const union in_addr_union
*dst
,
274 unsigned char dst_prefixlen
,
280 _cleanup_route_free_ Route
*route
= NULL
;
287 r
= route_new(&route
);
291 route
->family
= family
;
293 route
->dst_prefixlen
= dst_prefixlen
;
295 route
->priority
= priority
;
296 route
->table
= table
;
298 r
= set_ensure_allocated(routes
, &route_hash_ops
);
302 r
= set_put(*routes
, route
);
316 int route_add_foreign(
319 const union in_addr_union
*dst
,
320 unsigned char dst_prefixlen
,
326 return route_add_internal(link
, &link
->routes_foreign
, family
, dst
, dst_prefixlen
, tos
, priority
, table
, ret
);
332 const union in_addr_union
*dst
,
333 unsigned char dst_prefixlen
,
342 r
= route_get(link
, family
, dst
, dst_prefixlen
, tos
, priority
, table
, &route
);
344 /* Route does not exist, create a new one */
345 r
= route_add_internal(link
, &link
->routes
, family
, dst
, dst_prefixlen
, tos
, priority
, table
, &route
);
349 /* Take over a foreign route */
350 r
= set_ensure_allocated(&link
->routes
, &route_hash_ops
);
354 r
= set_put(link
->routes
, route
);
358 set_remove(link
->routes_foreign
, route
);
360 /* Route exists, do nothing */
371 int route_update(Route
*route
,
372 const union in_addr_union
*src
,
373 unsigned char src_prefixlen
,
374 const union in_addr_union
*gw
,
375 const union in_addr_union
*prefsrc
,
377 unsigned char protocol
,
378 unsigned char type
) {
386 route
->src_prefixlen
= src_prefixlen
;
388 route
->prefsrc
= *prefsrc
;
389 route
->scope
= scope
;
390 route
->protocol
= protocol
;
396 int route_remove(Route
*route
, Link
*link
,
397 sd_netlink_message_handler_t callback
) {
398 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
402 assert(link
->manager
);
403 assert(link
->manager
->rtnl
);
404 assert(link
->ifindex
> 0);
405 assert(IN_SET(route
->family
, AF_INET
, AF_INET6
));
407 r
= sd_rtnl_message_new_route(link
->manager
->rtnl
, &req
,
408 RTM_DELROUTE
, route
->family
,
411 return log_error_errno(r
, "Could not create RTM_DELROUTE message: %m");
413 if (!in_addr_is_null(route
->family
, &route
->gw
)) {
414 if (route
->family
== AF_INET
)
415 r
= sd_netlink_message_append_in_addr(req
, RTA_GATEWAY
, &route
->gw
.in
);
416 else if (route
->family
== AF_INET6
)
417 r
= sd_netlink_message_append_in6_addr(req
, RTA_GATEWAY
, &route
->gw
.in6
);
419 return log_error_errno(r
, "Could not append RTA_GATEWAY attribute: %m");
422 if (route
->dst_prefixlen
) {
423 if (route
->family
== AF_INET
)
424 r
= sd_netlink_message_append_in_addr(req
, RTA_DST
, &route
->dst
.in
);
425 else if (route
->family
== AF_INET6
)
426 r
= sd_netlink_message_append_in6_addr(req
, RTA_DST
, &route
->dst
.in6
);
428 return log_error_errno(r
, "Could not append RTA_DST attribute: %m");
430 r
= sd_rtnl_message_route_set_dst_prefixlen(req
, route
->dst_prefixlen
);
432 return log_error_errno(r
, "Could not set destination prefix length: %m");
435 if (route
->src_prefixlen
) {
436 if (route
->family
== AF_INET
)
437 r
= sd_netlink_message_append_in_addr(req
, RTA_SRC
, &route
->src
.in
);
438 else if (route
->family
== AF_INET6
)
439 r
= sd_netlink_message_append_in6_addr(req
, RTA_SRC
, &route
->src
.in6
);
441 return log_error_errno(r
, "Could not append RTA_SRC attribute: %m");
443 r
= sd_rtnl_message_route_set_src_prefixlen(req
, route
->src_prefixlen
);
445 return log_error_errno(r
, "Could not set source prefix length: %m");
448 if (!in_addr_is_null(route
->family
, &route
->prefsrc
)) {
449 if (route
->family
== AF_INET
)
450 r
= sd_netlink_message_append_in_addr(req
, RTA_PREFSRC
, &route
->prefsrc
.in
);
451 else if (route
->family
== AF_INET6
)
452 r
= sd_netlink_message_append_in6_addr(req
, RTA_PREFSRC
, &route
->prefsrc
.in6
);
454 return log_error_errno(r
, "Could not append RTA_PREFSRC attribute: %m");
457 r
= sd_rtnl_message_route_set_scope(req
, route
->scope
);
459 return log_error_errno(r
, "Could not set scope: %m");
461 r
= sd_netlink_message_append_u32(req
, RTA_PRIORITY
, route
->priority
);
463 return log_error_errno(r
, "Could not append RTA_PRIORITY attribute: %m");
465 if (!IN_SET(route
->type
, RTN_UNREACHABLE
, RTN_PROHIBIT
, RTN_BLACKHOLE
)) {
466 r
= sd_netlink_message_append_u32(req
, RTA_OIF
, link
->ifindex
);
468 return log_error_errno(r
, "Could not append RTA_OIF attribute: %m");
471 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
473 return log_error_errno(r
, "Could not send rtnetlink message: %m");
480 static int route_expire_callback(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
481 Link
*link
= userdata
;
487 assert(link
->ifname
);
489 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
492 r
= sd_netlink_message_get_errno(m
);
493 if (r
< 0 && r
!= -EEXIST
)
494 log_link_warning_errno(link
, r
, "could not remove route: %m");
499 int route_expire_handler(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
500 Route
*route
= userdata
;
505 r
= route_remove(route
, route
->link
, route_expire_callback
);
507 log_warning_errno(r
, "Could not remove route: %m");
517 sd_netlink_message_handler_t callback
) {
519 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
520 _cleanup_(sd_event_source_unrefp
) sd_event_source
*expire
= NULL
;
525 assert(link
->manager
);
526 assert(link
->manager
->rtnl
);
527 assert(link
->ifindex
> 0);
528 assert(IN_SET(route
->family
, AF_INET
, AF_INET6
));
530 if (route_get(link
, route
->family
, &route
->dst
, route
->dst_prefixlen
, route
->tos
, route
->priority
, route
->table
, NULL
) <= 0 &&
531 set_size(link
->routes
) >= routes_max())
534 r
= sd_rtnl_message_new_route(link
->manager
->rtnl
, &req
,
535 RTM_NEWROUTE
, route
->family
,
538 return log_error_errno(r
, "Could not create RTM_NEWROUTE message: %m");
540 if (!in_addr_is_null(route
->family
, &route
->gw
)) {
541 if (route
->family
== AF_INET
)
542 r
= sd_netlink_message_append_in_addr(req
, RTA_GATEWAY
, &route
->gw
.in
);
543 else if (route
->family
== AF_INET6
)
544 r
= sd_netlink_message_append_in6_addr(req
, RTA_GATEWAY
, &route
->gw
.in6
);
546 return log_error_errno(r
, "Could not append RTA_GATEWAY attribute: %m");
548 r
= sd_rtnl_message_route_set_family(req
, route
->family
);
550 return log_error_errno(r
, "Could not set route family: %m");
553 if (route
->dst_prefixlen
) {
554 if (route
->family
== AF_INET
)
555 r
= sd_netlink_message_append_in_addr(req
, RTA_DST
, &route
->dst
.in
);
556 else if (route
->family
== AF_INET6
)
557 r
= sd_netlink_message_append_in6_addr(req
, RTA_DST
, &route
->dst
.in6
);
559 return log_error_errno(r
, "Could not append RTA_DST attribute: %m");
561 r
= sd_rtnl_message_route_set_dst_prefixlen(req
, route
->dst_prefixlen
);
563 return log_error_errno(r
, "Could not set destination prefix length: %m");
566 if (route
->src_prefixlen
) {
567 if (route
->family
== AF_INET
)
568 r
= sd_netlink_message_append_in_addr(req
, RTA_SRC
, &route
->src
.in
);
569 else if (route
->family
== AF_INET6
)
570 r
= sd_netlink_message_append_in6_addr(req
, RTA_SRC
, &route
->src
.in6
);
572 return log_error_errno(r
, "Could not append RTA_SRC attribute: %m");
574 r
= sd_rtnl_message_route_set_src_prefixlen(req
, route
->src_prefixlen
);
576 return log_error_errno(r
, "Could not set source prefix length: %m");
579 if (!in_addr_is_null(route
->family
, &route
->prefsrc
)) {
580 if (route
->family
== AF_INET
)
581 r
= sd_netlink_message_append_in_addr(req
, RTA_PREFSRC
, &route
->prefsrc
.in
);
582 else if (route
->family
== AF_INET6
)
583 r
= sd_netlink_message_append_in6_addr(req
, RTA_PREFSRC
, &route
->prefsrc
.in6
);
585 return log_error_errno(r
, "Could not append RTA_PREFSRC attribute: %m");
588 r
= sd_rtnl_message_route_set_scope(req
, route
->scope
);
590 return log_error_errno(r
, "Could not set scope: %m");
592 r
= sd_rtnl_message_route_set_flags(req
, route
->flags
);
594 return log_error_errno(r
, "Could not set flags: %m");
596 if (route
->table
!= RT_TABLE_MAIN
) {
597 if (route
->table
< 256) {
598 r
= sd_rtnl_message_route_set_table(req
, route
->table
);
600 return log_error_errno(r
, "Could not set route table: %m");
602 r
= sd_rtnl_message_route_set_table(req
, RT_TABLE_UNSPEC
);
604 return log_error_errno(r
, "Could not set route table: %m");
606 /* Table attribute to allow more than 256. */
607 r
= sd_netlink_message_append_data(req
, RTA_TABLE
, &route
->table
, sizeof(route
->table
));
609 return log_error_errno(r
, "Could not append RTA_TABLE attribute: %m");
613 r
= sd_netlink_message_append_u32(req
, RTA_PRIORITY
, route
->priority
);
615 return log_error_errno(r
, "Could not append RTA_PRIORITY attribute: %m");
617 r
= sd_netlink_message_append_u8(req
, RTA_PREF
, route
->pref
);
619 return log_error_errno(r
, "Could not append RTA_PREF attribute: %m");
621 r
= sd_rtnl_message_route_set_type(req
, route
->type
);
623 return log_error_errno(r
, "Could not set route type: %m");
625 if (!IN_SET(route
->type
, RTN_UNREACHABLE
, RTN_PROHIBIT
, RTN_BLACKHOLE
)) {
626 r
= sd_netlink_message_append_u32(req
, RTA_OIF
, link
->ifindex
);
628 return log_error_errno(r
, "Could not append RTA_OIF attribute: %m");
631 r
= sd_netlink_message_open_container(req
, RTA_METRICS
);
633 return log_error_errno(r
, "Could not append RTA_METRICS attribute: %m");
635 if (route
->mtu
> 0) {
636 r
= sd_netlink_message_append_u32(req
, RTAX_MTU
, route
->mtu
);
638 return log_error_errno(r
, "Could not append RTAX_MTU attribute: %m");
641 r
= sd_netlink_message_close_container(req
);
643 return log_error_errno(r
, "Could not append RTA_METRICS attribute: %m");
645 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
647 return log_error_errno(r
, "Could not send rtnetlink message: %m");
651 lifetime
= route
->lifetime
;
653 r
= route_add(link
, route
->family
, &route
->dst
, route
->dst_prefixlen
, route
->tos
, route
->priority
, route
->table
, &route
);
655 return log_error_errno(r
, "Could not add route: %m");
657 /* TODO: drop expiration handling once it can be pushed into the kernel */
658 route
->lifetime
= lifetime
;
660 if (route
->lifetime
!= USEC_INFINITY
) {
661 r
= sd_event_add_time(link
->manager
->event
, &expire
, clock_boottime_or_monotonic(),
662 route
->lifetime
, 0, route_expire_handler
, route
);
664 return log_error_errno(r
, "Could not arm expiration timer: %m");
667 sd_event_source_unref(route
->expire
);
668 route
->expire
= expire
;
674 int config_parse_gateway(const char *unit
,
675 const char *filename
,
678 unsigned section_line
,
685 Network
*network
= userdata
;
686 _cleanup_route_free_ Route
*n
= NULL
;
687 union in_addr_union buffer
;
696 if (streq(section
, "Network")) {
697 /* we are not in an Route section, so treat
698 * this as the special '0' section */
699 r
= route_new_static(network
, NULL
, 0, &n
);
701 r
= route_new_static(network
, filename
, section_line
, &n
);
706 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
708 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Route is invalid, ignoring assignment: %s", rvalue
);
719 int config_parse_preferred_src(const char *unit
,
720 const char *filename
,
723 unsigned section_line
,
730 Network
*network
= userdata
;
731 _cleanup_route_free_ Route
*n
= NULL
;
732 union in_addr_union buffer
;
741 r
= route_new_static(network
, filename
, section_line
, &n
);
745 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
747 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
748 "Preferred source is invalid, ignoring assignment: %s", rvalue
);
759 int config_parse_destination(const char *unit
,
760 const char *filename
,
763 unsigned section_line
,
770 Network
*network
= userdata
;
771 _cleanup_route_free_ Route
*n
= NULL
;
772 union in_addr_union buffer
;
773 unsigned char prefixlen
;
782 r
= route_new_static(network
, filename
, section_line
, &n
);
786 r
= in_addr_prefix_from_string(rvalue
, AF_INET
, &buffer
, &prefixlen
);
788 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &buffer
, &prefixlen
);
790 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
791 "Route %s= prefix is invalid, ignoring assignment: %s",
796 n
->family
= AF_INET6
;
800 if (streq(lvalue
, "Destination")) {
802 n
->dst_prefixlen
= prefixlen
;
803 } else if (streq(lvalue
, "Source")) {
805 n
->src_prefixlen
= prefixlen
;
807 assert_not_reached(lvalue
);
814 int config_parse_route_priority(const char *unit
,
815 const char *filename
,
818 unsigned section_line
,
824 Network
*network
= userdata
;
825 _cleanup_route_free_ Route
*n
= NULL
;
835 r
= route_new_static(network
, filename
, section_line
, &n
);
839 r
= safe_atou32(rvalue
, &k
);
841 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
842 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue
);
852 int config_parse_route_scope(const char *unit
,
853 const char *filename
,
856 unsigned section_line
,
862 Network
*network
= userdata
;
863 _cleanup_route_free_ Route
*n
= NULL
;
872 r
= route_new_static(network
, filename
, section_line
, &n
);
876 if (streq(rvalue
, "host"))
877 n
->scope
= RT_SCOPE_HOST
;
878 else if (streq(rvalue
, "link"))
879 n
->scope
= RT_SCOPE_LINK
;
880 else if (streq(rvalue
, "global"))
881 n
->scope
= RT_SCOPE_UNIVERSE
;
883 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unknown route scope: %s", rvalue
);
892 int config_parse_route_table(const char *unit
,
893 const char *filename
,
896 unsigned section_line
,
902 _cleanup_route_free_ Route
*n
= NULL
;
903 Network
*network
= userdata
;
913 r
= route_new_static(network
, filename
, section_line
, &n
);
917 r
= safe_atou32(rvalue
, &k
);
919 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
920 "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue
);
931 int config_parse_gateway_onlink(const char *unit
,
932 const char *filename
,
935 unsigned section_line
,
941 Network
*network
= userdata
;
942 _cleanup_route_free_ Route
*n
= NULL
;
951 r
= route_new_static(network
, filename
, section_line
, &n
);
955 r
= parse_boolean(rvalue
);
957 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
958 "Could not parse gateway onlink \"%s\", ignoring assignment: %m", rvalue
);
962 SET_FLAG(n
->flags
, RTNH_F_ONLINK
, r
);
968 int config_parse_ipv6_route_preference(const char *unit
,
969 const char *filename
,
972 unsigned section_line
,
978 Network
*network
= userdata
;
979 _cleanup_route_free_ Route
*n
= NULL
;
982 r
= route_new_static(network
, filename
, section_line
, &n
);
986 if (streq(rvalue
, "low"))
987 n
->pref
= ICMPV6_ROUTER_PREF_LOW
;
988 else if (streq(rvalue
, "medium"))
989 n
->pref
= ICMPV6_ROUTER_PREF_MEDIUM
;
990 else if (streq(rvalue
, "high"))
991 n
->pref
= ICMPV6_ROUTER_PREF_HIGH
;
993 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unknown route preference: %s", rvalue
);
1002 int config_parse_route_protocol(const char *unit
,
1003 const char *filename
,
1005 const char *section
,
1006 unsigned section_line
,
1012 Network
*network
= userdata
;
1013 _cleanup_route_free_ Route
*n
= NULL
;
1016 r
= route_new_static(network
, filename
, section_line
, &n
);
1020 if (streq(rvalue
, "kernel"))
1021 n
->protocol
= RTPROT_KERNEL
;
1022 else if (streq(rvalue
, "boot"))
1023 n
->protocol
= RTPROT_BOOT
;
1024 else if (streq(rvalue
, "static"))
1025 n
->protocol
= RTPROT_STATIC
;
1027 r
= safe_atou8(rvalue
, &n
->protocol
);
1029 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Could not parse route protocol \"%s\", ignoring assignment: %m", rvalue
);
1039 int config_parse_route_type(const char *unit
,
1040 const char *filename
,
1042 const char *section
,
1043 unsigned section_line
,
1049 Network
*network
= userdata
;
1050 _cleanup_route_free_ Route
*n
= NULL
;
1053 r
= route_new_static(network
, filename
, section_line
, &n
);
1057 if (streq(rvalue
, "unicast"))
1058 n
->type
= RTN_UNICAST
;
1059 else if (streq(rvalue
, "blackhole"))
1060 n
->type
= RTN_BLACKHOLE
;
1061 else if (streq(rvalue
, "unreachable"))
1062 n
->type
= RTN_UNREACHABLE
;
1063 else if (streq(rvalue
, "prohibit"))
1064 n
->type
= RTN_PROHIBIT
;
1066 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Could not parse route type \"%s\", ignoring assignment: %m", rvalue
);