]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
networkd: unref tunnel
[thirdparty/systemd.git] / src / network / networkd-network.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 <ctype.h>
23 #include <net/if.h>
24
25 #include "networkd.h"
26 #include "network-internal.h"
27 #include "path-util.h"
28 #include "conf-files.h"
29 #include "conf-parser.h"
30 #include "util.h"
31
32 static int network_load_one(Manager *manager, const char *filename) {
33 _cleanup_network_free_ Network *network = NULL;
34 _cleanup_fclose_ FILE *file = NULL;
35 Route *route;
36 Address *address;
37 int r;
38
39 assert(manager);
40 assert(filename);
41
42 file = fopen(filename, "re");
43 if (!file) {
44 if (errno == ENOENT)
45 return 0;
46 else
47 return -errno;
48 }
49
50 if (null_or_empty_path(filename)) {
51 log_debug("skipping empty file: %s", filename);
52 return 0;
53 }
54
55 network = new0(Network, 1);
56 if (!network)
57 return log_oom();
58
59 network->manager = manager;
60
61 LIST_HEAD_INIT(network->static_addresses);
62 LIST_HEAD_INIT(network->static_routes);
63
64 network->vlans = hashmap_new(string_hash_func, string_compare_func);
65 if (!network->vlans)
66 return log_oom();
67
68 network->macvlans = hashmap_new(uint64_hash_func, uint64_compare_func);
69 if (!network->macvlans)
70 return log_oom();
71
72 network->vxlans = hashmap_new(uint64_hash_func, uint64_compare_func);
73 if (!network->vxlans)
74 return log_oom();
75
76 network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
77 if (!network->addresses_by_section)
78 return log_oom();
79
80 network->routes_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
81 if (!network->routes_by_section)
82 return log_oom();
83
84 network->filename = strdup(filename);
85 if (!network->filename)
86 return log_oom();
87
88 network->dhcp_ntp = true;
89 network->dhcp_dns = true;
90 network->dhcp_hostname = true;
91 network->dhcp_domainname = true;
92
93 r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCPv4\0", config_item_perf_lookup,
94 (void*) network_network_gperf_lookup, false, false, network);
95 if (r < 0) {
96 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
97 return r;
98 }
99
100 LIST_PREPEND(networks, manager->networks, network);
101
102 LIST_FOREACH(routes, route, network->static_routes) {
103 if (!route->family) {
104 log_warning("Route section without Gateway field configured in %s. "
105 "Ignoring", filename);
106 return 0;
107 }
108 }
109
110 LIST_FOREACH(addresses, address, network->static_addresses) {
111 if (!address->family) {
112 log_warning("Address section without Address field configured in %s. "
113 "Ignoring", filename);
114 return 0;
115 }
116 }
117
118 network = NULL;
119
120 return 0;
121 }
122
123 int network_load(Manager *manager) {
124 Network *network;
125 _cleanup_strv_free_ char **files = NULL;
126 char **f;
127 int r;
128
129 assert(manager);
130
131 while ((network = manager->networks))
132 network_free(network);
133
134 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
135 if (r < 0) {
136 log_error("Failed to enumerate network files: %s", strerror(-r));
137 return r;
138 }
139
140 STRV_FOREACH_BACKWARDS(f, files) {
141 r = network_load_one(manager, *f);
142 if (r < 0)
143 return r;
144 }
145
146 return 0;
147 }
148
149 void network_free(Network *network) {
150 NetDev *netdev;
151 Route *route;
152 Address *address;
153 Iterator i;
154
155 if (!network)
156 return;
157
158 free(network->filename);
159
160 free(network->match_mac);
161 free(network->match_path);
162 free(network->match_driver);
163 free(network->match_type);
164 free(network->match_name);
165
166 free(network->description);
167
168 while ((address = network->ntp)) {
169 LIST_REMOVE(addresses, network->ntp, address);
170 address_free(address);
171 }
172
173 while ((address = network->dns)) {
174 LIST_REMOVE(addresses, network->dns, address);
175 address_free(address);
176 }
177
178 netdev_unref(network->bridge);
179
180 netdev_unref(network->bond);
181
182 netdev_unref(network->tunnel);
183
184 HASHMAP_FOREACH(netdev, network->vlans, i)
185 netdev_unref(netdev);
186 hashmap_free(network->vlans);
187
188 HASHMAP_FOREACH(netdev, network->macvlans, i)
189 netdev_unref(netdev);
190 hashmap_free(network->macvlans);
191
192 HASHMAP_FOREACH(netdev, network->vxlans, i)
193 netdev_unref(netdev);
194 hashmap_free(network->vxlans);
195
196 while ((route = network->static_routes))
197 route_free(route);
198
199 while ((address = network->static_addresses))
200 address_free(address);
201
202 hashmap_free(network->addresses_by_section);
203 hashmap_free(network->routes_by_section);
204
205 if (network->manager && network->manager->networks)
206 LIST_REMOVE(networks, network->manager->networks, network);
207
208 condition_free_list(network->match_host);
209 condition_free_list(network->match_virt);
210 condition_free_list(network->match_kernel);
211 condition_free_list(network->match_arch);
212
213 free(network);
214 }
215
216 int network_get(Manager *manager, struct udev_device *device,
217 const char *ifname, const struct ether_addr *address,
218 Network **ret) {
219 Network *network;
220
221 assert(manager);
222 assert(ret);
223
224 LIST_FOREACH(networks, network, manager->networks) {
225 if (net_match_config(network->match_mac, network->match_path,
226 network->match_driver, network->match_type,
227 network->match_name, network->match_host,
228 network->match_virt, network->match_kernel,
229 network->match_arch,
230 address,
231 udev_device_get_property_value(device, "ID_PATH"),
232 udev_device_get_driver(udev_device_get_parent(device)),
233 udev_device_get_property_value(device, "ID_NET_DRIVER"),
234 udev_device_get_devtype(device),
235 ifname)) {
236 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
237 network->filename);
238 *ret = network;
239 return 0;
240 }
241 }
242
243 *ret = NULL;
244
245 return -ENOENT;
246 }
247
248 int network_apply(Manager *manager, Network *network, Link *link) {
249 int r;
250
251 link->network = network;
252
253 if (network->dns || network->ntp) {
254 r = link_save(link);
255 if (r < 0)
256 return r;
257 }
258
259 return 0;
260 }
261
262 int config_parse_netdev(const char *unit,
263 const char *filename,
264 unsigned line,
265 const char *section,
266 unsigned section_line,
267 const char *lvalue,
268 int ltype,
269 const char *rvalue,
270 void *data,
271 void *userdata) {
272 Network *network = userdata;
273 _cleanup_free_ char *kind_string = NULL;
274 char *p;
275 NetDev *netdev;
276 NetDevKind kind;
277 int r;
278
279 assert(filename);
280 assert(lvalue);
281 assert(rvalue);
282 assert(data);
283
284 kind_string = strdup(lvalue);
285 if (!kind_string)
286 return log_oom();
287
288 /* the keys are CamelCase versions of the kind */
289 for (p = kind_string; *p; p++)
290 *p = tolower(*p);
291
292 kind = netdev_kind_from_string(kind_string);
293 if (kind == _NETDEV_KIND_INVALID) {
294 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
295 "Invalid NetDev kind: %s", lvalue);
296 return 0;
297 }
298
299 r = netdev_get(network->manager, rvalue, &netdev);
300 if (r < 0) {
301 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
302 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
303 return 0;
304 }
305
306 if (netdev->kind != kind) {
307 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
308 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
309 return 0;
310 }
311
312 switch (kind) {
313 case NETDEV_KIND_BRIDGE:
314 network->bridge = netdev;
315
316 break;
317 case NETDEV_KIND_BOND:
318 network->bond = netdev;
319
320 break;
321 case NETDEV_KIND_VLAN:
322 r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
323 if (r < 0) {
324 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
325 "Can not add VLAN to network: %s", rvalue);
326 return 0;
327 }
328
329 break;
330 case NETDEV_KIND_MACVLAN:
331 r = hashmap_put(network->macvlans, netdev->ifname, netdev);
332 if (r < 0) {
333 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
334 "Can not add MACVLAN to network: %s", rvalue);
335 return 0;
336 }
337
338 break;
339 case NETDEV_KIND_VXLAN:
340 r = hashmap_put(network->vxlans, netdev->ifname, netdev);
341 if (r < 0) {
342 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
343 "Can not add VXLAN to network: %s", rvalue);
344 return 0;
345 }
346
347 break;
348 default:
349 assert_not_reached("Can not parse NetDev");
350 }
351
352 netdev_ref(netdev);
353
354 return 0;
355 }
356
357 int config_parse_tunnel(const char *unit,
358 const char *filename,
359 unsigned line,
360 const char *section,
361 unsigned section_line,
362 const char *lvalue,
363 int ltype,
364 const char *rvalue,
365 void *data,
366 void *userdata) {
367 Network *network = userdata;
368 NetDev *netdev;
369 int r;
370
371 assert(filename);
372 assert(lvalue);
373 assert(rvalue);
374 assert(data);
375
376 r = netdev_get(network->manager, rvalue, &netdev);
377 if (r < 0) {
378 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
379 "Tunnel is invalid, ignoring assignment: %s", rvalue);
380 return 0;
381 }
382
383 if (netdev->kind != NETDEV_KIND_IPIP &&
384 netdev->kind != NETDEV_KIND_SIT &&
385 netdev->kind != NETDEV_KIND_GRE &&
386 netdev->kind != NETDEV_KIND_VTI) {
387 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
388 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
389 return 0;
390 }
391
392 network->tunnel = netdev;
393
394 return 0;
395 }