]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-route.c
timesyncd: fix typo in comment
[thirdparty/systemd.git] / src / network / networkd-route.c
CommitLineData
f579559b
TG
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
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.
12
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.
17
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/>.
20***/
21
22#include <net/if.h>
23
24#include "networkd.h"
25
26#include "utf8.h"
27#include "util.h"
28#include "conf-parser.h"
c6f7c917 29#include "network-internal.h"
f579559b 30
f048a16b 31int route_new_static(Network *network, unsigned section, Route **ret) {
f579559b
TG
32 _cleanup_route_free_ Route *route = NULL;
33
6ae115c1
TG
34 if (section) {
35 uint64_t key = section;
36
37 route = hashmap_get(network->routes_by_section, &key);
38 if (route) {
39 *ret = route;
40 route = NULL;
41
42 return 0;
43 }
44 }
45
f579559b
TG
46 route = new0(Route, 1);
47 if (!route)
48 return -ENOMEM;
49
801bd9e8 50 route->family = AF_UNSPEC;
5c1d3fc9 51 route->scope = RT_SCOPE_UNIVERSE;
801bd9e8 52
f579559b
TG
53 route->network = network;
54
f048a16b 55 LIST_PREPEND(static_routes, network->static_routes, route);
f579559b 56
6ae115c1
TG
57 if (section) {
58 route->section = section;
59 hashmap_put(network->routes_by_section, &route->section, route);
60 }
61
f579559b
TG
62 *ret = route;
63 route = NULL;
64
65 return 0;
66}
67
f048a16b
TG
68int route_new_dynamic(Route **ret) {
69 _cleanup_route_free_ Route *route = NULL;
70
71 route = new0(Route, 1);
72 if (!route)
73 return -ENOMEM;
74
801bd9e8 75 route->family = AF_UNSPEC;
5c1d3fc9 76 route->scope = RT_SCOPE_UNIVERSE;
801bd9e8 77
f048a16b
TG
78 *ret = route;
79 route = NULL;
80
81 return 0;
82}
83
f579559b
TG
84void route_free(Route *route) {
85 if (!route)
86 return;
87
f048a16b
TG
88 if (route->network) {
89 LIST_REMOVE(static_routes, route->network->static_routes, route);
f579559b 90
f048a16b
TG
91 if (route->section)
92 hashmap_remove(route->network->routes_by_section,
93 &route->section);
94 }
6ae115c1 95
f579559b
TG
96 free(route);
97}
98
5c1d3fc9
UTL
99int route_drop(Route *route, Link *link,
100 sd_rtnl_message_handler_t callback) {
101 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
102 int r;
103
104 assert(link);
105 assert(link->manager);
106 assert(link->manager->rtnl);
107 assert(link->ifindex > 0);
108 assert(route->family == AF_INET || route->family == AF_INET6);
109
110 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
111 RTM_DELROUTE, route->family);
112 if (r < 0) {
113 log_error("Could not create RTM_DELROUTE message: %s", strerror(-r));
114 return r;
115 }
116
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);
121 if (r < 0) {
122 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
123 return r;
124 }
125
126 if (route->dst_prefixlen) {
127 if (route->family == AF_INET)
128 r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
129 else if (route->family == AF_INET6)
130 r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
131 if (r < 0) {
132 log_error("Could not append RTA_DST attribute: %s", strerror(-r));
133 return r;
134 }
135
136 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
137 if (r < 0) {
138 log_error("Could not set destination prefix length: %s", strerror(-r));
139 return r;
140 }
141 }
142
143 r = sd_rtnl_message_route_set_scope(req, route->scope);
144 if (r < 0) {
145 log_error("Could not set scope: %s", strerror(-r));
146 return r;
147 }
148
149 r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
150 if (r < 0) {
151 log_error("Could not append RTA_PRIORITY attribute: %s", strerror(-r));
152 return r;
153 }
154
155 r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
156 if (r < 0) {
157 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
158 return r;
159 }
160
161 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
162 if (r < 0) {
163 log_error("Could not send rtnetlink message: %s", strerror(-r));
164 return r;
165 }
166
167 return 0;
168}
169
f882c247
TG
170int route_configure(Route *route, Link *link,
171 sd_rtnl_message_handler_t callback) {
cf6a8911 172 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
f579559b
TG
173 int r;
174
f579559b 175 assert(link);
f882c247
TG
176 assert(link->manager);
177 assert(link->manager->rtnl);
f579559b
TG
178 assert(link->ifindex > 0);
179 assert(route->family == AF_INET || route->family == AF_INET6);
180
151b9b96
LP
181 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
182 RTM_NEWROUTE, route->family);
f579559b
TG
183 if (r < 0) {
184 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
185 return r;
186 }
187
0a0dc69b
TG
188 if (route->family == AF_INET)
189 r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
190 else if (route->family == AF_INET6)
191 r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
f579559b
TG
192 if (r < 0) {
193 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
194 return r;
195 }
196
0a0dc69b
TG
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);
202 if (r < 0) {
203 log_error("Could not append RTA_DST attribute: %s", strerror(-r));
204 return r;
205 }
6ae115c1 206
ae4c67a7
TG
207 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
208 if (r < 0) {
209 log_error("Could not set destination prefix length: %s", strerror(-r));
210 return r;
211 }
1f01fb4f
TG
212 }
213
5c1d3fc9
UTL
214 r = sd_rtnl_message_route_set_scope(req, route->scope);
215 if (r < 0) {
216 log_error("Could not set scope: %s", strerror(-r));
217 return r;
218 }
219
220 r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
221 if (r < 0) {
222 log_error("Could not append RTA_PRIORITY attribute: %s", strerror(-r));
223 return r;
224 }
225
0a0dc69b 226 r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
f579559b
TG
227 if (r < 0) {
228 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
229 return r;
230 }
231
f882c247 232 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
f579559b 233 if (r < 0) {
f882c247 234 log_error("Could not send rtnetlink message: %s", strerror(-r));
f579559b
TG
235 return r;
236 }
237
f579559b
TG
238 return 0;
239}
240
241int config_parse_gateway(const char *unit,
242 const char *filename,
243 unsigned line,
244 const char *section,
71a61510 245 unsigned section_line,
f579559b
TG
246 const char *lvalue,
247 int ltype,
248 const char *rvalue,
249 void *data,
250 void *userdata) {
6ae115c1 251 Network *network = userdata;
f579559b
TG
252 _cleanup_route_free_ Route *n = NULL;
253 _cleanup_free_ char *route = NULL;
254 int r;
255
256 assert(filename);
6ae115c1 257 assert(section);
f579559b
TG
258 assert(lvalue);
259 assert(rvalue);
260 assert(data);
261
92fe133a
TG
262 if (streq(section, "Network")) {
263 /* we are not in an Route section, so treat
264 * this as the special '0' section */
265 section_line = 0;
266 }
267
f048a16b 268 r = route_new_static(network, section_line, &n);
f579559b
TG
269 if (r < 0)
270 return r;
271
272 r = net_parse_inaddr(rvalue, &n->family, &n->in_addr);
273 if (r < 0) {
274 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
275 "Route is invalid, ignoring assignment: %s", route);
276 return 0;
277 }
278
279 n = NULL;
280
281 return 0;
282}
6ae115c1
TG
283
284int config_parse_destination(const char *unit,
285 const char *filename,
286 unsigned line,
287 const char *section,
288 unsigned section_line,
289 const char *lvalue,
290 int ltype,
291 const char *rvalue,
292 void *data,
293 void *userdata) {
294 Network *network = userdata;
295 _cleanup_route_free_ Route *n = NULL;
296 _cleanup_free_ char *address = NULL;
297 const char *e;
298 int r;
299
300 assert(filename);
301 assert(section);
302 assert(lvalue);
303 assert(rvalue);
304 assert(data);
305
f048a16b 306 r = route_new_static(network, section_line, &n);
6ae115c1
TG
307 if (r < 0)
308 return r;
309
310 /* Destination=address/prefixlen */
311
ae4c67a7 312 /* address */
6ae115c1
TG
313 e = strchr(rvalue, '/');
314 if (e) {
6ae115c1
TG
315 address = strndup(rvalue, e - rvalue);
316 if (!address)
317 return log_oom();
318 } else {
319 address = strdup(rvalue);
320 if (!address)
321 return log_oom();
322 }
323
801bd9e8 324 r = net_parse_inaddr(address, &n->family, &n->dst_addr);
6ae115c1
TG
325 if (r < 0) {
326 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
327 "Destination is invalid, ignoring assignment: %s", address);
328 return 0;
329 }
330
ae4c67a7
TG
331 /* prefixlen */
332 if (e) {
333 unsigned i;
334
335 r = safe_atou(e + 1, &i);
336 if (r < 0) {
337 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
338 "Route destination prefix length is invalid, "
339 "ignoring assignment: %s", e + 1);
340 return 0;
341 }
342
343 n->dst_prefixlen = (unsigned char) i;
344 } else {
801bd9e8 345 switch (n->family) {
ae4c67a7
TG
346 case AF_INET:
347 n->dst_prefixlen = 32;
348 break;
349 case AF_INET6:
350 n->dst_prefixlen = 128;
351 break;
352 }
353 }
354
6ae115c1
TG
355 n = NULL;
356
357 return 0;
358}