chiark / gitweb /
networkd: add bridge support
[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         r = route_new(network, section_line, &n);
146         if (r < 0)
147                 return r;
148
149         r = net_parse_inaddr(rvalue, &n->family, &n->in_addr);
150         if (r < 0) {
151                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
152                            "Route is invalid, ignoring assignment: %s", route);
153                 return 0;
154         }
155
156         n = NULL;
157
158         return 0;
159 }
160
161 int config_parse_destination(const char *unit,
162                 const char *filename,
163                 unsigned line,
164                 const char *section,
165                 unsigned section_line,
166                 const char *lvalue,
167                 int ltype,
168                 const char *rvalue,
169                 void *data,
170                 void *userdata) {
171         Network *network = userdata;
172         _cleanup_route_free_ Route *n = NULL;
173         _cleanup_free_ char *address = NULL;
174         const char *e;
175         int r;
176
177         assert(filename);
178         assert(section);
179         assert(lvalue);
180         assert(rvalue);
181         assert(data);
182
183         r = route_new(network, section_line, &n);
184         if (r < 0)
185                 return r;
186
187         /* Destination=address/prefixlen */
188
189         /* prefixlen */
190         e = strchr(rvalue, '/');
191         if (e) {
192                 unsigned i;
193                 r = safe_atou(e + 1, &i);
194                 if (r < 0) {
195                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
196                                    "Route destination prefix length is invalid, "
197                                    "ignoring assignment: %s", e + 1);
198                         return 0;
199                 }
200
201                 n->dst_prefixlen = (unsigned char) i;
202
203                 address = strndup(rvalue, e - rvalue);
204                 if (!address)
205                         return log_oom();
206         } else {
207                 address = strdup(rvalue);
208                 if (!address)
209                         return log_oom();
210         }
211
212         r = net_parse_inaddr(address, &n->family, &n->dst_addr);
213         if (r < 0) {
214                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
215                            "Destination is invalid, ignoring assignment: %s", address);
216                 return 0;
217         }
218
219         n = NULL;
220
221         return 0;
222 }