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