]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
networkd: add basic support for MACVLANs
[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(string_hash_func, string_compare_func);
57 if (!network->vlans)
58 return log_oom();
59
60 network->macvlans = hashmap_new(uint64_hash_func, uint64_compare_func);
61 if (!network->macvlans)
62 return log_oom();
63
64 network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
65 if (!network->addresses_by_section)
66 return log_oom();
67
68 network->routes_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
69 if (!network->routes_by_section)
70 return log_oom();
71
72 network->filename = strdup(filename);
73 if (!network->filename)
74 return log_oom();
75
76 network->dhcp_dns = true;
77 network->dhcp_hostname = true;
78 network->dhcp_domainname = true;
79
80 r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCPv4\0", config_item_perf_lookup,
81 (void*) network_network_gperf_lookup, false, false, network);
82 if (r < 0) {
83 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
84 return r;
85 }
86
87 LIST_PREPEND(networks, manager->networks, network);
88
89 LIST_FOREACH(static_routes, route, network->static_routes) {
90 if (!route->family) {
91 log_warning("Route section without Gateway field configured in %s. "
92 "Ignoring", filename);
93 return 0;
94 }
95 }
96
97 LIST_FOREACH(static_addresses, address, network->static_addresses) {
98 if (!address->family) {
99 log_warning("Address section without Address field configured in %s. "
100 "Ignoring", filename);
101 return 0;
102 }
103 }
104
105 network = NULL;
106
107 return 0;
108 }
109
110 int network_load(Manager *manager) {
111 Network *network;
112 _cleanup_strv_free_ char **files = NULL;
113 char **f;
114 int r;
115
116 assert(manager);
117
118 while ((network = manager->networks))
119 network_free(network);
120
121 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
122 if (r < 0) {
123 log_error("Failed to enumerate network files: %s", strerror(-r));
124 return r;
125 }
126
127 STRV_FOREACH_BACKWARDS(f, files) {
128 r = network_load_one(manager, *f);
129 if (r < 0)
130 return r;
131 }
132
133 return 0;
134 }
135
136 void network_free(Network *network) {
137 Route *route;
138 Address *address;
139
140 if (!network)
141 return;
142
143 free(network->filename);
144
145 free(network->match_mac);
146 free(network->match_path);
147 free(network->match_driver);
148 free(network->match_type);
149 free(network->match_name);
150
151 free(network->description);
152
153 address_free(network->dns);
154
155 hashmap_free(network->vlans);
156
157 hashmap_free(network->macvlans);
158
159 while ((route = network->static_routes))
160 route_free(route);
161
162 while ((address = network->static_addresses))
163 address_free(address);
164
165 hashmap_free(network->addresses_by_section);
166 hashmap_free(network->routes_by_section);
167
168 if (network->manager && network->manager->networks)
169 LIST_REMOVE(networks, network->manager->networks, network);
170
171 free(network);
172 }
173
174 int network_get(Manager *manager, struct udev_device *device, Network **ret) {
175 Network *network;
176
177 assert(manager);
178 assert(device);
179 assert(ret);
180
181 LIST_FOREACH(networks, network, manager->networks) {
182 if (net_match_config(network->match_mac, network->match_path,
183 network->match_driver, network->match_type,
184 network->match_name, network->match_host,
185 network->match_virt, network->match_kernel,
186 network->match_arch,
187 udev_device_get_sysattr_value(device, "address"),
188 udev_device_get_property_value(device, "ID_PATH"),
189 udev_device_get_driver(udev_device_get_parent(device)),
190 udev_device_get_property_value(device, "ID_NET_DRIVER"),
191 udev_device_get_devtype(device),
192 udev_device_get_sysname(device))) {
193 log_debug("%s: found matching network '%s'",
194 udev_device_get_sysname(device),
195 network->filename);
196 *ret = network;
197 return 0;
198 }
199 }
200
201 *ret = NULL;
202
203 return -ENOENT;
204 }
205
206 int network_apply(Manager *manager, Network *network, Link *link) {
207 int r;
208
209 link->network = network;
210
211 r = link_configure(link);
212 if (r < 0)
213 return r;
214
215 if (network->dns) {
216 r = manager_update_resolv_conf(manager);
217 if (r < 0)
218 return r;
219 }
220
221 return 0;
222 }
223
224 int config_parse_bridge(const char *unit,
225 const char *filename,
226 unsigned line,
227 const char *section,
228 unsigned section_line,
229 const char *lvalue,
230 int ltype,
231 const char *rvalue,
232 void *data,
233 void *userdata) {
234 Network *network = userdata;
235 NetDev *netdev;
236 int r;
237
238 assert(filename);
239 assert(lvalue);
240 assert(rvalue);
241 assert(data);
242
243 r = netdev_get(network->manager, rvalue, &netdev);
244 if (r < 0) {
245 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
246 "Bridge is invalid, ignoring assignment: %s", rvalue);
247 return 0;
248 }
249
250 if (netdev->kind != NETDEV_KIND_BRIDGE) {
251 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
252 "NetDev is not a bridge, ignoring assignment: %s", rvalue);
253 return 0;
254 }
255
256 network->bridge = netdev;
257
258 return 0;
259 }
260
261 int config_parse_bond(const char *unit,
262 const char *filename,
263 unsigned line,
264 const char *section,
265 unsigned section_line,
266 const char *lvalue,
267 int ltype,
268 const char *rvalue,
269 void *data,
270 void *userdata) {
271 Network *network = userdata;
272 NetDev *netdev;
273 int r;
274
275 assert(filename);
276 assert(lvalue);
277 assert(rvalue);
278 assert(data);
279
280 r = netdev_get(network->manager, rvalue, &netdev);
281 if (r < 0) {
282 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
283 "Bond is invalid, ignoring assignment: %s", rvalue);
284 return 0;
285 }
286
287 if (netdev->kind != NETDEV_KIND_BOND) {
288 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
289 "NetDev is not a bond, ignoring assignment: %s", rvalue);
290 return 0;
291 }
292
293 network->bond = netdev;
294
295 return 0;
296 }
297
298 int config_parse_vlan(const char *unit,
299 const char *filename,
300 unsigned line,
301 const char *section,
302 unsigned section_line,
303 const char *lvalue,
304 int ltype,
305 const char *rvalue,
306 void *data,
307 void *userdata) {
308 Network *network = userdata;
309 NetDev *netdev;
310 int r;
311
312 assert(filename);
313 assert(lvalue);
314 assert(rvalue);
315 assert(data);
316
317 r = netdev_get(network->manager, rvalue, &netdev);
318 if (r < 0) {
319 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
320 "VLAN is invalid, ignoring assignment: %s", rvalue);
321 return 0;
322 }
323
324 if (netdev->kind != NETDEV_KIND_VLAN) {
325 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
326 "NetDev is not a VLAN, ignoring assignment: %s", rvalue);
327 return 0;
328 }
329
330 r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
331 if (r < 0) {
332 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
333 "Can not add VLAN to network: %s", rvalue);
334 return 0;
335 }
336
337 return 0;
338 }
339
340 int config_parse_macvlan(const char *unit,
341 const char *filename,
342 unsigned line,
343 const char *section,
344 unsigned section_line,
345 const char *lvalue,
346 int ltype,
347 const char *rvalue,
348 void *data,
349 void *userdata) {
350 Network *network = userdata;
351 NetDev *netdev;
352 int r;
353
354 assert(filename);
355 assert(lvalue);
356 assert(rvalue);
357 assert(data);
358
359 r = netdev_get(network->manager, rvalue, &netdev);
360 if (r < 0) {
361 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
362 "MACVLAN is invalid, ignoring assignment: %s", rvalue);
363 return 0;
364 }
365
366 if (netdev->kind != NETDEV_KIND_MACVLAN) {
367 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
368 "NetDev is not a MACVLAN, ignoring assignment: %s", rvalue);
369 return 0;
370 }
371
372 r = hashmap_put(network->macvlans, netdev->name, netdev);
373 if (r < 0) {
374 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
375 "Can not add MACVLAN to network: %s", rvalue);
376 return 0;
377 }
378
379 return 0;
380 }