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