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