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