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/>.
25 #include "networkd-link.h"
29 #include "conf-parser.h"
30 #include "network-internal.h"
32 int route_new_static(Network *network, unsigned section, Route **ret) {
33 _cleanup_route_free_ Route *route = NULL;
36 route = hashmap_get(network->routes_by_section,
37 UINT_TO_PTR(section));
46 route = new0(Route, 1);
50 route->family = AF_UNSPEC;
51 route->scope = RT_SCOPE_UNIVERSE;
52 route->protocol = RTPROT_STATIC;
54 route->network = network;
56 LIST_PREPEND(routes, network->static_routes, route);
59 route->section = section;
60 hashmap_put(network->routes_by_section,
61 UINT_TO_PTR(route->section), route);
70 int route_new_dynamic(Route **ret, unsigned char rtm_protocol) {
71 _cleanup_route_free_ Route *route = NULL;
73 route = new0(Route, 1);
77 route->family = AF_UNSPEC;
78 route->scope = RT_SCOPE_UNIVERSE;
79 route->protocol = rtm_protocol;
87 void route_free(Route *route) {
92 LIST_REMOVE(routes, route->network->static_routes, route);
95 hashmap_remove(route->network->routes_by_section,
96 UINT_TO_PTR(route->section));
102 int route_drop(Route *route, Link *link,
103 sd_rtnl_message_handler_t callback) {
104 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
108 assert(link->manager);
109 assert(link->manager->rtnl);
110 assert(link->ifindex > 0);
111 assert(route->family == AF_INET || route->family == AF_INET6);
113 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
114 RTM_DELROUTE, route->family,
117 log_error("Could not create RTM_DELROUTE message: %s", strerror(-r));
121 if (route->family == AF_INET)
122 r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
123 else if (route->family == AF_INET6)
124 r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
126 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
130 if (route->dst_prefixlen) {
131 if (route->family == AF_INET)
132 r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
133 else if (route->family == AF_INET6)
134 r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
136 log_error("Could not append RTA_DST attribute: %s", strerror(-r));
140 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
142 log_error("Could not set destination prefix length: %s", strerror(-r));
147 r = sd_rtnl_message_route_set_scope(req, route->scope);
149 log_error("Could not set scope: %s", strerror(-r));
153 r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
155 log_error("Could not append RTA_PRIORITY attribute: %s", strerror(-r));
159 r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
161 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
165 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
167 log_error("Could not send rtnetlink message: %s", strerror(-r));
176 int route_configure(Route *route, Link *link,
177 sd_rtnl_message_handler_t callback) {
178 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
182 assert(link->manager);
183 assert(link->manager->rtnl);
184 assert(link->ifindex > 0);
185 assert(route->family == AF_INET || route->family == AF_INET6);
187 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
188 RTM_NEWROUTE, route->family,
191 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
195 if (route->family == AF_INET)
196 r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
197 else if (route->family == AF_INET6)
198 r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
200 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
204 if (route->dst_prefixlen) {
205 if (route->family == AF_INET)
206 r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
207 else if (route->family == AF_INET6)
208 r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
210 log_error("Could not append RTA_DST attribute: %s", strerror(-r));
214 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
216 log_error("Could not set destination prefix length: %s", strerror(-r));
221 r = sd_rtnl_message_route_set_scope(req, route->scope);
223 log_error("Could not set scope: %s", strerror(-r));
227 r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
229 log_error("Could not append RTA_PRIORITY attribute: %s", strerror(-r));
233 r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
235 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
239 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
241 log_error("Could not send rtnetlink message: %s", strerror(-r));
250 int config_parse_gateway(const char *unit,
251 const char *filename,
254 unsigned section_line,
261 Network *network = userdata;
262 _cleanup_route_free_ Route *n = NULL;
263 union in_addr_union buffer;
272 if (streq(section, "Network")) {
273 /* we are not in an Route section, so treat
274 * this as the special '0' section */
278 r = route_new_static(network, section_line, &n);
282 r = in_addr_from_string_auto(rvalue, &f, &buffer);
284 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
285 "Route is invalid, ignoring assignment: %s", rvalue);
296 int config_parse_destination(const char *unit,
297 const char *filename,
300 unsigned section_line,
307 Network *network = userdata;
308 _cleanup_route_free_ Route *n = NULL;
309 const char *address, *e;
310 union in_addr_union buffer;
319 r = route_new_static(network, section_line, &n);
323 /* Destination=address/prefixlen */
326 e = strchr(rvalue, '/');
328 address = strndupa(rvalue, e - rvalue);
332 r = in_addr_from_string_auto(address, &f, &buffer);
334 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
335 "Destination is invalid, ignoring assignment: %s", address);
343 r = safe_atou(e + 1, &i);
345 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
346 "Route destination prefix length is invalid, ignoring assignment: %s", e + 1);
350 n->dst_prefixlen = (unsigned char) i;
354 n->dst_prefixlen = 32;
357 n->dst_prefixlen = 128;
363 n->dst_addr = buffer;
369 int config_parse_route_priority(const char *unit,
370 const char *filename,
373 unsigned section_line,
379 Network *network = userdata;
380 _cleanup_route_free_ Route *n = NULL;
389 r = route_new_static(network, section_line, &n);
393 r = config_parse_unsigned(unit, filename, line, section,
394 section_line, lvalue, ltype,
395 rvalue, &n->metrics, userdata);