chiark / gitweb /
net-util: match on the driver as exposed by ethtool if DRIVER not set
[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->vlans = hashmap_new(uint64_hash_func, uint64_compare_func);
57         if (!network->vlans)
58                 return log_oom();
59
60         network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
61         if (!network->addresses_by_section)
62                 return log_oom();
63
64         network->routes_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
65         if (!network->routes_by_section)
66                 return log_oom();
67
68         network->filename = strdup(filename);
69         if (!network->filename)
70                 return log_oom();
71
72         network->dhcp_dns = true;
73         network->dhcp_hostname = true;
74         network->dhcp_domainname = true;
75
76         r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCPv4\0", config_item_perf_lookup,
77                         (void*) network_network_gperf_lookup, false, false, network);
78         if (r < 0) {
79                 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
80                 return r;
81         }
82
83         LIST_PREPEND(networks, manager->networks, network);
84
85         LIST_FOREACH(static_routes, route, network->static_routes) {
86                 if (!route->family) {
87                         log_warning("Route section without Gateway field configured in %s. "
88                                     "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         hashmap_free(network->vlans);
152
153         while ((route = network->static_routes))
154                 route_free(route);
155
156         while ((address = network->static_addresses))
157                 address_free(address);
158
159         hashmap_free(network->addresses_by_section);
160         hashmap_free(network->routes_by_section);
161
162         if (network->manager && network->manager->networks)
163                 LIST_REMOVE(networks, network->manager->networks, network);
164
165         free(network);
166 }
167
168 int network_get(Manager *manager, struct udev_device *device, Network **ret) {
169         Network *network;
170
171         assert(manager);
172         assert(device);
173         assert(ret);
174
175         LIST_FOREACH(networks, network, manager->networks) {
176                 if (net_match_config(network->match_mac, network->match_path,
177                                         network->match_driver, network->match_type,
178                                         network->match_name, network->match_host,
179                                         network->match_virt, network->match_kernel,
180                                         network->match_arch,
181                                         udev_device_get_sysattr_value(device, "address"),
182                                         udev_device_get_property_value(device, "ID_PATH"),
183                                         udev_device_get_driver(udev_device_get_parent(device)),
184                                         udev_device_get_property_value(device, "ID_NET_DRIVER"),
185                                         udev_device_get_devtype(device),
186                                         udev_device_get_sysname(device))) {
187                         log_debug("%s: found matching network '%s'",
188                                         udev_device_get_sysname(device),
189                                         network->filename);
190                         *ret = network;
191                         return 0;
192                 }
193         }
194
195         *ret = NULL;
196
197         return -ENOENT;
198 }
199
200 int network_apply(Manager *manager, Network *network, Link *link) {
201         int r;
202
203         link->network = network;
204
205         r = link_configure(link);
206         if (r < 0)
207                 return r;
208
209         if (network->dns) {
210                 r = manager_update_resolv_conf(manager);
211                 if (r < 0)
212                         return r;
213         }
214
215         return 0;
216 }
217
218 int config_parse_bridge(const char *unit,
219                 const char *filename,
220                 unsigned line,
221                 const char *section,
222                 unsigned section_line,
223                 const char *lvalue,
224                 int ltype,
225                 const char *rvalue,
226                 void *data,
227                 void *userdata) {
228         Network *network = userdata;
229         NetDev *netdev;
230         int r;
231
232         assert(filename);
233         assert(lvalue);
234         assert(rvalue);
235         assert(data);
236
237         r = netdev_get(network->manager, rvalue, &netdev);
238         if (r < 0) {
239                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
240                            "Bridge is invalid, ignoring assignment: %s", rvalue);
241                 return 0;
242         }
243
244         if (netdev->kind != NETDEV_KIND_BRIDGE) {
245                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
246                            "NetDev is not a bridge, ignoring assignment: %s", rvalue);
247                 return 0;
248         }
249
250         network->bridge = netdev;
251
252         return 0;
253 }
254
255 int config_parse_bond(const char *unit,
256                 const char *filename,
257                 unsigned line,
258                 const char *section,
259                 unsigned section_line,
260                 const char *lvalue,
261                 int ltype,
262                 const char *rvalue,
263                 void *data,
264                 void *userdata) {
265         Network *network = userdata;
266         NetDev *netdev;
267         int r;
268
269         assert(filename);
270         assert(lvalue);
271         assert(rvalue);
272         assert(data);
273
274         r = netdev_get(network->manager, rvalue, &netdev);
275         if (r < 0) {
276                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
277                            "Bond is invalid, ignoring assignment: %s", rvalue);
278                 return 0;
279         }
280
281         if (netdev->kind != NETDEV_KIND_BOND) {
282                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
283                            "NetDev is not a bond, ignoring assignment: %s", rvalue);
284                 return 0;
285         }
286
287         network->bond = netdev;
288
289         return 0;
290 }
291
292 int config_parse_vlan(const char *unit,
293                 const char *filename,
294                 unsigned line,
295                 const char *section,
296                 unsigned section_line,
297                 const char *lvalue,
298                 int ltype,
299                 const char *rvalue,
300                 void *data,
301                 void *userdata) {
302         Network *network = userdata;
303         NetDev *netdev;
304         int r;
305
306         assert(filename);
307         assert(lvalue);
308         assert(rvalue);
309         assert(data);
310
311         r = netdev_get(network->manager, rvalue, &netdev);
312         if (r < 0) {
313                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
314                            "VLAN is invalid, ignoring assignment: %s", rvalue);
315                 return 0;
316         }
317
318         if (netdev->kind != NETDEV_KIND_VLAN) {
319                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
320                            "NetDev is not a VLAN, ignoring assignment: %s", rvalue);
321                 return 0;
322         }
323
324         r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
325         if (r < 0) {
326                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
327                            "Can not add VLAN to network: %s", rvalue);
328                 return 0;
329         }
330
331         return 0;
332 }