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