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 (route->src_prefixlen) {
142 if (route->family == AF_INET)
143 r = sd_rtnl_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
144 else if (route->family == AF_INET6)
145 r = sd_rtnl_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
147 return log_error_errno(r, "Could not append RTA_DST attribute: %m");
149 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
151 return log_error_errno(r, "Could not set source prefix length: %m");
154 if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
155 if (route->family == AF_INET)
156 r = sd_rtnl_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
157 else if (route->family == AF_INET6)
158 r = sd_rtnl_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
160 return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
163 r = sd_rtnl_message_route_set_scope(req, route->scope);
165 return log_error_errno(r, "Could not set scope: %m");
167 r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
169 return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
171 r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
173 return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
175 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
177 return log_error_errno(r, "Could not send rtnetlink message: %m");
184 int route_configure(Route *route, Link *link,
185 sd_rtnl_message_handler_t callback) {
186 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
190 assert(link->manager);
191 assert(link->manager->rtnl);
192 assert(link->ifindex > 0);
193 assert(route->family == AF_INET || route->family == AF_INET6);
195 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
196 RTM_NEWROUTE, route->family,
199 return log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
201 if (!in_addr_is_null(route->family, &route->in_addr)) {
202 if (route->family == AF_INET)
203 r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
204 else if (route->family == AF_INET6)
205 r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
207 return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
210 if (route->dst_prefixlen) {
211 if (route->family == AF_INET)
212 r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
213 else if (route->family == AF_INET6)
214 r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
216 return log_error_errno(r, "Could not append RTA_DST attribute: %m");
218 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
220 return log_error_errno(r, "Could not set destination prefix length: %m");
223 if (route->src_prefixlen) {
224 if (route->family == AF_INET)
225 r = sd_rtnl_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
226 else if (route->family == AF_INET6)
227 r = sd_rtnl_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
229 return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
231 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
233 return log_error_errno(r, "Could not set source prefix length: %m");
236 if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
237 if (route->family == AF_INET)
238 r = sd_rtnl_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
239 else if (route->family == AF_INET6)
240 r = sd_rtnl_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
242 return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
245 r = sd_rtnl_message_route_set_scope(req, route->scope);
247 return log_error_errno(r, "Could not set scope: %m");
249 r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
251 return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
253 r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
255 return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
257 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
259 return log_error_errno(r, "Could not send rtnetlink message: %m");
266 int config_parse_gateway(const char *unit,
267 const char *filename,
270 unsigned section_line,
277 Network *network = userdata;
278 _cleanup_route_free_ Route *n = NULL;
279 union in_addr_union buffer;
288 if (streq(section, "Network")) {
289 /* we are not in an Route section, so treat
290 * this as the special '0' section */
294 r = route_new_static(network, section_line, &n);
298 r = in_addr_from_string_auto(rvalue, &f, &buffer);
300 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
301 "Route is invalid, ignoring assignment: %s", rvalue);
312 int config_parse_destination(const char *unit,
313 const char *filename,
316 unsigned section_line,
323 Network *network = userdata;
324 _cleanup_route_free_ Route *n = NULL;
325 const char *address, *e;
326 union in_addr_union buffer;
327 unsigned char prefixlen;
336 r = route_new_static(network, section_line, &n);
340 /* Destination|Source=address/prefixlen */
343 e = strchr(rvalue, '/');
345 address = strndupa(rvalue, e - rvalue);
349 r = in_addr_from_string_auto(address, &f, &buffer);
351 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
352 "Destination is invalid, ignoring assignment: %s", address);
356 if (f != AF_INET && f != AF_INET6) {
357 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
358 "Unknown address family, ignoring assignment: %s", address);
364 r = safe_atou8(e + 1, &prefixlen);
366 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
367 "Route destination prefix length is invalid, ignoring assignment: %s", e + 1);
382 if (streq(lvalue, "Destination")) {
383 n->dst_addr = buffer;
384 n->dst_prefixlen = prefixlen;
385 } else if (streq(lvalue, "Source")) {
386 n->src_addr = buffer;
387 n->src_prefixlen = prefixlen;
389 assert_not_reached(lvalue);
396 int config_parse_route_priority(const char *unit,
397 const char *filename,
400 unsigned section_line,
406 Network *network = userdata;
407 _cleanup_route_free_ Route *n = NULL;
416 r = route_new_static(network, section_line, &n);
420 r = config_parse_unsigned(unit, filename, line, section,
421 section_line, lvalue, ltype,
422 rvalue, &n->metrics, userdata);