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