chiark / gitweb /
f2546440cf55eb8e9fd32af665a2f6cf45e4b9b6
[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         LIST_FOREACH(networks, network, manager->networks) {
170                 if (net_match_config(network->match_mac, network->match_path,
171                                         network->match_driver, network->match_type,
172                                         network->match_name,
173                                         udev_device_get_sysattr_value(device, "address"),
174                                         udev_device_get_property_value(device, "ID_PATH"),
175                                         udev_device_get_driver(device),
176                                         udev_device_get_devtype(device),
177                                         udev_device_get_sysname(device))) {
178                         log_debug("%s: found matching network '%s'",
179                                         udev_device_get_sysname(device),
180                                         network->filename);
181                         *ret = network;
182                         return 0;
183                 }
184         }
185
186         *ret = NULL;
187
188         return -ENOENT;
189 }
190
191 int network_apply(Manager *manager, Network *network, Link *link) {
192         int r;
193
194         link->network = network;
195
196         r = link_configure(link);
197         if (r < 0)
198                 return r;
199
200         return 0;
201 }
202
203 int config_parse_bridge(const char *unit,
204                 const char *filename,
205                 unsigned line,
206                 const char *section,
207                 unsigned section_line,
208                 const char *lvalue,
209                 int ltype,
210                 const char *rvalue,
211                 void *data,
212                 void *userdata) {
213         Network *network = userdata;
214         Bridge *bridge;
215         int r;
216
217         assert(filename);
218         assert(lvalue);
219         assert(rvalue);
220         assert(data);
221
222         r = bridge_get(network->manager, rvalue, &bridge);
223         if (r < 0) {
224                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
225                            "Bridge is invalid, ignoring assignment: %s", rvalue);
226                 return 0;
227         }
228
229         network->bridge = bridge;
230
231         return 0;
232 }