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