chiark / gitweb /
2e68bec2e745a520b24aa105e1ade33092d4efa1
[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(uint64_hash_func, uint64_compare_func);
57         if (!network->vlans)
58                 return log_oom();
59
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
72         network->dhcp_dns = true;
73         network->dhcp_hostname = true;
74         network->dhcp_domainname = true;
75
76         r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCPv4\0", config_item_perf_lookup,
77                         (void*) network_network_gperf_lookup, false, false, network);
78         if (r < 0) {
79                 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
80                 return r;
81         }
82
83         LIST_PREPEND(networks, manager->networks, network);
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                 }
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
101         network = NULL;
102
103         return 0;
104 }
105
106 int network_load(Manager *manager) {
107         Network *network;
108         _cleanup_strv_free_ char **files = NULL;
109         char **f;
110         int r;
111
112         assert(manager);
113
114         while ((network = manager->networks))
115                 network_free(network);
116
117         r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
118         if (r < 0) {
119                 log_error("Failed to enumerate network files: %s", strerror(-r));
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
129         return 0;
130 }
131
132 void 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
149         address_free(network->dns);
150
151         hashmap_free(network->vlans);
152
153         while ((route = network->static_routes))
154                 route_free(route);
155
156         while ((address = network->static_addresses))
157                 address_free(address);
158
159         hashmap_free(network->addresses_by_section);
160         hashmap_free(network->routes_by_section);
161
162         if (network->manager && network->manager->networks)
163                 LIST_REMOVE(networks, network->manager->networks, network);
164
165         free(network);
166 }
167
168 int network_get(Manager *manager, struct udev_device *device, Network **ret) {
169         Network *network;
170
171         assert(manager);
172         assert(device);
173         assert(ret);
174
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,
178                                         network->match_name, network->match_host,
179                                         network->match_virt, network->match_kernel,
180                                         network->match_arch,
181                                         udev_device_get_sysattr_value(device, "address"),
182                                         udev_device_get_property_value(device, "ID_PATH"),
183                                         udev_device_get_driver(udev_device_get_parent(device)),
184                                         udev_device_get_devtype(device),
185                                         udev_device_get_sysname(device))) {
186                         log_debug("%s: found matching network '%s'",
187                                         udev_device_get_sysname(device),
188                                         network->filename);
189                         *ret = network;
190                         return 0;
191                 }
192         }
193
194         *ret = NULL;
195
196         return -ENOENT;
197 }
198
199 int network_apply(Manager *manager, Network *network, Link *link) {
200         int r;
201
202         link->network = network;
203
204         r = link_configure(link);
205         if (r < 0)
206                 return r;
207
208         if (network->dns) {
209                 r = manager_update_resolv_conf(manager);
210                 if (r < 0)
211                         return r;
212         }
213
214         return 0;
215 }
216
217 int config_parse_bridge(const char *unit,
218                 const char *filename,
219                 unsigned line,
220                 const char *section,
221                 unsigned section_line,
222                 const char *lvalue,
223                 int ltype,
224                 const char *rvalue,
225                 void *data,
226                 void *userdata) {
227         Network *network = userdata;
228         NetDev *netdev;
229         int r;
230
231         assert(filename);
232         assert(lvalue);
233         assert(rvalue);
234         assert(data);
235
236         r = netdev_get(network->manager, rvalue, &netdev);
237         if (r < 0) {
238                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
239                            "Bridge is invalid, ignoring assignment: %s", rvalue);
240                 return 0;
241         }
242
243         if (netdev->kind != NETDEV_KIND_BRIDGE) {
244                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
245                            "NetDev is not a bridge, ignoring assignment: %s", rvalue);
246                 return 0;
247         }
248
249         network->bridge = netdev;
250
251         return 0;
252 }
253
254 int config_parse_bond(const char *unit,
255                 const char *filename,
256                 unsigned line,
257                 const char *section,
258                 unsigned section_line,
259                 const char *lvalue,
260                 int ltype,
261                 const char *rvalue,
262                 void *data,
263                 void *userdata) {
264         Network *network = userdata;
265         NetDev *netdev;
266         int r;
267
268         assert(filename);
269         assert(lvalue);
270         assert(rvalue);
271         assert(data);
272
273         r = netdev_get(network->manager, rvalue, &netdev);
274         if (r < 0) {
275                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
276                            "Bond is invalid, ignoring assignment: %s", rvalue);
277                 return 0;
278         }
279
280         if (netdev->kind != NETDEV_KIND_BOND) {
281                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
282                            "NetDev is not a bond, ignoring assignment: %s", rvalue);
283                 return 0;
284         }
285
286         network->bond = netdev;
287
288         return 0;
289 }
290
291 int config_parse_vlan(const char *unit,
292                 const char *filename,
293                 unsigned line,
294                 const char *section,
295                 unsigned section_line,
296                 const char *lvalue,
297                 int ltype,
298                 const char *rvalue,
299                 void *data,
300                 void *userdata) {
301         Network *network = userdata;
302         NetDev *netdev;
303         int r;
304
305         assert(filename);
306         assert(lvalue);
307         assert(rvalue);
308         assert(data);
309
310         r = netdev_get(network->manager, rvalue, &netdev);
311         if (r < 0) {
312                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
313                            "VLAN is invalid, ignoring assignment: %s", rvalue);
314                 return 0;
315         }
316
317         if (netdev->kind != NETDEV_KIND_VLAN) {
318                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
319                            "NetDev is not a VLAN, ignoring assignment: %s", rvalue);
320                 return 0;
321         }
322
323         r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
324         if (r < 0) {
325                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
326                            "Can not add VLAN to network: %s", rvalue);
327                 return 0;
328         }
329
330         return 0;
331 }