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