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