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