]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
networkd: network - merge all netdev parsing into one function
[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
TG
147void network_free(Network *network) {
148 Route *route;
149 Address *address;
06f021a8 150 Iterator i;
f579559b
TG
151
152 if (!network)
153 return;
154
155 free(network->filename);
156
157 free(network->match_mac);
158 free(network->match_path);
159 free(network->match_driver);
160 free(network->match_type);
161 free(network->match_name);
162
163 free(network->description);
164
06f021a8
TG
165 SET_FOREACH(address, network->dns, i)
166 address_free(address);
167
168 set_free(network->dns);
3bef724f 169
672682a6
TG
170 hashmap_free(network->vlans);
171
fe6b2d55
TG
172 hashmap_free(network->macvlans);
173
f048a16b 174 while ((route = network->static_routes))
f579559b
TG
175 route_free(route);
176
f048a16b 177 while ((address = network->static_addresses))
f579559b
TG
178 address_free(address);
179
6ae115c1
TG
180 hashmap_free(network->addresses_by_section);
181 hashmap_free(network->routes_by_section);
182
b3070dc0 183 if (network->manager && network->manager->networks)
7384fa92 184 LIST_REMOVE(networks, network->manager->networks, network);
f579559b 185
79e16ce3
LP
186 condition_free_list(network->match_host);
187 condition_free_list(network->match_virt);
188 condition_free_list(network->match_kernel);
189 condition_free_list(network->match_arch);
190
f579559b
TG
191 free(network);
192}
193
505f8da7
TG
194int network_get(Manager *manager, struct udev_device *device,
195 const char *ifname, const struct ether_addr *address,
196 Network **ret) {
f579559b
TG
197 Network *network;
198
199 assert(manager);
f579559b
TG
200 assert(ret);
201
f579559b
TG
202 LIST_FOREACH(networks, network, manager->networks) {
203 if (net_match_config(network->match_mac, network->match_path,
505f8da7
TG
204 network->match_driver, network->match_type,
205 network->match_name, network->match_host,
206 network->match_virt, network->match_kernel,
207 network->match_arch,
208 address,
209 udev_device_get_property_value(device, "ID_PATH"),
210 udev_device_get_driver(udev_device_get_parent(device)),
211 udev_device_get_property_value(device, "ID_NET_DRIVER"),
212 udev_device_get_devtype(device),
213 ifname)) {
214 log_debug("%s: found matching network '%s'", ifname,
215 network->filename);
f579559b
TG
216 *ret = network;
217 return 0;
218 }
219 }
220
221 *ret = NULL;
222
223 return -ENOENT;
224}
225
226int network_apply(Manager *manager, Network *network, Link *link) {
f579559b
TG
227 int r;
228
f579559b
TG
229 link->network = network;
230
3bef724f
TG
231 if (network->dns) {
232 r = manager_update_resolv_conf(manager);
233 if (r < 0)
234 return r;
235 }
236
f579559b
TG
237 return 0;
238}
02b59d57 239
69a93e7d 240int config_parse_netdev(const char *unit,
02b59d57
TG
241 const char *filename,
242 unsigned line,
243 const char *section,
244 unsigned section_line,
245 const char *lvalue,
246 int ltype,
247 const char *rvalue,
248 void *data,
249 void *userdata) {
250 Network *network = userdata;
69a93e7d 251 char *kind_string, *p;
1a436809 252 NetDev *netdev;
69a93e7d 253 NetDevKind kind;
02b59d57
TG
254 int r;
255
256 assert(filename);
257 assert(lvalue);
258 assert(rvalue);
259 assert(data);
260
69a93e7d
TG
261 kind_string = strdup(lvalue);
262 if (!kind_string)
263 return log_oom();
52433f6b 264
69a93e7d
TG
265 /* the keys are CamelCase versions of the kind */
266 for (p = kind_string; *p; p++)
267 *p = tolower(*p);
52433f6b 268
69a93e7d
TG
269 kind = netdev_kind_from_string(kind_string);
270 if (kind == _NETDEV_KIND_INVALID) {
52433f6b 271 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
69a93e7d 272 "Invalid NetDev kind: %s", lvalue);
52433f6b
TG
273 return 0;
274 }
275
54abf461
TG
276 r = netdev_get(network->manager, rvalue, &netdev);
277 if (r < 0) {
278 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
69a93e7d 279 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
280 return 0;
281 }
282
69a93e7d 283 if (netdev->kind != kind) {
54abf461 284 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
69a93e7d 285 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
286 return 0;
287 }
288
69a93e7d
TG
289 switch (kind) {
290 case NETDEV_KIND_BRIDGE:
291 network->bridge = netdev;
54abf461 292
69a93e7d
TG
293 break;
294 case NETDEV_KIND_BOND:
295 network->bond = netdev;
fe6b2d55 296
69a93e7d
TG
297 break;
298 case NETDEV_KIND_VLAN:
299 r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
300 if (r < 0) {
301 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
302 "Can not add VLAN to network: %s", rvalue);
303 return 0;
304 }
fe6b2d55 305
69a93e7d
TG
306 break;
307 case NETDEV_KIND_MACVLAN:
308 r = hashmap_put(network->macvlans, netdev->name, netdev);
309 if (r < 0) {
310 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
311 "Can not add MACVLAN to network: %s", rvalue);
312 return 0;
313 }
fe6b2d55 314
69a93e7d
TG
315 break;
316 default:
317 assert_not_reached("Can not parse NetDev");
fe6b2d55
TG
318 }
319
320 return 0;
321}