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 return log_error_errno(r, "Could not create RTM_DELROUTE message: %m");
119 if (!in_addr_is_null(route->family, &route->in_addr)) {
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 return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
128 if (route->dst_prefixlen) {
129 if (route->family == AF_INET)
130 r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
131 else if (route->family == AF_INET6)
132 r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
134 return log_error_errno(r, "Could not append RTA_DST attribute: %m");
136 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
138 return log_error_errno(r, "Could not set destination prefix length: %m");
141 if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
142 if (route->family == AF_INET)
143 r = sd_rtnl_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
144 else if (route->family == AF_INET6)
145 r = sd_rtnl_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
147 return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
150 r = sd_rtnl_message_route_set_scope(req, route->scope);
152 return log_error_errno(r, "Could not set scope: %m");
154 r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
156 return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
158 r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
160 return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
162 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
164 return log_error_errno(r, "Could not send rtnetlink message: %m");
171 int route_configure(Route *route, Link *link,
172 sd_rtnl_message_handler_t callback) {
173 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
177 assert(link->manager);
178 assert(link->manager->rtnl);
179 assert(link->ifindex > 0);
180 assert(route->family == AF_INET || route->family == AF_INET6);
182 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
183 RTM_NEWROUTE, route->family,
186 return log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
188 if (!in_addr_is_null(route->family, &route->in_addr)) {
189 if (route->family == AF_INET)
190 r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
191 else if (route->family == AF_INET6)
192 r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
194 return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
197 if (route->dst_prefixlen) {
198 if (route->family == AF_INET)
199 r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
200 else if (route->family == AF_INET6)
201 r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
203 return log_error_errno(r, "Could not append RTA_DST attribute: %m");
205 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
207 return log_error_errno(r, "Could not set destination prefix length: %m");
210 if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
211 if (route->family == AF_INET)
212 r = sd_rtnl_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
213 else if (route->family == AF_INET6)
214 r = sd_rtnl_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
216 return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
219 r = sd_rtnl_message_route_set_scope(req, route->scope);
221 return log_error_errno(r, "Could not set scope: %m");
223 r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
225 return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
227 r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
229 return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
231 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
233 return log_error_errno(r, "Could not send rtnetlink message: %m");
240 int config_parse_gateway(const char *unit,
241 const char *filename,
244 unsigned section_line,
251 Network *network = userdata;
252 _cleanup_route_free_ Route *n = NULL;
253 union in_addr_union buffer;
262 if (streq(section, "Network")) {
263 /* we are not in an Route section, so treat
264 * this as the special '0' section */
268 r = route_new_static(network, section_line, &n);
272 r = in_addr_from_string_auto(rvalue, &f, &buffer);
274 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
275 "Route is invalid, ignoring assignment: %s", rvalue);
286 int config_parse_destination(const char *unit,
287 const char *filename,
290 unsigned section_line,
297 Network *network = userdata;
298 _cleanup_route_free_ Route *n = NULL;
299 const char *address, *e;
300 union in_addr_union buffer;
309 r = route_new_static(network, section_line, &n);
313 /* Destination=address/prefixlen */
316 e = strchr(rvalue, '/');
318 address = strndupa(rvalue, e - rvalue);
322 r = in_addr_from_string_auto(address, &f, &buffer);
324 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
325 "Destination is invalid, ignoring assignment: %s", address);
333 r = safe_atou(e + 1, &i);
335 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
336 "Route destination prefix length is invalid, ignoring assignment: %s", e + 1);
340 n->dst_prefixlen = (unsigned char) i;
344 n->dst_prefixlen = 32;
347 n->dst_prefixlen = 128;
353 n->dst_addr = buffer;
359 int config_parse_route_priority(const char *unit,
360 const char *filename,
363 unsigned section_line,
369 Network *network = userdata;
370 _cleanup_route_free_ Route *n = NULL;
379 r = route_new_static(network, section_line, &n);
383 r = config_parse_unsigned(unit, filename, line, section,
384 section_line, lvalue, ltype,
385 rvalue, &n->metrics, userdata);