chiark / gitweb /
498dea65fe8d76f229d1c5544e4e3d4e64011e84
[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
70         r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCPv4\0", config_item_perf_lookup,
71                         (void*) network_gperf_lookup, false, false, network);
72         if (r < 0) {
73                 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
74                 return r;
75         }
76
77         LIST_PREPEND(networks, manager->networks, network);
78
79         LIST_FOREACH(static_routes, route, network->static_routes) {
80                 if (!route->family) {
81                         log_warning("Route section without Gateway field configured in %s. "
82                                     "Ignoring", filename);
83                         return 0;
84                 }
85
86                 if (route->dst_family && route->family != route->dst_family) {
87                         log_warning("Route section with conflicting Gateway and Destination address "
88                                     "family configured in %s. 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         while ((route = network->static_routes))
152                 route_free(route);
153
154         while ((address = network->static_addresses))
155                 address_free(address);
156
157         hashmap_free(network->addresses_by_section);
158         hashmap_free(network->routes_by_section);
159
160         if (network->manager && network->manager->networks)
161                 LIST_REMOVE(networks, network->manager->networks, network);
162
163         free(network);
164 }
165
166 int network_get(Manager *manager, struct udev_device *device, Network **ret) {
167         Network *network;
168
169         assert(manager);
170         assert(device);
171         assert(ret);
172
173         LIST_FOREACH(networks, network, manager->networks) {
174                 if (net_match_config(network->match_mac, network->match_path,
175                                         network->match_driver, network->match_type,
176                                         network->match_name,
177                                         udev_device_get_sysattr_value(device, "address"),
178                                         udev_device_get_property_value(device, "ID_PATH"),
179                                         udev_device_get_driver(device),
180                                         udev_device_get_devtype(device),
181                                         udev_device_get_sysname(device))) {
182                         log_debug("%s: found matching network '%s'",
183                                         udev_device_get_sysname(device),
184                                         network->filename);
185                         *ret = network;
186                         return 0;
187                 }
188         }
189
190         *ret = NULL;
191
192         return -ENOENT;
193 }
194
195 int network_apply(Manager *manager, Network *network, Link *link) {
196         int r;
197
198         link->network = network;
199
200         r = link_configure(link);
201         if (r < 0)
202                 return r;
203
204         if (network->dns) {
205                 r = manager_update_resolv_conf(manager);
206                 if (r < 0)
207                         return r;
208         }
209
210         return 0;
211 }
212
213 int config_parse_bridge(const char *unit,
214                 const char *filename,
215                 unsigned line,
216                 const char *section,
217                 unsigned section_line,
218                 const char *lvalue,
219                 int ltype,
220                 const char *rvalue,
221                 void *data,
222                 void *userdata) {
223         Network *network = userdata;
224         Bridge *bridge;
225         int r;
226
227         assert(filename);
228         assert(lvalue);
229         assert(rvalue);
230         assert(data);
231
232         r = bridge_get(network->manager, rvalue, &bridge);
233         if (r < 0) {
234                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
235                            "Bridge is invalid, ignoring assignment: %s", rvalue);
236                 return 0;
237         }
238
239         network->bridge = bridge;
240
241         return 0;
242 }