]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
sd-rtnl: extend tests a bit
[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
22#include "networkd.h"
23#include "net-util.h"
24#include "path-util.h"
25#include "conf-files.h"
26#include "conf-parser.h"
477e73b5 27#include "util.h"
f579559b
TG
28
29static int network_load_one(Manager *manager, const char *filename) {
30 _cleanup_network_free_ Network *network = NULL;
31 _cleanup_fclose_ FILE *file = NULL;
b3070dc0
TG
32 Route *route;
33 Address *address;
f579559b
TG
34 int r;
35
bf1bc670
TA
36 assert(manager);
37 assert(filename);
38
f579559b
TG
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
5a3eb5a7
TG
51 network->manager = manager;
52
f048a16b
TG
53 LIST_HEAD_INIT(network->static_addresses);
54 LIST_HEAD_INIT(network->static_routes);
f579559b 55
6ae115c1
TG
56 network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
57 if (!network->addresses_by_section)
58 return log_oom();
59
60 network->routes_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
61 if (!network->routes_by_section)
62 return log_oom();
63
64 network->filename = strdup(filename);
65 if (!network->filename)
66 return log_oom();
67
5be4d38e 68 network->dhcp_dns = true;
1346b1f0 69 network->dhcp_hostname = true;
039ebe6a 70 network->dhcp_domainname = true;
5be4d38e
TG
71
72 r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCPv4\0", config_item_perf_lookup,
f579559b
TG
73 (void*) network_gperf_lookup, false, false, network);
74 if (r < 0) {
75 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
76 return r;
449f7554 77 }
f579559b 78
f579559b 79 LIST_PREPEND(networks, manager->networks, network);
b3070dc0
TG
80
81 LIST_FOREACH(static_routes, route, network->static_routes) {
82 if (!route->family) {
83 log_warning("Route section without Gateway field configured in %s. "
84 "Ignoring", filename);
85 return 0;
86 }
87
88 if (route->dst_family && route->family != route->dst_family) {
89 log_warning("Route section with conflicting Gateway and Destination address "
90 "family configured in %s. Ignoring", filename);
91 return 0;
92 }
93 }
94
95 LIST_FOREACH(static_addresses, address, network->static_addresses) {
96 if (!address->family) {
97 log_warning("Address section without Address field configured in %s. "
98 "Ignoring", filename);
99 return 0;
100 }
101 }
102
f579559b
TG
103 network = NULL;
104
105 return 0;
106}
107
108int network_load(Manager *manager) {
109 Network *network;
477e73b5
ZJS
110 _cleanup_strv_free_ char **files = NULL;
111 char **f;
f579559b
TG
112 int r;
113
114 assert(manager);
115
116 while ((network = manager->networks))
117 network_free(network);
118
2ad8416d 119 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
f579559b 120 if (r < 0) {
449f7554 121 log_error("Failed to enumerate network files: %s", strerror(-r));
f579559b
TG
122 return r;
123 }
124
125 STRV_FOREACH_BACKWARDS(f, files) {
126 r = network_load_one(manager, *f);
127 if (r < 0)
128 return r;
129 }
130
f579559b
TG
131 return 0;
132}
133
f579559b
TG
134void network_free(Network *network) {
135 Route *route;
136 Address *address;
137
138 if (!network)
139 return;
140
141 free(network->filename);
142
143 free(network->match_mac);
144 free(network->match_path);
145 free(network->match_driver);
146 free(network->match_type);
147 free(network->match_name);
148
149 free(network->description);
150
3bef724f
TG
151 address_free(network->dns);
152
f048a16b 153 while ((route = network->static_routes))
f579559b
TG
154 route_free(route);
155
f048a16b 156 while ((address = network->static_addresses))
f579559b
TG
157 address_free(address);
158
6ae115c1
TG
159 hashmap_free(network->addresses_by_section);
160 hashmap_free(network->routes_by_section);
161
b3070dc0 162 if (network->manager && network->manager->networks)
7384fa92 163 LIST_REMOVE(networks, network->manager->networks, network);
f579559b
TG
164
165 free(network);
166}
167
168int network_get(Manager *manager, struct udev_device *device, Network **ret) {
169 Network *network;
170
171 assert(manager);
172 assert(device);
173 assert(ret);
174
f579559b
TG
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))) {
449f7554
TG
184 log_debug("%s: found matching network '%s'",
185 udev_device_get_sysname(device),
186 network->filename);
f579559b
TG
187 *ret = network;
188 return 0;
189 }
190 }
191
192 *ret = NULL;
193
194 return -ENOENT;
195}
196
197int network_apply(Manager *manager, Network *network, Link *link) {
f579559b
TG
198 int r;
199
f579559b
TG
200 link->network = network;
201
f882c247 202 r = link_configure(link);
f579559b
TG
203 if (r < 0)
204 return r;
205
3bef724f
TG
206 if (network->dns) {
207 r = manager_update_resolv_conf(manager);
208 if (r < 0)
209 return r;
210 }
211
f579559b
TG
212 return 0;
213}
02b59d57
TG
214
215int 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;
52433f6b 226 Netdev *netdev;
02b59d57
TG
227 int r;
228
229 assert(filename);
230 assert(lvalue);
231 assert(rvalue);
232 assert(data);
233
52433f6b 234 r = netdev_get(network->manager, rvalue, &netdev);
02b59d57
TG
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
52433f6b
TG
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
252int 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;
02b59d57
TG
285
286 return 0;
287}