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