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