chiark / gitweb /
f9873100114f5a8186c4ead70f170be8990a0184
[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         r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0", config_item_perf_lookup,
69                         (void*) network_gperf_lookup, false, false, network);
70         if (r < 0) {
71                 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
72                 return r;
73         }
74
75         LIST_PREPEND(networks, manager->networks, network);
76
77         LIST_FOREACH(static_routes, route, network->static_routes) {
78                 if (!route->family) {
79                         log_warning("Route section without Gateway field configured in %s. "
80                                     "Ignoring", filename);
81                         return 0;
82                 }
83
84                 if (route->dst_family && route->family != route->dst_family) {
85                         log_warning("Route section with conflicting Gateway and Destination address "
86                                     "family configured in %s. Ignoring", filename);
87                         return 0;
88                 }
89         }
90
91         LIST_FOREACH(static_addresses, address, network->static_addresses) {
92                 if (!address->family) {
93                         log_warning("Address section without Address field configured in %s. "
94                                     "Ignoring", filename);
95                         return 0;
96                 }
97         }
98
99         network = NULL;
100
101         return 0;
102 }
103
104 int network_load(Manager *manager) {
105         Network *network;
106         _cleanup_strv_free_ char **files = NULL;
107         char **f;
108         int r;
109
110         assert(manager);
111
112         while ((network = manager->networks))
113                 network_free(network);
114
115         r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
116         if (r < 0) {
117                 log_error("Failed to enumerate network files: %s", strerror(-r));
118                 return r;
119         }
120
121         STRV_FOREACH_BACKWARDS(f, files) {
122                 r = network_load_one(manager, *f);
123                 if (r < 0)
124                         return r;
125         }
126
127         return 0;
128 }
129
130 void network_free(Network *network) {
131         Route *route;
132         Address *address;
133
134         if (!network)
135                 return;
136
137         free(network->filename);
138
139         free(network->match_mac);
140         free(network->match_path);
141         free(network->match_driver);
142         free(network->match_type);
143         free(network->match_name);
144
145         free(network->description);
146
147         address_free(network->dns);
148
149         while ((route = network->static_routes))
150                 route_free(route);
151
152         while ((address = network->static_addresses))
153                 address_free(address);
154
155         hashmap_free(network->addresses_by_section);
156         hashmap_free(network->routes_by_section);
157
158         if (network->manager && network->manager->networks)
159                 LIST_REMOVE(networks, network->manager->networks, network);
160
161         free(network);
162 }
163
164 int network_get(Manager *manager, struct udev_device *device, Network **ret) {
165         Network *network;
166
167         assert(manager);
168         assert(device);
169         assert(ret);
170
171         LIST_FOREACH(networks, network, manager->networks) {
172                 if (net_match_config(network->match_mac, network->match_path,
173                                         network->match_driver, network->match_type,
174                                         network->match_name,
175                                         udev_device_get_sysattr_value(device, "address"),
176                                         udev_device_get_property_value(device, "ID_PATH"),
177                                         udev_device_get_driver(device),
178                                         udev_device_get_devtype(device),
179                                         udev_device_get_sysname(device))) {
180                         log_debug("%s: found matching network '%s'",
181                                         udev_device_get_sysname(device),
182                                         network->filename);
183                         *ret = network;
184                         return 0;
185                 }
186         }
187
188         *ret = NULL;
189
190         return -ENOENT;
191 }
192
193 int network_apply(Manager *manager, Network *network, Link *link) {
194         int r;
195
196         link->network = network;
197
198         r = link_configure(link);
199         if (r < 0)
200                 return r;
201
202         if (network->dns) {
203                 r = manager_update_resolv_conf(manager);
204                 if (r < 0)
205                         return r;
206         }
207
208         return 0;
209 }
210
211 int config_parse_bridge(const char *unit,
212                 const char *filename,
213                 unsigned line,
214                 const char *section,
215                 unsigned section_line,
216                 const char *lvalue,
217                 int ltype,
218                 const char *rvalue,
219                 void *data,
220                 void *userdata) {
221         Network *network = userdata;
222         Bridge *bridge;
223         int r;
224
225         assert(filename);
226         assert(lvalue);
227         assert(rvalue);
228         assert(data);
229
230         r = bridge_get(network->manager, rvalue, &bridge);
231         if (r < 0) {
232                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
233                            "Bridge is invalid, ignoring assignment: %s", rvalue);
234                 return 0;
235         }
236
237         network->bridge = bridge;
238
239         return 0;
240 }