1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include "conf-parser.h"
24 #include "netlink-util.h"
27 #include "networkd-route.h"
29 int route_new(Route
**ret
, unsigned char rtm_protocol
) {
30 _cleanup_route_free_ Route
*route
= NULL
;
32 route
= new0(Route
, 1);
36 route
->family
= AF_UNSPEC
;
37 route
->scope
= RT_SCOPE_UNIVERSE
;
38 route
->protocol
= rtm_protocol
;
46 int route_new_static(Network
*network
, unsigned section
, Route
**ret
) {
47 _cleanup_route_free_ Route
*route
= NULL
;
51 route
= hashmap_get(network
->routes_by_section
,
52 UINT_TO_PTR(section
));
61 r
= route_new(&route
, RTPROT_STATIC
);
65 route
->network
= network
;
67 LIST_PREPEND(routes
, network
->static_routes
, route
);
70 route
->section
= section
;
71 hashmap_put(network
->routes_by_section
,
72 UINT_TO_PTR(route
->section
), route
);
81 void route_free(Route
*route
) {
86 LIST_REMOVE(routes
, route
->network
->static_routes
, route
);
89 hashmap_remove(route
->network
->routes_by_section
,
90 UINT_TO_PTR(route
->section
));
96 int route_remove(Route
*route
, Link
*link
,
97 sd_netlink_message_handler_t callback
) {
98 _cleanup_netlink_message_unref_ sd_netlink_message
*req
= NULL
;
102 assert(link
->manager
);
103 assert(link
->manager
->rtnl
);
104 assert(link
->ifindex
> 0);
105 assert(route
->family
== AF_INET
|| route
->family
== AF_INET6
);
107 r
= sd_rtnl_message_new_route(link
->manager
->rtnl
, &req
,
108 RTM_DELROUTE
, route
->family
,
111 return log_error_errno(r
, "Could not create RTM_DELROUTE message: %m");
113 if (!in_addr_is_null(route
->family
, &route
->in_addr
)) {
114 if (route
->family
== AF_INET
)
115 r
= sd_netlink_message_append_in_addr(req
, RTA_GATEWAY
, &route
->in_addr
.in
);
116 else if (route
->family
== AF_INET6
)
117 r
= sd_netlink_message_append_in6_addr(req
, RTA_GATEWAY
, &route
->in_addr
.in6
);
119 return log_error_errno(r
, "Could not append RTA_GATEWAY attribute: %m");
122 if (route
->dst_prefixlen
) {
123 if (route
->family
== AF_INET
)
124 r
= sd_netlink_message_append_in_addr(req
, RTA_DST
, &route
->dst_addr
.in
);
125 else if (route
->family
== AF_INET6
)
126 r
= sd_netlink_message_append_in6_addr(req
, RTA_DST
, &route
->dst_addr
.in6
);
128 return log_error_errno(r
, "Could not append RTA_DST attribute: %m");
130 r
= sd_rtnl_message_route_set_dst_prefixlen(req
, route
->dst_prefixlen
);
132 return log_error_errno(r
, "Could not set destination prefix length: %m");
135 if (route
->src_prefixlen
) {
136 if (route
->family
== AF_INET
)
137 r
= sd_netlink_message_append_in_addr(req
, RTA_SRC
, &route
->src_addr
.in
);
138 else if (route
->family
== AF_INET6
)
139 r
= sd_netlink_message_append_in6_addr(req
, RTA_SRC
, &route
->src_addr
.in6
);
141 return log_error_errno(r
, "Could not append RTA_DST attribute: %m");
143 r
= sd_rtnl_message_route_set_src_prefixlen(req
, route
->src_prefixlen
);
145 return log_error_errno(r
, "Could not set source prefix length: %m");
148 if (!in_addr_is_null(route
->family
, &route
->prefsrc_addr
)) {
149 if (route
->family
== AF_INET
)
150 r
= sd_netlink_message_append_in_addr(req
, RTA_PREFSRC
, &route
->prefsrc_addr
.in
);
151 else if (route
->family
== AF_INET6
)
152 r
= sd_netlink_message_append_in6_addr(req
, RTA_PREFSRC
, &route
->prefsrc_addr
.in6
);
154 return log_error_errno(r
, "Could not append RTA_PREFSRC attribute: %m");
157 r
= sd_rtnl_message_route_set_scope(req
, route
->scope
);
159 return log_error_errno(r
, "Could not set scope: %m");
161 r
= sd_netlink_message_append_u32(req
, RTA_PRIORITY
, route
->metrics
);
163 return log_error_errno(r
, "Could not append RTA_PRIORITY attribute: %m");
165 r
= sd_netlink_message_append_u32(req
, RTA_OIF
, link
->ifindex
);
167 return log_error_errno(r
, "Could not append RTA_OIF attribute: %m");
169 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
171 return log_error_errno(r
, "Could not send rtnetlink message: %m");
178 int route_configure(Route
*route
, Link
*link
,
179 sd_netlink_message_handler_t callback
) {
180 _cleanup_netlink_message_unref_ sd_netlink_message
*req
= NULL
;
184 assert(link
->manager
);
185 assert(link
->manager
->rtnl
);
186 assert(link
->ifindex
> 0);
187 assert(route
->family
== AF_INET
|| route
->family
== AF_INET6
);
189 r
= sd_rtnl_message_new_route(link
->manager
->rtnl
, &req
,
190 RTM_NEWROUTE
, route
->family
,
193 return log_error_errno(r
, "Could not create RTM_NEWROUTE message: %m");
195 if (!in_addr_is_null(route
->family
, &route
->in_addr
)) {
196 if (route
->family
== AF_INET
)
197 r
= sd_netlink_message_append_in_addr(req
, RTA_GATEWAY
, &route
->in_addr
.in
);
198 else if (route
->family
== AF_INET6
)
199 r
= sd_netlink_message_append_in6_addr(req
, RTA_GATEWAY
, &route
->in_addr
.in6
);
201 return log_error_errno(r
, "Could not append RTA_GATEWAY attribute: %m");
204 if (route
->dst_prefixlen
) {
205 if (route
->family
== AF_INET
)
206 r
= sd_netlink_message_append_in_addr(req
, RTA_DST
, &route
->dst_addr
.in
);
207 else if (route
->family
== AF_INET6
)
208 r
= sd_netlink_message_append_in6_addr(req
, RTA_DST
, &route
->dst_addr
.in6
);
210 return log_error_errno(r
, "Could not append RTA_DST attribute: %m");
212 r
= sd_rtnl_message_route_set_dst_prefixlen(req
, route
->dst_prefixlen
);
214 return log_error_errno(r
, "Could not set destination prefix length: %m");
217 if (route
->src_prefixlen
) {
218 if (route
->family
== AF_INET
)
219 r
= sd_netlink_message_append_in_addr(req
, RTA_SRC
, &route
->src_addr
.in
);
220 else if (route
->family
== AF_INET6
)
221 r
= sd_netlink_message_append_in6_addr(req
, RTA_SRC
, &route
->src_addr
.in6
);
223 return log_error_errno(r
, "Could not append RTA_SRC attribute: %m");
225 r
= sd_rtnl_message_route_set_src_prefixlen(req
, route
->src_prefixlen
);
227 return log_error_errno(r
, "Could not set source prefix length: %m");
230 if (!in_addr_is_null(route
->family
, &route
->prefsrc_addr
)) {
231 if (route
->family
== AF_INET
)
232 r
= sd_netlink_message_append_in_addr(req
, RTA_PREFSRC
, &route
->prefsrc_addr
.in
);
233 else if (route
->family
== AF_INET6
)
234 r
= sd_netlink_message_append_in6_addr(req
, RTA_PREFSRC
, &route
->prefsrc_addr
.in6
);
236 return log_error_errno(r
, "Could not append RTA_PREFSRC attribute: %m");
239 r
= sd_rtnl_message_route_set_scope(req
, route
->scope
);
241 return log_error_errno(r
, "Could not set scope: %m");
243 r
= sd_netlink_message_append_u32(req
, RTA_PRIORITY
, route
->metrics
);
245 return log_error_errno(r
, "Could not append RTA_PRIORITY attribute: %m");
247 r
= sd_netlink_message_append_u32(req
, RTA_OIF
, link
->ifindex
);
249 return log_error_errno(r
, "Could not append RTA_OIF attribute: %m");
251 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
253 return log_error_errno(r
, "Could not send rtnetlink message: %m");
260 int config_parse_gateway(const char *unit
,
261 const char *filename
,
264 unsigned section_line
,
271 Network
*network
= userdata
;
272 _cleanup_route_free_ Route
*n
= NULL
;
273 union in_addr_union buffer
;
282 if (streq(section
, "Network")) {
283 /* we are not in an Route section, so treat
284 * this as the special '0' section */
288 r
= route_new_static(network
, section_line
, &n
);
292 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
294 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Route is invalid, ignoring assignment: %s", rvalue
);
305 int config_parse_preferred_src(const char *unit
,
306 const char *filename
,
309 unsigned section_line
,
316 Network
*network
= userdata
;
317 _cleanup_route_free_ Route
*n
= NULL
;
318 union in_addr_union buffer
;
327 r
= route_new_static(network
, section_line
, &n
);
331 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
333 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
334 "Preferred source is invalid, ignoring assignment: %s", rvalue
);
339 n
->prefsrc_addr
= buffer
;
345 int config_parse_destination(const char *unit
,
346 const char *filename
,
349 unsigned section_line
,
356 Network
*network
= userdata
;
357 _cleanup_route_free_ Route
*n
= NULL
;
358 const char *address
, *e
;
359 union in_addr_union buffer
;
360 unsigned char prefixlen
;
369 r
= route_new_static(network
, section_line
, &n
);
373 /* Destination|Source=address/prefixlen */
376 e
= strchr(rvalue
, '/');
378 address
= strndupa(rvalue
, e
- rvalue
);
382 r
= in_addr_from_string_auto(address
, &f
, &buffer
);
384 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Destination is invalid, ignoring assignment: %s", address
);
388 if (f
!= AF_INET
&& f
!= AF_INET6
) {
389 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unknown address family, ignoring assignment: %s", address
);
395 r
= safe_atou8(e
+ 1, &prefixlen
);
397 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Route destination prefix length is invalid, ignoring assignment: %s", e
+ 1);
412 if (streq(lvalue
, "Destination")) {
413 n
->dst_addr
= buffer
;
414 n
->dst_prefixlen
= prefixlen
;
415 } else if (streq(lvalue
, "Source")) {
416 n
->src_addr
= buffer
;
417 n
->src_prefixlen
= prefixlen
;
419 assert_not_reached(lvalue
);
426 int config_parse_route_priority(const char *unit
,
427 const char *filename
,
430 unsigned section_line
,
436 Network
*network
= userdata
;
437 _cleanup_route_free_ Route
*n
= NULL
;
446 r
= route_new_static(network
, section_line
, &n
);
450 r
= config_parse_unsigned(unit
, filename
, line
, section
,
451 section_line
, lvalue
, ltype
,
452 rvalue
, &n
->metrics
, userdata
);
461 int config_parse_route_scope(const char *unit
,
462 const char *filename
,
465 unsigned section_line
,
471 Network
*network
= userdata
;
472 _cleanup_route_free_ Route
*n
= NULL
;
481 r
= route_new_static(network
, section_line
, &n
);
485 if (streq(rvalue
, "host"))
486 n
->scope
= RT_SCOPE_HOST
;
487 else if (streq(rvalue
, "link"))
488 n
->scope
= RT_SCOPE_LINK
;
489 else if (streq(rvalue
, "global"))
490 n
->scope
= RT_SCOPE_UNIVERSE
;
492 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unknown route scope: %s", rvalue
);