]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
networkd: VLAN - allow multiple vlans to be created on a link
[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_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,
179 udev_device_get_sysattr_value(device, "address"),
180 udev_device_get_property_value(device, "ID_PATH"),
181 udev_device_get_driver(device),
182 udev_device_get_devtype(device),
183 udev_device_get_sysname(device))) {
184 log_debug("%s: found matching network '%s'",
185 udev_device_get_sysname(device),
186 network->filename);
187 *ret = network;
188 return 0;
189 }
190 }
191
192 *ret = NULL;
193
194 return -ENOENT;
195 }
196
197 int network_apply(Manager *manager, Network *network, Link *link) {
198 int r;
199
200 link->network = network;
201
202 r = link_configure(link);
203 if (r < 0)
204 return r;
205
206 if (network->dns) {
207 r = manager_update_resolv_conf(manager);
208 if (r < 0)
209 return r;
210 }
211
212 return 0;
213 }
214
215 int config_parse_bridge(const char *unit,
216 const char *filename,
217 unsigned line,
218 const char *section,
219 unsigned section_line,
220 const char *lvalue,
221 int ltype,
222 const char *rvalue,
223 void *data,
224 void *userdata) {
225 Network *network = userdata;
226 NetDev *netdev;
227 int r;
228
229 assert(filename);
230 assert(lvalue);
231 assert(rvalue);
232 assert(data);
233
234 r = netdev_get(network->manager, rvalue, &netdev);
235 if (r < 0) {
236 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
237 "Bridge is invalid, ignoring assignment: %s", rvalue);
238 return 0;
239 }
240
241 if (netdev->kind != NETDEV_KIND_BRIDGE) {
242 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
243 "NetDev is not a bridge, ignoring assignment: %s", rvalue);
244 return 0;
245 }
246
247 network->bridge = netdev;
248
249 return 0;
250 }
251
252 int config_parse_bond(const char *unit,
253 const char *filename,
254 unsigned line,
255 const char *section,
256 unsigned section_line,
257 const char *lvalue,
258 int ltype,
259 const char *rvalue,
260 void *data,
261 void *userdata) {
262 Network *network = userdata;
263 NetDev *netdev;
264 int r;
265
266 assert(filename);
267 assert(lvalue);
268 assert(rvalue);
269 assert(data);
270
271 r = netdev_get(network->manager, rvalue, &netdev);
272 if (r < 0) {
273 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
274 "Bond is invalid, ignoring assignment: %s", rvalue);
275 return 0;
276 }
277
278 if (netdev->kind != NETDEV_KIND_BOND) {
279 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
280 "NetDev is not a bond, ignoring assignment: %s", rvalue);
281 return 0;
282 }
283
284 network->bond = netdev;
285
286 return 0;
287 }
288
289 int config_parse_vlan(const char *unit,
290 const char *filename,
291 unsigned line,
292 const char *section,
293 unsigned section_line,
294 const char *lvalue,
295 int ltype,
296 const char *rvalue,
297 void *data,
298 void *userdata) {
299 Network *network = userdata;
300 NetDev *netdev;
301 int r;
302
303 assert(filename);
304 assert(lvalue);
305 assert(rvalue);
306 assert(data);
307
308 r = netdev_get(network->manager, rvalue, &netdev);
309 if (r < 0) {
310 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
311 "VLAN is invalid, ignoring assignment: %s", rvalue);
312 return 0;
313 }
314
315 if (netdev->kind != NETDEV_KIND_VLAN) {
316 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
317 "NetDev is not a VLAN, ignoring assignment: %s", rvalue);
318 return 0;
319 }
320
321 r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
322 if (r < 0) {
323 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
324 "Can not add VLAN to network: %s", rvalue);
325 return 0;
326 }
327
328 return 0;
329 }