2 This file is part of systemd.
4 Copyright 2013 Tom Gundersen <teg@jklm.no>
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include "alloc-util.h"
21 #include "conf-parser.h"
22 #include "in-addr-util.h"
23 #include "netlink-util.h"
24 #include "networkd-route.h"
26 #include "parse-util.h"
28 #include "string-util.h"
31 #define ROUTES_PER_LINK_MAX 2048U
32 #define STATIC_ROUTES_PER_NETWORK_MAX 1024U
34 int route_new(Route
**ret
) {
35 _cleanup_route_free_ Route
*route
= NULL
;
37 route
= new0(Route
, 1);
41 route
->family
= AF_UNSPEC
;
42 route
->scope
= RT_SCOPE_UNIVERSE
;
43 route
->protocol
= RTPROT_UNSPEC
;
44 route
->table
= RT_TABLE_DEFAULT
;
45 route
->lifetime
= USEC_INFINITY
;
53 int route_new_static(Network
*network
, unsigned section
, Route
**ret
) {
54 _cleanup_route_free_ Route
*route
= NULL
;
61 route
= hashmap_get(network
->routes_by_section
, UINT_TO_PTR(section
));
70 if (network
->n_static_routes
>= STATIC_ROUTES_PER_NETWORK_MAX
)
73 r
= route_new(&route
);
77 route
->protocol
= RTPROT_STATIC
;
80 route
->section
= section
;
82 r
= hashmap_put(network
->routes_by_section
, UINT_TO_PTR(route
->section
), route
);
87 route
->network
= network
;
88 LIST_PREPEND(routes
, network
->static_routes
, route
);
89 network
->n_static_routes
++;
97 void route_free(Route
*route
) {
101 if (route
->network
) {
102 LIST_REMOVE(routes
, route
->network
->static_routes
, route
);
104 assert(route
->network
->n_static_routes
> 0);
105 route
->network
->n_static_routes
--;
108 hashmap_remove(route
->network
->routes_by_section
, UINT_TO_PTR(route
->section
));
112 set_remove(route
->link
->routes
, route
);
113 set_remove(route
->link
->routes_foreign
, route
);
116 sd_event_source_unref(route
->expire
);
121 static void route_hash_func(const void *b
, struct siphash
*state
) {
122 const Route
*route
= b
;
126 siphash24_compress(&route
->family
, sizeof(route
->family
), state
);
128 switch (route
->family
) {
131 /* Equality of routes are given by the 4-touple
132 (dst_prefix,dst_prefixlen,tos,priority,table) */
133 siphash24_compress(&route
->dst
, FAMILY_ADDRESS_SIZE(route
->family
), state
);
134 siphash24_compress(&route
->dst_prefixlen
, sizeof(route
->dst_prefixlen
), state
);
135 siphash24_compress(&route
->tos
, sizeof(route
->tos
), state
);
136 siphash24_compress(&route
->priority
, sizeof(route
->priority
), state
);
137 siphash24_compress(&route
->table
, sizeof(route
->table
), state
);
141 /* treat any other address family as AF_UNSPEC */
146 static int route_compare_func(const void *_a
, const void *_b
) {
147 const Route
*a
= _a
, *b
= _b
;
149 if (a
->family
< b
->family
)
151 if (a
->family
> b
->family
)
157 if (a
->dst_prefixlen
< b
->dst_prefixlen
)
159 if (a
->dst_prefixlen
> b
->dst_prefixlen
)
167 if (a
->priority
< b
->priority
)
169 if (a
->priority
> b
->priority
)
172 if (a
->table
< b
->table
)
174 if (a
->table
> b
->table
)
177 return memcmp(&a
->dst
, &b
->dst
, FAMILY_ADDRESS_SIZE(a
->family
));
179 /* treat any other address family as AF_UNSPEC */
184 static const struct hash_ops route_hash_ops
= {
185 .hash
= route_hash_func
,
186 .compare
= route_compare_func
189 int route_get(Link
*link
,
191 const union in_addr_union
*dst
,
192 unsigned char dst_prefixlen
,
198 Route route
, *existing
;
206 .dst_prefixlen
= dst_prefixlen
,
208 .priority
= priority
,
212 existing
= set_get(link
->routes
, &route
);
219 existing
= set_get(link
->routes_foreign
, &route
);
229 static int route_add_internal(Link
*link
, Set
**routes
,
231 union in_addr_union
*dst
,
232 unsigned char dst_prefixlen
,
235 unsigned char table
, Route
**ret
) {
236 _cleanup_route_free_ Route
*route
= NULL
;
243 r
= route_new(&route
);
247 route
->family
= family
;
249 route
->dst_prefixlen
= dst_prefixlen
;
251 route
->priority
= priority
;
252 route
->table
= table
;
254 r
= set_ensure_allocated(routes
, &route_hash_ops
);
258 r
= set_put(*routes
, route
);
272 int route_add_foreign(Link
*link
,
274 union in_addr_union
*dst
,
275 unsigned char dst_prefixlen
,
278 unsigned char table
, Route
**ret
) {
279 return route_add_internal(link
, &link
->routes_foreign
, family
, dst
, dst_prefixlen
, tos
, priority
, table
, ret
);
282 int route_add(Link
*link
,
284 union in_addr_union
*dst
,
285 unsigned char dst_prefixlen
,
288 unsigned char table
, Route
**ret
) {
292 r
= route_get(link
, family
, dst
, dst_prefixlen
, tos
, priority
, table
, &route
);
294 /* Route does not exist, create a new one */
295 r
= route_add_internal(link
, &link
->routes
, family
, dst
, dst_prefixlen
, tos
, priority
, table
, &route
);
299 /* Take over a foreign route */
300 r
= set_ensure_allocated(&link
->routes
, &route_hash_ops
);
304 r
= set_put(link
->routes
, route
);
308 set_remove(link
->routes_foreign
, route
);
310 /* Route exists, do nothing */
320 int route_update(Route
*route
,
321 union in_addr_union
*src
,
322 unsigned char src_prefixlen
,
323 union in_addr_union
*gw
,
324 union in_addr_union
*prefsrc
,
326 unsigned char protocol
) {
333 route
->src_prefixlen
= src_prefixlen
;
335 route
->prefsrc
= *prefsrc
;
336 route
->scope
= scope
;
337 route
->protocol
= protocol
;
342 int route_remove(Route
*route
, Link
*link
,
343 sd_netlink_message_handler_t callback
) {
344 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
348 assert(link
->manager
);
349 assert(link
->manager
->rtnl
);
350 assert(link
->ifindex
> 0);
351 assert(route
->family
== AF_INET
|| route
->family
== AF_INET6
);
353 r
= sd_rtnl_message_new_route(link
->manager
->rtnl
, &req
,
354 RTM_DELROUTE
, route
->family
,
357 return log_error_errno(r
, "Could not create RTM_DELROUTE message: %m");
359 if (!in_addr_is_null(route
->family
, &route
->gw
)) {
360 if (route
->family
== AF_INET
)
361 r
= sd_netlink_message_append_in_addr(req
, RTA_GATEWAY
, &route
->gw
.in
);
362 else if (route
->family
== AF_INET6
)
363 r
= sd_netlink_message_append_in6_addr(req
, RTA_GATEWAY
, &route
->gw
.in6
);
365 return log_error_errno(r
, "Could not append RTA_GATEWAY attribute: %m");
368 if (route
->dst_prefixlen
) {
369 if (route
->family
== AF_INET
)
370 r
= sd_netlink_message_append_in_addr(req
, RTA_DST
, &route
->dst
.in
);
371 else if (route
->family
== AF_INET6
)
372 r
= sd_netlink_message_append_in6_addr(req
, RTA_DST
, &route
->dst
.in6
);
374 return log_error_errno(r
, "Could not append RTA_DST attribute: %m");
376 r
= sd_rtnl_message_route_set_dst_prefixlen(req
, route
->dst_prefixlen
);
378 return log_error_errno(r
, "Could not set destination prefix length: %m");
381 if (route
->src_prefixlen
) {
382 if (route
->family
== AF_INET
)
383 r
= sd_netlink_message_append_in_addr(req
, RTA_SRC
, &route
->src
.in
);
384 else if (route
->family
== AF_INET6
)
385 r
= sd_netlink_message_append_in6_addr(req
, RTA_SRC
, &route
->src
.in6
);
387 return log_error_errno(r
, "Could not append RTA_SRC attribute: %m");
389 r
= sd_rtnl_message_route_set_src_prefixlen(req
, route
->src_prefixlen
);
391 return log_error_errno(r
, "Could not set source prefix length: %m");
394 if (!in_addr_is_null(route
->family
, &route
->prefsrc
)) {
395 if (route
->family
== AF_INET
)
396 r
= sd_netlink_message_append_in_addr(req
, RTA_PREFSRC
, &route
->prefsrc
.in
);
397 else if (route
->family
== AF_INET6
)
398 r
= sd_netlink_message_append_in6_addr(req
, RTA_PREFSRC
, &route
->prefsrc
.in6
);
400 return log_error_errno(r
, "Could not append RTA_PREFSRC attribute: %m");
403 r
= sd_rtnl_message_route_set_scope(req
, route
->scope
);
405 return log_error_errno(r
, "Could not set scope: %m");
407 r
= sd_netlink_message_append_u32(req
, RTA_PRIORITY
, route
->priority
);
409 return log_error_errno(r
, "Could not append RTA_PRIORITY attribute: %m");
411 r
= sd_netlink_message_append_u32(req
, RTA_OIF
, link
->ifindex
);
413 return log_error_errno(r
, "Could not append RTA_OIF attribute: %m");
415 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
417 return log_error_errno(r
, "Could not send rtnetlink message: %m");
424 static int route_expire_callback(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
425 Link
*link
= userdata
;
431 assert(link
->ifname
);
432 assert(link
->link_messages
> 0);
434 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
437 link
->link_messages
--;
439 r
= sd_netlink_message_get_errno(m
);
440 if (r
< 0 && r
!= -EEXIST
)
441 log_link_warning_errno(link
, r
, "could not remove route: %m");
443 if (link
->link_messages
== 0)
444 log_link_debug(link
, "route removed");
449 int route_expire_handler(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
450 Route
*route
= userdata
;
455 r
= route_remove(route
, route
->link
, route_expire_callback
);
457 log_warning_errno(r
, "Could not remove route: %m");
459 /* route may not be exist in kernel. If we fail still remove it */
460 route
->link
->link_messages
++;
470 sd_netlink_message_handler_t callback
) {
472 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
473 _cleanup_(sd_event_source_unrefp
) sd_event_source
*expire
= NULL
;
478 assert(link
->manager
);
479 assert(link
->manager
->rtnl
);
480 assert(link
->ifindex
> 0);
481 assert(route
->family
== AF_INET
|| route
->family
== AF_INET6
);
483 if (route_get(link
, route
->family
, &route
->dst
, route
->dst_prefixlen
, route
->tos
, route
->priority
, route
->table
, NULL
) <= 0 &&
484 set_size(route
->link
->routes
) >= ROUTES_PER_LINK_MAX
)
487 r
= sd_rtnl_message_new_route(link
->manager
->rtnl
, &req
,
488 RTM_NEWROUTE
, route
->family
,
491 return log_error_errno(r
, "Could not create RTM_NEWROUTE message: %m");
493 if (!in_addr_is_null(route
->family
, &route
->gw
)) {
494 if (route
->family
== AF_INET
)
495 r
= sd_netlink_message_append_in_addr(req
, RTA_GATEWAY
, &route
->gw
.in
);
496 else if (route
->family
== AF_INET6
)
497 r
= sd_netlink_message_append_in6_addr(req
, RTA_GATEWAY
, &route
->gw
.in6
);
499 return log_error_errno(r
, "Could not append RTA_GATEWAY attribute: %m");
501 r
= sd_rtnl_message_route_set_family(req
, route
->family
);
503 return log_error_errno(r
, "Could not set route family: %m");
506 if (route
->dst_prefixlen
) {
507 if (route
->family
== AF_INET
)
508 r
= sd_netlink_message_append_in_addr(req
, RTA_DST
, &route
->dst
.in
);
509 else if (route
->family
== AF_INET6
)
510 r
= sd_netlink_message_append_in6_addr(req
, RTA_DST
, &route
->dst
.in6
);
512 return log_error_errno(r
, "Could not append RTA_DST attribute: %m");
514 r
= sd_rtnl_message_route_set_dst_prefixlen(req
, route
->dst_prefixlen
);
516 return log_error_errno(r
, "Could not set destination prefix length: %m");
519 if (route
->src_prefixlen
) {
520 if (route
->family
== AF_INET
)
521 r
= sd_netlink_message_append_in_addr(req
, RTA_SRC
, &route
->src
.in
);
522 else if (route
->family
== AF_INET6
)
523 r
= sd_netlink_message_append_in6_addr(req
, RTA_SRC
, &route
->src
.in6
);
525 return log_error_errno(r
, "Could not append RTA_SRC attribute: %m");
527 r
= sd_rtnl_message_route_set_src_prefixlen(req
, route
->src_prefixlen
);
529 return log_error_errno(r
, "Could not set source prefix length: %m");
532 if (!in_addr_is_null(route
->family
, &route
->prefsrc
)) {
533 if (route
->family
== AF_INET
)
534 r
= sd_netlink_message_append_in_addr(req
, RTA_PREFSRC
, &route
->prefsrc
.in
);
535 else if (route
->family
== AF_INET6
)
536 r
= sd_netlink_message_append_in6_addr(req
, RTA_PREFSRC
, &route
->prefsrc
.in6
);
538 return log_error_errno(r
, "Could not append RTA_PREFSRC attribute: %m");
541 r
= sd_rtnl_message_route_set_scope(req
, route
->scope
);
543 return log_error_errno(r
, "Could not set scope: %m");
545 r
= sd_rtnl_message_route_set_flags(req
, route
->flags
);
547 return log_error_errno(r
, "Could not set flags: %m");
549 if (route
->table
!= RT_TABLE_DEFAULT
) {
551 if (route
->table
< 256) {
552 r
= sd_rtnl_message_route_set_table(req
, route
->table
);
554 return log_error_errno(r
, "Could not set route table: %m");
557 r
= sd_rtnl_message_route_set_table(req
, RT_TABLE_UNSPEC
);
559 return log_error_errno(r
, "Could not set route table: %m");
561 /* Table attribute to allow more than 256. */
562 r
= sd_netlink_message_append_data(req
, RTA_TABLE
, &route
->table
, sizeof(route
->table
));
564 return log_error_errno(r
, "Could not append RTA_TABLE attribute: %m");
568 r
= sd_netlink_message_append_u32(req
, RTA_PRIORITY
, route
->priority
);
570 return log_error_errno(r
, "Could not append RTA_PRIORITY attribute: %m");
572 r
= sd_netlink_message_append_u8(req
, RTA_PREF
, route
->pref
);
574 return log_error_errno(r
, "Could not append RTA_PREF attribute: %m");
576 r
= sd_netlink_message_append_u32(req
, RTA_OIF
, link
->ifindex
);
578 return log_error_errno(r
, "Could not append RTA_OIF attribute: %m");
580 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
582 return log_error_errno(r
, "Could not send rtnetlink message: %m");
586 lifetime
= route
->lifetime
;
588 r
= route_add(link
, route
->family
, &route
->dst
, route
->dst_prefixlen
, route
->tos
, route
->priority
, route
->table
, &route
);
590 return log_error_errno(r
, "Could not add route: %m");
592 /* TODO: drop expiration handling once it can be pushed into the kernel */
593 route
->lifetime
= lifetime
;
595 if (route
->lifetime
!= USEC_INFINITY
) {
596 r
= sd_event_add_time(link
->manager
->event
, &expire
, clock_boottime_or_monotonic(),
597 route
->lifetime
, 0, route_expire_handler
, route
);
599 return log_error_errno(r
, "Could not arm expiration timer: %m");
602 sd_event_source_unref(route
->expire
);
603 route
->expire
= expire
;
609 int config_parse_gateway(const char *unit
,
610 const char *filename
,
613 unsigned section_line
,
620 Network
*network
= userdata
;
621 _cleanup_route_free_ Route
*n
= NULL
;
622 union in_addr_union buffer
;
631 if (streq(section
, "Network")) {
632 /* we are not in an Route section, so treat
633 * this as the special '0' section */
637 r
= route_new_static(network
, section_line
, &n
);
641 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
643 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Route is invalid, ignoring assignment: %s", rvalue
);
654 int config_parse_preferred_src(const char *unit
,
655 const char *filename
,
658 unsigned section_line
,
665 Network
*network
= userdata
;
666 _cleanup_route_free_ Route
*n
= NULL
;
667 union in_addr_union buffer
;
676 r
= route_new_static(network
, section_line
, &n
);
680 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
682 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
683 "Preferred source is invalid, ignoring assignment: %s", rvalue
);
694 int config_parse_destination(const char *unit
,
695 const char *filename
,
698 unsigned section_line
,
705 Network
*network
= userdata
;
706 _cleanup_route_free_ Route
*n
= NULL
;
707 const char *address
, *e
;
708 union in_addr_union buffer
;
709 unsigned char prefixlen
;
718 r
= route_new_static(network
, section_line
, &n
);
722 /* Destination|Source=address/prefixlen */
725 e
= strchr(rvalue
, '/');
727 address
= strndupa(rvalue
, e
- rvalue
);
731 r
= in_addr_from_string_auto(address
, &f
, &buffer
);
733 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Destination is invalid, ignoring assignment: %s", address
);
737 if (f
!= AF_INET
&& f
!= AF_INET6
) {
738 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unknown address family, ignoring assignment: %s", address
);
744 r
= safe_atou8(e
+ 1, &prefixlen
);
746 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Route destination prefix length is invalid, ignoring assignment: %s", e
+ 1);
761 if (streq(lvalue
, "Destination")) {
763 n
->dst_prefixlen
= prefixlen
;
764 } else if (streq(lvalue
, "Source")) {
766 n
->src_prefixlen
= prefixlen
;
768 assert_not_reached(lvalue
);
775 int config_parse_route_priority(const char *unit
,
776 const char *filename
,
779 unsigned section_line
,
785 Network
*network
= userdata
;
786 _cleanup_route_free_ Route
*n
= NULL
;
795 r
= route_new_static(network
, section_line
, &n
);
799 r
= config_parse_uint32(unit
, filename
, line
, section
,
800 section_line
, lvalue
, ltype
,
801 rvalue
, &n
->priority
, userdata
);
810 int config_parse_route_scope(const char *unit
,
811 const char *filename
,
814 unsigned section_line
,
820 Network
*network
= userdata
;
821 _cleanup_route_free_ Route
*n
= NULL
;
830 r
= route_new_static(network
, section_line
, &n
);
834 if (streq(rvalue
, "host"))
835 n
->scope
= RT_SCOPE_HOST
;
836 else if (streq(rvalue
, "link"))
837 n
->scope
= RT_SCOPE_LINK
;
838 else if (streq(rvalue
, "global"))
839 n
->scope
= RT_SCOPE_UNIVERSE
;
841 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unknown route scope: %s", rvalue
);
850 int config_parse_route_table(const char *unit
,
851 const char *filename
,
854 unsigned section_line
,
860 _cleanup_route_free_ Route
*n
= NULL
;
861 Network
*network
= userdata
;
871 r
= route_new_static(network
, section_line
, &n
);
875 r
= safe_atou32(rvalue
, &k
);
877 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
878 "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue
);