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/>.
24 #include "networkd-link.h"
27 #include "conf-parser.h"
29 int route_new_static(Network *network, unsigned section, Route **ret) {
30 _cleanup_route_free_ Route *route = NULL;
33 route = hashmap_get(network->routes_by_section,
34 UINT_TO_PTR(section));
43 route = new0(Route, 1);
47 route->family = AF_UNSPEC;
48 route->scope = RT_SCOPE_UNIVERSE;
49 route->protocol = RTPROT_STATIC;
51 route->network = network;
53 LIST_PREPEND(routes, network->static_routes, route);
56 route->section = section;
57 hashmap_put(network->routes_by_section,
58 UINT_TO_PTR(route->section), route);
67 int route_new_dynamic(Route **ret, unsigned char rtm_protocol) {
68 _cleanup_route_free_ Route *route = NULL;
70 route = new0(Route, 1);
74 route->family = AF_UNSPEC;
75 route->scope = RT_SCOPE_UNIVERSE;
76 route->protocol = rtm_protocol;
84 void route_free(Route *route) {
89 LIST_REMOVE(routes, route->network->static_routes, route);
92 hashmap_remove(route->network->routes_by_section,
93 UINT_TO_PTR(route->section));
99 int route_drop(Route *route, Link *link,
100 sd_rtnl_message_handler_t callback) {
101 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
105 assert(link->manager);
106 assert(link->manager->rtnl);
107 assert(link->ifindex > 0);
108 assert(route->family == AF_INET || route->family == AF_INET6);
110 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
111 RTM_DELROUTE, route->family,
114 return log_error_errno(r, "Could not create RTM_DELROUTE message: %m");
116 if (!in_addr_is_null(route->family, &route->in_addr)) {
117 if (route->family == AF_INET)
118 r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
119 else if (route->family == AF_INET6)
120 r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
122 return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
125 if (route->dst_prefixlen) {
126 if (route->family == AF_INET)
127 r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
128 else if (route->family == AF_INET6)
129 r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
131 return log_error_errno(r, "Could not append RTA_DST attribute: %m");
133 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
135 return log_error_errno(r, "Could not set destination prefix length: %m");
138 if (route->src_prefixlen) {
139 if (route->family == AF_INET)
140 r = sd_rtnl_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
141 else if (route->family == AF_INET6)
142 r = sd_rtnl_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
144 return log_error_errno(r, "Could not append RTA_DST attribute: %m");
146 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
148 return log_error_errno(r, "Could not set source prefix length: %m");
151 if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
152 if (route->family == AF_INET)
153 r = sd_rtnl_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
154 else if (route->family == AF_INET6)
155 r = sd_rtnl_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
157 return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
160 r = sd_rtnl_message_route_set_scope(req, route->scope);
162 return log_error_errno(r, "Could not set scope: %m");
164 r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
166 return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
168 r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
170 return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
172 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
174 return log_error_errno(r, "Could not send rtnetlink message: %m");
181 int route_configure(Route *route, Link *link,
182 sd_rtnl_message_handler_t callback) {
183 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
187 assert(link->manager);
188 assert(link->manager->rtnl);
189 assert(link->ifindex > 0);
190 assert(route->family == AF_INET || route->family == AF_INET6);
192 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
193 RTM_NEWROUTE, route->family,
196 return log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
198 if (!in_addr_is_null(route->family, &route->in_addr)) {
199 if (route->family == AF_INET)
200 r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
201 else if (route->family == AF_INET6)
202 r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
204 return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
207 if (route->dst_prefixlen) {
208 if (route->family == AF_INET)
209 r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
210 else if (route->family == AF_INET6)
211 r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
213 return log_error_errno(r, "Could not append RTA_DST attribute: %m");
215 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
217 return log_error_errno(r, "Could not set destination prefix length: %m");
220 if (route->src_prefixlen) {
221 if (route->family == AF_INET)
222 r = sd_rtnl_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
223 else if (route->family == AF_INET6)
224 r = sd_rtnl_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
226 return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
228 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
230 return log_error_errno(r, "Could not set source prefix length: %m");
233 if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
234 if (route->family == AF_INET)
235 r = sd_rtnl_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
236 else if (route->family == AF_INET6)
237 r = sd_rtnl_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
239 return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
242 r = sd_rtnl_message_route_set_scope(req, route->scope);
244 return log_error_errno(r, "Could not set scope: %m");
246 r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
248 return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
250 r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
252 return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
254 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
256 return log_error_errno(r, "Could not send rtnetlink message: %m");
263 int config_parse_gateway(const char *unit,
264 const char *filename,
267 unsigned section_line,
274 Network *network = userdata;
275 _cleanup_route_free_ Route *n = NULL;
276 union in_addr_union buffer;
285 if (streq(section, "Network")) {
286 /* we are not in an Route section, so treat
287 * this as the special '0' section */
291 r = route_new_static(network, section_line, &n);
295 r = in_addr_from_string_auto(rvalue, &f, &buffer);
297 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
298 "Route is invalid, ignoring assignment: %s", rvalue);
309 int config_parse_destination(const char *unit,
310 const char *filename,
313 unsigned section_line,
320 Network *network = userdata;
321 _cleanup_route_free_ Route *n = NULL;
322 const char *address, *e;
323 union in_addr_union buffer;
324 unsigned char prefixlen;
333 r = route_new_static(network, section_line, &n);
337 /* Destination|Source=address/prefixlen */
340 e = strchr(rvalue, '/');
342 address = strndupa(rvalue, e - rvalue);
346 r = in_addr_from_string_auto(address, &f, &buffer);
348 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
349 "Destination is invalid, ignoring assignment: %s", address);
353 if (f != AF_INET && f != AF_INET6) {
354 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
355 "Unknown address family, ignoring assignment: %s", address);
361 r = safe_atou8(e + 1, &prefixlen);
363 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
364 "Route destination prefix length is invalid, ignoring assignment: %s", e + 1);
379 if (streq(lvalue, "Destination")) {
380 n->dst_addr = buffer;
381 n->dst_prefixlen = prefixlen;
382 } else if (streq(lvalue, "Source")) {
383 n->src_addr = buffer;
384 n->src_prefixlen = prefixlen;
386 assert_not_reached(lvalue);
393 int config_parse_route_priority(const char *unit,
394 const char *filename,
397 unsigned section_line,
403 Network *network = userdata;
404 _cleanup_route_free_ Route *n = NULL;
413 r = route_new_static(network, section_line, &n);
417 r = config_parse_unsigned(unit, filename, line, section,
418 section_line, lvalue, ltype,
419 rvalue, &n->metrics, userdata);
428 int config_parse_route_scope(const char *unit,
429 const char *filename,
432 unsigned section_line,
438 Network *network = userdata;
439 _cleanup_route_free_ Route *n = NULL;
448 r = route_new_static(network, section_line, &n);
452 if (streq(rvalue, "host"))
453 n->scope = RT_SCOPE_HOST;
454 else if (streq(rvalue, "link"))
455 n->scope = RT_SCOPE_LINK;
456 else if (streq(rvalue, "global"))
457 n->scope = RT_SCOPE_UNIVERSE;
459 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
460 "Unknown route scope: %s", rvalue);