chiark / gitweb /
1606042264b584758f9a7cd7b80076d17c1acc4b
[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         while ((route = network->static_routes))
148                 route_free(route);
149
150         while ((address = network->static_addresses))
151                 address_free(address);
152
153         hashmap_free(network->addresses_by_section);
154         hashmap_free(network->routes_by_section);
155
156         if (network->manager && network->manager->networks)
157                 LIST_REMOVE(networks, network->manager->networks, network);
158
159         free(network);
160 }
161
162 int network_get(Manager *manager, struct udev_device *device, Network **ret) {
163         Network *network;
164
165         assert(manager);
166         assert(device);
167         assert(ret);
168
169         if (manager_should_reload(manager))
170                 manager_load_config(manager);
171
172         LIST_FOREACH(networks, network, manager->networks) {
173                 if (net_match_config(network->match_mac, network->match_path,
174                                         network->match_driver, network->match_type,
175                                         network->match_name,
176                                         udev_device_get_sysattr_value(device, "address"),
177                                         udev_device_get_property_value(device, "ID_PATH"),
178                                         udev_device_get_driver(device),
179                                         udev_device_get_devtype(device),
180                                         udev_device_get_sysname(device))) {
181                         log_debug("%s: found matching network '%s'",
182                                         udev_device_get_sysname(device),
183                                         network->filename);
184                         *ret = network;
185                         return 0;
186                 }
187         }
188
189         *ret = NULL;
190
191         return -ENOENT;
192 }
193
194 int network_apply(Manager *manager, Network *network, Link *link) {
195         int r;
196
197         link->network = network;
198
199         r = link_configure(link);
200         if (r < 0)
201                 return r;
202
203         return 0;
204 }
205
206 int config_parse_bridge(const char *unit,
207                 const char *filename,
208                 unsigned line,
209                 const char *section,
210                 unsigned section_line,
211                 const char *lvalue,
212                 int ltype,
213                 const char *rvalue,
214                 void *data,
215                 void *userdata) {
216         Network *network = userdata;
217         Bridge *bridge;
218         int r;
219
220         assert(filename);
221         assert(lvalue);
222         assert(rvalue);
223         assert(data);
224
225         r = bridge_get(network->manager, rvalue, &bridge);
226         if (r < 0) {
227                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
228                            "Bridge is invalid, ignoring assignment: %s", rvalue);
229                 return 0;
230         }
231
232         network->bridge = bridge;
233
234         return 0;
235 }