]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-route.c
sd-bus: the bus returned should be the first arg
[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"
29#include "net-util.h"
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
TG
50 route->family = AF_UNSPEC;
51
f579559b
TG
52 route->network = network;
53
f048a16b 54 LIST_PREPEND(static_routes, network->static_routes, route);
f579559b 55
6ae115c1
TG
56 if (section) {
57 route->section = section;
58 hashmap_put(network->routes_by_section, &route->section, route);
59 }
60
f579559b
TG
61 *ret = route;
62 route = NULL;
63
64 return 0;
65}
66
f048a16b
TG
67int route_new_dynamic(Route **ret) {
68 _cleanup_route_free_ Route *route = NULL;
69
70 route = new0(Route, 1);
71 if (!route)
72 return -ENOMEM;
73
801bd9e8
TG
74 route->family = AF_UNSPEC;
75
f048a16b
TG
76 *ret = route;
77 route = NULL;
78
79 return 0;
80}
81
f579559b
TG
82void route_free(Route *route) {
83 if (!route)
84 return;
85
f048a16b
TG
86 if (route->network) {
87 LIST_REMOVE(static_routes, route->network->static_routes, route);
f579559b 88
f048a16b
TG
89 if (route->section)
90 hashmap_remove(route->network->routes_by_section,
91 &route->section);
92 }
6ae115c1 93
f579559b
TG
94 free(route);
95}
96
f882c247
TG
97int route_configure(Route *route, Link *link,
98 sd_rtnl_message_handler_t callback) {
cf6a8911 99 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
f579559b
TG
100 int r;
101
f579559b 102 assert(link);
f882c247
TG
103 assert(link->manager);
104 assert(link->manager->rtnl);
f579559b
TG
105 assert(link->ifindex > 0);
106 assert(route->family == AF_INET || route->family == AF_INET6);
107
4fb7242c
TG
108 r = sd_rtnl_message_new_route(link->manager->rtnl, RTM_NEWROUTE,
109 route->family, &req);
f579559b
TG
110 if (r < 0) {
111 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
112 return r;
113 }
114
0a0dc69b
TG
115 if (route->family == AF_INET)
116 r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
117 else if (route->family == AF_INET6)
118 r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
f579559b
TG
119 if (r < 0) {
120 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
121 return r;
122 }
123
0a0dc69b
TG
124 if (route->dst_prefixlen) {
125 if (route->family == AF_INET)
126 r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
127 else if (route->family == AF_INET6)
128 r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
129 if (r < 0) {
130 log_error("Could not append RTA_DST attribute: %s", strerror(-r));
131 return r;
132 }
6ae115c1 133
ae4c67a7
TG
134 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
135 if (r < 0) {
136 log_error("Could not set destination prefix length: %s", strerror(-r));
137 return r;
138 }
1f01fb4f
TG
139 }
140
0a0dc69b 141 r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
f579559b
TG
142 if (r < 0) {
143 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
144 return r;
145 }
146
f882c247 147 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
f579559b 148 if (r < 0) {
f882c247 149 log_error("Could not send rtnetlink message: %s", strerror(-r));
f579559b
TG
150 return r;
151 }
152
f579559b
TG
153 return 0;
154}
155
156int config_parse_gateway(const char *unit,
157 const char *filename,
158 unsigned line,
159 const char *section,
71a61510 160 unsigned section_line,
f579559b
TG
161 const char *lvalue,
162 int ltype,
163 const char *rvalue,
164 void *data,
165 void *userdata) {
6ae115c1 166 Network *network = userdata;
f579559b
TG
167 _cleanup_route_free_ Route *n = NULL;
168 _cleanup_free_ char *route = NULL;
169 int r;
170
171 assert(filename);
6ae115c1 172 assert(section);
f579559b
TG
173 assert(lvalue);
174 assert(rvalue);
175 assert(data);
176
92fe133a
TG
177 if (streq(section, "Network")) {
178 /* we are not in an Route section, so treat
179 * this as the special '0' section */
180 section_line = 0;
181 }
182
f048a16b 183 r = route_new_static(network, section_line, &n);
f579559b
TG
184 if (r < 0)
185 return r;
186
187 r = net_parse_inaddr(rvalue, &n->family, &n->in_addr);
188 if (r < 0) {
189 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
190 "Route is invalid, ignoring assignment: %s", route);
191 return 0;
192 }
193
194 n = NULL;
195
196 return 0;
197}
6ae115c1
TG
198
199int config_parse_destination(const char *unit,
200 const char *filename,
201 unsigned line,
202 const char *section,
203 unsigned section_line,
204 const char *lvalue,
205 int ltype,
206 const char *rvalue,
207 void *data,
208 void *userdata) {
209 Network *network = userdata;
210 _cleanup_route_free_ Route *n = NULL;
211 _cleanup_free_ char *address = NULL;
212 const char *e;
213 int r;
214
215 assert(filename);
216 assert(section);
217 assert(lvalue);
218 assert(rvalue);
219 assert(data);
220
f048a16b 221 r = route_new_static(network, section_line, &n);
6ae115c1
TG
222 if (r < 0)
223 return r;
224
225 /* Destination=address/prefixlen */
226
ae4c67a7 227 /* address */
6ae115c1
TG
228 e = strchr(rvalue, '/');
229 if (e) {
6ae115c1
TG
230 address = strndup(rvalue, e - rvalue);
231 if (!address)
232 return log_oom();
233 } else {
234 address = strdup(rvalue);
235 if (!address)
236 return log_oom();
237 }
238
801bd9e8 239 r = net_parse_inaddr(address, &n->family, &n->dst_addr);
6ae115c1
TG
240 if (r < 0) {
241 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
242 "Destination is invalid, ignoring assignment: %s", address);
243 return 0;
244 }
245
ae4c67a7
TG
246 /* prefixlen */
247 if (e) {
248 unsigned i;
249
250 r = safe_atou(e + 1, &i);
251 if (r < 0) {
252 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
253 "Route destination prefix length is invalid, "
254 "ignoring assignment: %s", e + 1);
255 return 0;
256 }
257
258 n->dst_prefixlen = (unsigned char) i;
259 } else {
801bd9e8 260 switch (n->family) {
ae4c67a7
TG
261 case AF_INET:
262 n->dst_prefixlen = 32;
263 break;
264 case AF_INET6:
265 n->dst_prefixlen = 128;
266 break;
267 }
268 }
269
6ae115c1
TG
270 n = NULL;
271
272 return 0;
273}