]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
networkd: introduce refcounting for Links and NetDevs
[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
22#include "networkd.h"
c6f7c917 23#include "network-internal.h"
f579559b
TG
24#include "path-util.h"
25#include "conf-files.h"
26#include "conf-parser.h"
477e73b5 27#include "util.h"
f579559b
TG
28
29static int network_load_one(Manager *manager, const char *filename) {
30 _cleanup_network_free_ Network *network = NULL;
31 _cleanup_fclose_ FILE *file = NULL;
b3070dc0
TG
32 Route *route;
33 Address *address;
f579559b
TG
34 int r;
35
bf1bc670
TA
36 assert(manager);
37 assert(filename);
38
f579559b
TG
39 file = fopen(filename, "re");
40 if (!file) {
41 if (errno == ENOENT)
42 return 0;
43 else
ecb08ec6 44 return -errno;
f579559b
TG
45 }
46
6916ec29
TG
47 if (null_or_empty_path(filename)) {
48 log_debug("skipping empty file: %s", filename);
49 return 0;
50 }
51
f579559b
TG
52 network = new0(Network, 1);
53 if (!network)
54 return log_oom();
55
5a3eb5a7
TG
56 network->manager = manager;
57
f048a16b
TG
58 LIST_HEAD_INIT(network->static_addresses);
59 LIST_HEAD_INIT(network->static_routes);
f579559b 60
fe6b2d55 61 network->vlans = hashmap_new(string_hash_func, string_compare_func);
672682a6
TG
62 if (!network->vlans)
63 return log_oom();
64
fe6b2d55
TG
65 network->macvlans = hashmap_new(uint64_hash_func, uint64_compare_func);
66 if (!network->macvlans)
67 return log_oom();
68
6ae115c1
TG
69 network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
70 if (!network->addresses_by_section)
71 return log_oom();
72
73 network->routes_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
74 if (!network->routes_by_section)
75 return log_oom();
76
06f021a8
TG
77 network->dns = set_new(NULL, NULL);
78 if (!network->dns)
79 return log_oom();
80
6ae115c1
TG
81 network->filename = strdup(filename);
82 if (!network->filename)
83 return log_oom();
84
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
TG
97
98 LIST_FOREACH(static_routes, route, network->static_routes) {
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
106 LIST_FOREACH(static_addresses, address, network->static_addresses) {
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
TG
145void network_free(Network *network) {
146 Route *route;
147 Address *address;
06f021a8 148 Iterator i;
f579559b
TG
149
150 if (!network)
151 return;
152
153 free(network->filename);
154
155 free(network->match_mac);
156 free(network->match_path);
157 free(network->match_driver);
158 free(network->match_type);
159 free(network->match_name);
160
161 free(network->description);
162
06f021a8
TG
163 SET_FOREACH(address, network->dns, i)
164 address_free(address);
165
166 set_free(network->dns);
3bef724f 167
672682a6
TG
168 hashmap_free(network->vlans);
169
fe6b2d55
TG
170 hashmap_free(network->macvlans);
171
f048a16b 172 while ((route = network->static_routes))
f579559b
TG
173 route_free(route);
174
f048a16b 175 while ((address = network->static_addresses))
f579559b
TG
176 address_free(address);
177
6ae115c1
TG
178 hashmap_free(network->addresses_by_section);
179 hashmap_free(network->routes_by_section);
180
b3070dc0 181 if (network->manager && network->manager->networks)
7384fa92 182 LIST_REMOVE(networks, network->manager->networks, network);
f579559b 183
79e16ce3
LP
184 condition_free_list(network->match_host);
185 condition_free_list(network->match_virt);
186 condition_free_list(network->match_kernel);
187 condition_free_list(network->match_arch);
188
f579559b
TG
189 free(network);
190}
191
505f8da7
TG
192int network_get(Manager *manager, struct udev_device *device,
193 const char *ifname, const struct ether_addr *address,
194 Network **ret) {
f579559b
TG
195 Network *network;
196
197 assert(manager);
f579559b
TG
198 assert(ret);
199
f579559b
TG
200 LIST_FOREACH(networks, network, manager->networks) {
201 if (net_match_config(network->match_mac, network->match_path,
505f8da7
TG
202 network->match_driver, network->match_type,
203 network->match_name, network->match_host,
204 network->match_virt, network->match_kernel,
205 network->match_arch,
206 address,
207 udev_device_get_property_value(device, "ID_PATH"),
208 udev_device_get_driver(udev_device_get_parent(device)),
209 udev_device_get_property_value(device, "ID_NET_DRIVER"),
210 udev_device_get_devtype(device),
211 ifname)) {
212 log_debug("%s: found matching network '%s'", ifname,
213 network->filename);
f579559b
TG
214 *ret = network;
215 return 0;
216 }
217 }
218
219 *ret = NULL;
220
221 return -ENOENT;
222}
223
224int network_apply(Manager *manager, Network *network, Link *link) {
f579559b
TG
225 int r;
226
f579559b
TG
227 link->network = network;
228
3bef724f
TG
229 if (network->dns) {
230 r = manager_update_resolv_conf(manager);
231 if (r < 0)
232 return r;
233 }
234
f579559b
TG
235 return 0;
236}
02b59d57
TG
237
238int config_parse_bridge(const char *unit,
239 const char *filename,
240 unsigned line,
241 const char *section,
242 unsigned section_line,
243 const char *lvalue,
244 int ltype,
245 const char *rvalue,
246 void *data,
247 void *userdata) {
248 Network *network = userdata;
1a436809 249 NetDev *netdev;
02b59d57
TG
250 int r;
251
252 assert(filename);
253 assert(lvalue);
254 assert(rvalue);
255 assert(data);
256
52433f6b 257 r = netdev_get(network->manager, rvalue, &netdev);
02b59d57
TG
258 if (r < 0) {
259 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
260 "Bridge is invalid, ignoring assignment: %s", rvalue);
261 return 0;
262 }
263
52433f6b
TG
264 if (netdev->kind != NETDEV_KIND_BRIDGE) {
265 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1a436809 266 "NetDev is not a bridge, ignoring assignment: %s", rvalue);
52433f6b
TG
267 return 0;
268 }
269
270 network->bridge = netdev;
271
272 return 0;
273}
274
275int config_parse_bond(const char *unit,
276 const char *filename,
277 unsigned line,
278 const char *section,
279 unsigned section_line,
280 const char *lvalue,
281 int ltype,
282 const char *rvalue,
283 void *data,
284 void *userdata) {
285 Network *network = userdata;
1a436809 286 NetDev *netdev;
52433f6b
TG
287 int r;
288
289 assert(filename);
290 assert(lvalue);
291 assert(rvalue);
292 assert(data);
293
294 r = netdev_get(network->manager, rvalue, &netdev);
295 if (r < 0) {
296 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
297 "Bond is invalid, ignoring assignment: %s", rvalue);
298 return 0;
299 }
300
301 if (netdev->kind != NETDEV_KIND_BOND) {
302 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1a436809 303 "NetDev is not a bond, ignoring assignment: %s", rvalue);
52433f6b
TG
304 return 0;
305 }
306
307 network->bond = netdev;
02b59d57
TG
308
309 return 0;
310}
54abf461
TG
311
312int config_parse_vlan(const char *unit,
313 const char *filename,
314 unsigned line,
315 const char *section,
316 unsigned section_line,
317 const char *lvalue,
318 int ltype,
319 const char *rvalue,
320 void *data,
321 void *userdata) {
322 Network *network = userdata;
1a436809 323 NetDev *netdev;
54abf461
TG
324 int r;
325
326 assert(filename);
327 assert(lvalue);
328 assert(rvalue);
329 assert(data);
330
331 r = netdev_get(network->manager, rvalue, &netdev);
332 if (r < 0) {
333 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
334 "VLAN is invalid, ignoring assignment: %s", rvalue);
335 return 0;
336 }
337
338 if (netdev->kind != NETDEV_KIND_VLAN) {
339 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1a436809 340 "NetDev is not a VLAN, ignoring assignment: %s", rvalue);
54abf461
TG
341 return 0;
342 }
343
672682a6
TG
344 r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
345 if (r < 0) {
346 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
347 "Can not add VLAN to network: %s", rvalue);
348 return 0;
349 }
54abf461
TG
350
351 return 0;
352}
fe6b2d55
TG
353
354int config_parse_macvlan(const char *unit,
355 const char *filename,
356 unsigned line,
357 const char *section,
358 unsigned section_line,
359 const char *lvalue,
360 int ltype,
361 const char *rvalue,
362 void *data,
363 void *userdata) {
364 Network *network = userdata;
365 NetDev *netdev;
366 int r;
367
368 assert(filename);
369 assert(lvalue);
370 assert(rvalue);
371 assert(data);
372
373 r = netdev_get(network->manager, rvalue, &netdev);
374 if (r < 0) {
375 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
376 "MACVLAN is invalid, ignoring assignment: %s", rvalue);
377 return 0;
378 }
379
380 if (netdev->kind != NETDEV_KIND_MACVLAN) {
381 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
382 "NetDev is not a MACVLAN, ignoring assignment: %s", rvalue);
383 return 0;
384 }
385
386 r = hashmap_put(network->macvlans, netdev->name, netdev);
387 if (r < 0) {
388 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
389 "Can not add MACVLAN to network: %s", rvalue);
390 return 0;
391 }
392
393 return 0;
394}