chiark / gitweb /
3119471fa25a8801bb4b3d4e9ce8dff8d0db1290
[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                                         udev_device_get_sysattr_value(device, "address"),
181                                         udev_device_get_property_value(device, "ID_PATH"),
182                                         udev_device_get_driver(udev_device_get_parent(device)),
183                                         udev_device_get_devtype(device),
184                                         udev_device_get_sysname(device))) {
185                         log_debug("%s: found matching network '%s'",
186                                         udev_device_get_sysname(device),
187                                         network->filename);
188                         *ret = network;
189                         return 0;
190                 }
191         }
192
193         *ret = NULL;
194
195         return -ENOENT;
196 }
197
198 int network_apply(Manager *manager, Network *network, Link *link) {
199         int r;
200
201         link->network = network;
202
203         r = link_configure(link);
204         if (r < 0)
205                 return r;
206
207         if (network->dns) {
208                 r = manager_update_resolv_conf(manager);
209                 if (r < 0)
210                         return r;
211         }
212
213         return 0;
214 }
215
216 int config_parse_bridge(const char *unit,
217                 const char *filename,
218                 unsigned line,
219                 const char *section,
220                 unsigned section_line,
221                 const char *lvalue,
222                 int ltype,
223                 const char *rvalue,
224                 void *data,
225                 void *userdata) {
226         Network *network = userdata;
227         NetDev *netdev;
228         int r;
229
230         assert(filename);
231         assert(lvalue);
232         assert(rvalue);
233         assert(data);
234
235         r = netdev_get(network->manager, rvalue, &netdev);
236         if (r < 0) {
237                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
238                            "Bridge is invalid, ignoring assignment: %s", rvalue);
239                 return 0;
240         }
241
242         if (netdev->kind != NETDEV_KIND_BRIDGE) {
243                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
244                            "NetDev is not a bridge, ignoring assignment: %s", rvalue);
245                 return 0;
246         }
247
248         network->bridge = netdev;
249
250         return 0;
251 }
252
253 int config_parse_bond(const char *unit,
254                 const char *filename,
255                 unsigned line,
256                 const char *section,
257                 unsigned section_line,
258                 const char *lvalue,
259                 int ltype,
260                 const char *rvalue,
261                 void *data,
262                 void *userdata) {
263         Network *network = userdata;
264         NetDev *netdev;
265         int r;
266
267         assert(filename);
268         assert(lvalue);
269         assert(rvalue);
270         assert(data);
271
272         r = netdev_get(network->manager, rvalue, &netdev);
273         if (r < 0) {
274                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
275                            "Bond is invalid, ignoring assignment: %s", rvalue);
276                 return 0;
277         }
278
279         if (netdev->kind != NETDEV_KIND_BOND) {
280                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
281                            "NetDev is not a bond, ignoring assignment: %s", rvalue);
282                 return 0;
283         }
284
285         network->bond = netdev;
286
287         return 0;
288 }
289
290 int config_parse_vlan(const char *unit,
291                 const char *filename,
292                 unsigned line,
293                 const char *section,
294                 unsigned section_line,
295                 const char *lvalue,
296                 int ltype,
297                 const char *rvalue,
298                 void *data,
299                 void *userdata) {
300         Network *network = userdata;
301         NetDev *netdev;
302         int r;
303
304         assert(filename);
305         assert(lvalue);
306         assert(rvalue);
307         assert(data);
308
309         r = netdev_get(network->manager, rvalue, &netdev);
310         if (r < 0) {
311                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
312                            "VLAN is invalid, ignoring assignment: %s", rvalue);
313                 return 0;
314         }
315
316         if (netdev->kind != NETDEV_KIND_VLAN) {
317                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
318                            "NetDev is not a VLAN, ignoring assignment: %s", rvalue);
319                 return 0;
320         }
321
322         r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
323         if (r < 0) {
324                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
325                            "Can not add VLAN to network: %s", rvalue);
326                 return 0;
327         }
328
329         return 0;
330 }