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