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