]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
sd-network: expose DNS information
[thirdparty/systemd.git] / src / network / networkd-network.c
CommitLineData
f579559b
TG
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
69a93e7d 22#include <ctype.h>
987efa17 23#include <net/if.h>
69a93e7d 24
f579559b 25#include "networkd.h"
c6f7c917 26#include "network-internal.h"
f579559b
TG
27#include "path-util.h"
28#include "conf-files.h"
29#include "conf-parser.h"
477e73b5 30#include "util.h"
f579559b
TG
31
32static int network_load_one(Manager *manager, const char *filename) {
33 _cleanup_network_free_ Network *network = NULL;
34 _cleanup_fclose_ FILE *file = NULL;
b3070dc0
TG
35 Route *route;
36 Address *address;
f579559b
TG
37 int r;
38
bf1bc670
TA
39 assert(manager);
40 assert(filename);
41
f579559b
TG
42 file = fopen(filename, "re");
43 if (!file) {
44 if (errno == ENOENT)
45 return 0;
46 else
ecb08ec6 47 return -errno;
f579559b
TG
48 }
49
6916ec29
TG
50 if (null_or_empty_path(filename)) {
51 log_debug("skipping empty file: %s", filename);
52 return 0;
53 }
54
f579559b
TG
55 network = new0(Network, 1);
56 if (!network)
57 return log_oom();
58
5a3eb5a7
TG
59 network->manager = manager;
60
f048a16b
TG
61 LIST_HEAD_INIT(network->static_addresses);
62 LIST_HEAD_INIT(network->static_routes);
f579559b 63
fe6b2d55 64 network->vlans = hashmap_new(string_hash_func, string_compare_func);
672682a6
TG
65 if (!network->vlans)
66 return log_oom();
67
fe6b2d55
TG
68 network->macvlans = hashmap_new(uint64_hash_func, uint64_compare_func);
69 if (!network->macvlans)
70 return log_oom();
71
6ae115c1
TG
72 network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
73 if (!network->addresses_by_section)
74 return log_oom();
75
76 network->routes_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
77 if (!network->routes_by_section)
78 return log_oom();
79
80 network->filename = strdup(filename);
81 if (!network->filename)
82 return log_oom();
83
5be4d38e 84 network->dhcp_dns = true;
1346b1f0 85 network->dhcp_hostname = true;
039ebe6a 86 network->dhcp_domainname = true;
5be4d38e
TG
87
88 r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCPv4\0", config_item_perf_lookup,
c0dda186 89 (void*) network_network_gperf_lookup, false, false, network);
f579559b
TG
90 if (r < 0) {
91 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
92 return r;
449f7554 93 }
f579559b 94
f579559b 95 LIST_PREPEND(networks, manager->networks, network);
b3070dc0 96
3d3d4255 97 LIST_FOREACH(routes, route, network->static_routes) {
b3070dc0
TG
98 if (!route->family) {
99 log_warning("Route section without Gateway field configured in %s. "
100 "Ignoring", filename);
101 return 0;
102 }
b3070dc0
TG
103 }
104
3d3d4255 105 LIST_FOREACH(addresses, address, network->static_addresses) {
b3070dc0
TG
106 if (!address->family) {
107 log_warning("Address section without Address field configured in %s. "
108 "Ignoring", filename);
109 return 0;
110 }
111 }
112
f579559b
TG
113 network = NULL;
114
115 return 0;
116}
117
118int network_load(Manager *manager) {
119 Network *network;
477e73b5
ZJS
120 _cleanup_strv_free_ char **files = NULL;
121 char **f;
f579559b
TG
122 int r;
123
124 assert(manager);
125
126 while ((network = manager->networks))
127 network_free(network);
128
2ad8416d 129 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
f579559b 130 if (r < 0) {
449f7554 131 log_error("Failed to enumerate network files: %s", strerror(-r));
f579559b
TG
132 return r;
133 }
134
135 STRV_FOREACH_BACKWARDS(f, files) {
136 r = network_load_one(manager, *f);
137 if (r < 0)
138 return r;
139 }
140
f579559b
TG
141 return 0;
142}
143
f579559b 144void network_free(Network *network) {
47e2dc31 145 NetDev *netdev;
f579559b
TG
146 Route *route;
147 Address *address;
06f021a8 148 Iterator i;
f579559b
TG
149
150 if (!network)
151 return;
152
153 free(network->filename);
154
155 free(network->match_mac);
156 free(network->match_path);
157 free(network->match_driver);
158 free(network->match_type);
159 free(network->match_name);
160
161 free(network->description);
162
d4920165
TG
163 while ((address = network->dns)) {
164 LIST_REMOVE(addresses, network->dns, address);
06f021a8 165 address_free(address);
d4920165 166 }
3bef724f 167
47e2dc31
TG
168 netdev_unref(network->bridge);
169
170 netdev_unref(network->bond);
171
172 HASHMAP_FOREACH(netdev, network->vlans, i)
173 netdev_unref(netdev);
672682a6
TG
174 hashmap_free(network->vlans);
175
47e2dc31
TG
176 HASHMAP_FOREACH(netdev, network->macvlans, i)
177 netdev_unref(netdev);
fe6b2d55
TG
178 hashmap_free(network->macvlans);
179
f048a16b 180 while ((route = network->static_routes))
f579559b
TG
181 route_free(route);
182
f048a16b 183 while ((address = network->static_addresses))
f579559b
TG
184 address_free(address);
185
6ae115c1
TG
186 hashmap_free(network->addresses_by_section);
187 hashmap_free(network->routes_by_section);
188
b3070dc0 189 if (network->manager && network->manager->networks)
7384fa92 190 LIST_REMOVE(networks, network->manager->networks, network);
f579559b 191
79e16ce3
LP
192 condition_free_list(network->match_host);
193 condition_free_list(network->match_virt);
194 condition_free_list(network->match_kernel);
195 condition_free_list(network->match_arch);
196
f579559b
TG
197 free(network);
198}
199
505f8da7
TG
200int network_get(Manager *manager, struct udev_device *device,
201 const char *ifname, const struct ether_addr *address,
202 Network **ret) {
f579559b
TG
203 Network *network;
204
205 assert(manager);
f579559b
TG
206 assert(ret);
207
f579559b
TG
208 LIST_FOREACH(networks, network, manager->networks) {
209 if (net_match_config(network->match_mac, network->match_path,
505f8da7
TG
210 network->match_driver, network->match_type,
211 network->match_name, network->match_host,
212 network->match_virt, network->match_kernel,
213 network->match_arch,
214 address,
215 udev_device_get_property_value(device, "ID_PATH"),
216 udev_device_get_driver(udev_device_get_parent(device)),
217 udev_device_get_property_value(device, "ID_NET_DRIVER"),
218 udev_device_get_devtype(device),
219 ifname)) {
987efa17 220 log_debug("%*s: found matching network '%s'", IFNAMSIZ, ifname,
505f8da7 221 network->filename);
f579559b
TG
222 *ret = network;
223 return 0;
224 }
225 }
226
227 *ret = NULL;
228
229 return -ENOENT;
230}
231
232int network_apply(Manager *manager, Network *network, Link *link) {
f579559b
TG
233 int r;
234
f579559b
TG
235 link->network = network;
236
3bef724f
TG
237 if (network->dns) {
238 r = manager_update_resolv_conf(manager);
239 if (r < 0)
240 return r;
241 }
242
f579559b
TG
243 return 0;
244}
02b59d57 245
69a93e7d 246int config_parse_netdev(const char *unit,
02b59d57
TG
247 const char *filename,
248 unsigned line,
249 const char *section,
250 unsigned section_line,
251 const char *lvalue,
252 int ltype,
253 const char *rvalue,
254 void *data,
255 void *userdata) {
256 Network *network = userdata;
31d0ac36
TG
257 _cleanup_free_ char *kind_string = NULL;
258 char *p;
1a436809 259 NetDev *netdev;
69a93e7d 260 NetDevKind kind;
02b59d57
TG
261 int r;
262
263 assert(filename);
264 assert(lvalue);
265 assert(rvalue);
266 assert(data);
267
69a93e7d
TG
268 kind_string = strdup(lvalue);
269 if (!kind_string)
270 return log_oom();
52433f6b 271
69a93e7d
TG
272 /* the keys are CamelCase versions of the kind */
273 for (p = kind_string; *p; p++)
274 *p = tolower(*p);
52433f6b 275
69a93e7d
TG
276 kind = netdev_kind_from_string(kind_string);
277 if (kind == _NETDEV_KIND_INVALID) {
52433f6b 278 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
69a93e7d 279 "Invalid NetDev kind: %s", lvalue);
52433f6b
TG
280 return 0;
281 }
282
54abf461
TG
283 r = netdev_get(network->manager, rvalue, &netdev);
284 if (r < 0) {
285 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
69a93e7d 286 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
287 return 0;
288 }
289
69a93e7d 290 if (netdev->kind != kind) {
54abf461 291 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
69a93e7d 292 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
293 return 0;
294 }
295
69a93e7d
TG
296 switch (kind) {
297 case NETDEV_KIND_BRIDGE:
298 network->bridge = netdev;
54abf461 299
69a93e7d
TG
300 break;
301 case NETDEV_KIND_BOND:
302 network->bond = netdev;
fe6b2d55 303
69a93e7d
TG
304 break;
305 case NETDEV_KIND_VLAN:
306 r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
307 if (r < 0) {
308 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
309 "Can not add VLAN to network: %s", rvalue);
310 return 0;
311 }
fe6b2d55 312
69a93e7d
TG
313 break;
314 case NETDEV_KIND_MACVLAN:
af4e9e2c 315 r = hashmap_put(network->macvlans, netdev->ifname, netdev);
69a93e7d
TG
316 if (r < 0) {
317 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
318 "Can not add MACVLAN to network: %s", rvalue);
319 return 0;
320 }
fe6b2d55 321
69a93e7d
TG
322 break;
323 default:
324 assert_not_reached("Can not parse NetDev");
fe6b2d55
TG
325 }
326
47e2dc31
TG
327 netdev_ref(netdev);
328
fe6b2d55
TG
329 return 0;
330}
7951dea2
SS
331
332int config_parse_tunnel(const char *unit,
333 const char *filename,
334 unsigned line,
335 const char *section,
336 unsigned section_line,
337 const char *lvalue,
338 int ltype,
339 const char *rvalue,
340 void *data,
341 void *userdata) {
342 Network *network = userdata;
343 NetDev *netdev;
344 int r;
345
346 assert(filename);
347 assert(lvalue);
348 assert(rvalue);
349 assert(data);
350
351 r = netdev_get(network->manager, rvalue, &netdev);
352 if (r < 0) {
353 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
354 "Tunnel is invalid, ignoring assignment: %s", rvalue);
355 return 0;
356 }
357
358 if (netdev->kind != NETDEV_KIND_IPIP &&
359 netdev->kind != NETDEV_KIND_SIT &&
360 netdev->kind != NETDEV_KIND_GRE) {
361 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
362 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
363 return 0;
364 }
365
366 network->tunnel = netdev;
367
368 return 0;
369}