chiark / gitweb /
rtnl: simplify route_new()
[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         r = sd_rtnl_message_append(req, RTA_GATEWAY, &route->in_addr);
96         if (r < 0) {
97                 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
98                 return r;
99         }
100
101         r = sd_rtnl_message_append(req, RTA_DST, &route->dst_addr);
102         if (r < 0) {
103                 log_error("Could not append RTA_DST attribute: %s", strerror(-r));
104                 return r;
105         }
106
107         r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
108         if (r < 0) {
109                 log_error("Could not set destination prefix length: %s", strerror(-r));
110                 return r;
111         }
112
113         r = sd_rtnl_message_append(req, RTA_OIF, &link->ifindex);
114         if (r < 0) {
115                 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
116                 return r;
117         }
118
119         r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
120         if (r < 0) {
121                 log_error("Could not send rtnetlink message: %s", strerror(-r));
122                 return r;
123         }
124
125         return 0;
126 }
127
128 int config_parse_gateway(const char *unit,
129                 const char *filename,
130                 unsigned line,
131                 const char *section,
132                 unsigned section_line,
133                 const char *lvalue,
134                 int ltype,
135                 const char *rvalue,
136                 void *data,
137                 void *userdata) {
138         Network *network = userdata;
139         _cleanup_route_free_ Route *n = NULL;
140         _cleanup_free_ char *route = NULL;
141         int r;
142
143         assert(filename);
144         assert(section);
145         assert(lvalue);
146         assert(rvalue);
147         assert(data);
148
149         if (streq(section, "Network")) {
150                 /* we are not in an Route section, so treat
151                  * this as the special '0' section */
152                 section_line = 0;
153         }
154
155         r = route_new(network, section_line, &n);
156         if (r < 0)
157                 return r;
158
159         r = net_parse_inaddr(rvalue, &n->family, &n->in_addr);
160         if (r < 0) {
161                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
162                            "Route is invalid, ignoring assignment: %s", route);
163                 return 0;
164         }
165
166         n = NULL;
167
168         return 0;
169 }
170
171 int config_parse_destination(const char *unit,
172                 const char *filename,
173                 unsigned line,
174                 const char *section,
175                 unsigned section_line,
176                 const char *lvalue,
177                 int ltype,
178                 const char *rvalue,
179                 void *data,
180                 void *userdata) {
181         Network *network = userdata;
182         _cleanup_route_free_ Route *n = NULL;
183         _cleanup_free_ char *address = NULL;
184         const char *e;
185         int r;
186
187         assert(filename);
188         assert(section);
189         assert(lvalue);
190         assert(rvalue);
191         assert(data);
192
193         r = route_new(network, section_line, &n);
194         if (r < 0)
195                 return r;
196
197         /* Destination=address/prefixlen */
198
199         /* prefixlen */
200         e = strchr(rvalue, '/');
201         if (e) {
202                 unsigned i;
203                 r = safe_atou(e + 1, &i);
204                 if (r < 0) {
205                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
206                                    "Route destination prefix length is invalid, "
207                                    "ignoring assignment: %s", e + 1);
208                         return 0;
209                 }
210
211                 n->dst_prefixlen = (unsigned char) i;
212
213                 address = strndup(rvalue, e - rvalue);
214                 if (!address)
215                         return log_oom();
216         } else {
217                 address = strdup(rvalue);
218                 if (!address)
219                         return log_oom();
220         }
221
222         r = net_parse_inaddr(address, &n->family, &n->dst_addr);
223         if (r < 0) {
224                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
225                            "Destination is invalid, ignoring assignment: %s", address);
226                 return 0;
227         }
228
229         n = NULL;
230
231         return 0;
232 }