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