]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
net-util: match on the driver as exposed by ethtool if DRIVER not set
[thirdparty/systemd.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 }