chiark / gitweb /
sd-rtnl-message: store reference to the bus in the message
[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(link->manager->rtnl, RTM_NEWROUTE,
109                                       route->family, &req);
110         if (r < 0) {
111                 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
112                 return r;
113         }
114
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);
119         if (r < 0) {
120                 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
121                 return r;
122         }
123
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                 }
133
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                 }
139         }
140
141         r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
142         if (r < 0) {
143                 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
144                 return r;
145         }
146
147         r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
148         if (r < 0) {
149                 log_error("Could not send rtnetlink message: %s", strerror(-r));
150                 return r;
151         }
152
153         return 0;
154 }
155
156 int config_parse_gateway(const char *unit,
157                 const char *filename,
158                 unsigned line,
159                 const char *section,
160                 unsigned section_line,
161                 const char *lvalue,
162                 int ltype,
163                 const char *rvalue,
164                 void *data,
165                 void *userdata) {
166         Network *network = userdata;
167         _cleanup_route_free_ Route *n = NULL;
168         _cleanup_free_ char *route = NULL;
169         int r;
170
171         assert(filename);
172         assert(section);
173         assert(lvalue);
174         assert(rvalue);
175         assert(data);
176
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
183         r = route_new_static(network, section_line, &n);
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 }
198
199 int 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
221         r = route_new_static(network, section_line, &n);
222         if (r < 0)
223                 return r;
224
225         /* Destination=address/prefixlen */
226
227         /* address */
228         e = strchr(rvalue, '/');
229         if (e) {
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
239         r = net_parse_inaddr(address, &n->family, &n->dst_addr);
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
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 {
260                 switch (n->family) {
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
270         n = NULL;
271
272         return 0;
273 }