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