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/>.
28 #include "conf-parser.h"
29 #include "network-internal.h"
31 int route_new_static(Network *network, unsigned section, Route **ret) {
32 _cleanup_route_free_ Route *route = NULL;
35 uint64_t key = section;
37 route = hashmap_get(network->routes_by_section, &key);
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, &route->section, route);
69 int route_new_dynamic(Route **ret, unsigned char rtm_protocol) {
70 _cleanup_route_free_ Route *route = NULL;
72 route = new0(Route, 1);
76 route->family = AF_UNSPEC;
77 route->scope = RT_SCOPE_UNIVERSE;
78 route->protocol = rtm_protocol;
86 void route_free(Route *route) {
91 LIST_REMOVE(routes, route->network->static_routes, route);
94 hashmap_remove(route->network->routes_by_section,
101 int route_drop(Route *route, Link *link,
102 sd_rtnl_message_handler_t callback) {
103 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
107 assert(link->manager);
108 assert(link->manager->rtnl);
109 assert(link->ifindex > 0);
110 assert(route->family == AF_INET || route->family == AF_INET6);
112 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
113 RTM_DELROUTE, route->family,
116 log_error("Could not create RTM_DELROUTE message: %s", strerror(-r));
120 if (route->family == AF_INET)
121 r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
122 else if (route->family == AF_INET6)
123 r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
125 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
129 if (route->dst_prefixlen) {
130 if (route->family == AF_INET)
131 r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
132 else if (route->family == AF_INET6)
133 r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
135 log_error("Could not append RTA_DST attribute: %s", strerror(-r));
139 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
141 log_error("Could not set destination prefix length: %s", strerror(-r));
146 r = sd_rtnl_message_route_set_scope(req, route->scope);
148 log_error("Could not set scope: %s", strerror(-r));
152 r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
154 log_error("Could not append RTA_PRIORITY attribute: %s", strerror(-r));
158 r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
160 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
164 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
166 log_error("Could not send rtnetlink message: %s", strerror(-r));
175 int route_configure(Route *route, Link *link,
176 sd_rtnl_message_handler_t callback) {
177 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
181 assert(link->manager);
182 assert(link->manager->rtnl);
183 assert(link->ifindex > 0);
184 assert(route->family == AF_INET || route->family == AF_INET6);
186 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
187 RTM_NEWROUTE, route->family,
190 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
194 if (route->family == AF_INET)
195 r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
196 else if (route->family == AF_INET6)
197 r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
199 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
203 if (route->dst_prefixlen) {
204 if (route->family == AF_INET)
205 r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
206 else if (route->family == AF_INET6)
207 r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
209 log_error("Could not append RTA_DST attribute: %s", strerror(-r));
213 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
215 log_error("Could not set destination prefix length: %s", strerror(-r));
220 r = sd_rtnl_message_route_set_scope(req, route->scope);
222 log_error("Could not set scope: %s", strerror(-r));
226 r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
228 log_error("Could not append RTA_PRIORITY attribute: %s", strerror(-r));
232 r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
234 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
238 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
240 log_error("Could not send rtnetlink message: %s", strerror(-r));
249 int config_parse_gateway(const char *unit,
250 const char *filename,
253 unsigned section_line,
259 Network *network = userdata;
260 _cleanup_route_free_ Route *n = NULL;
261 _cleanup_free_ char *route = NULL;
270 if (streq(section, "Network")) {
271 /* we are not in an Route section, so treat
272 * this as the special '0' section */
276 r = route_new_static(network, section_line, &n);
280 r = net_parse_inaddr(rvalue, &n->family, &n->in_addr);
282 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
283 "Route is invalid, ignoring assignment: %s", route);
292 int config_parse_destination(const char *unit,
293 const char *filename,
296 unsigned section_line,
302 Network *network = userdata;
303 _cleanup_route_free_ Route *n = NULL;
304 _cleanup_free_ char *address = NULL;
314 r = route_new_static(network, section_line, &n);
318 /* Destination=address/prefixlen */
321 e = strchr(rvalue, '/');
323 address = strndup(rvalue, e - rvalue);
327 address = strdup(rvalue);
332 r = net_parse_inaddr(address, &n->family, &n->dst_addr);
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, "
347 "ignoring assignment: %s", e + 1);
351 n->dst_prefixlen = (unsigned char) i;
355 n->dst_prefixlen = 32;
358 n->dst_prefixlen = 128;
368 int config_parse_route_priority(const char *unit,
369 const char *filename,
372 unsigned section_line,
378 Network *network = userdata;
379 _cleanup_route_free_ Route *n = NULL;
388 r = route_new_static(network, section_line, &n);
392 r = config_parse_unsigned(unit, filename, line, section,
393 section_line, lvalue, ltype,
394 rvalue, &n->metrics, userdata);