chiark / gitweb /
02ffdb1a72fbbf967b6b14c8e54ec2936744abf6
[elogind.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->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
68         network->dhcp_dns = true;
69         network->dhcp_mtu = true;
70
71         r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCPv4\0", config_item_perf_lookup,
72                         (void*) network_gperf_lookup, false, false, network);
73         if (r < 0) {
74                 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
75                 return r;
76         }
77
78         LIST_PREPEND(networks, manager->networks, network);
79
80         LIST_FOREACH(static_routes, route, network->static_routes) {
81                 if (!route->family) {
82                         log_warning("Route section without Gateway field configured in %s. "
83                                     "Ignoring", filename);
84                         return 0;
85                 }
86
87                 if (route->dst_family && route->family != route->dst_family) {
88                         log_warning("Route section with conflicting Gateway and Destination address "
89                                     "family configured in %s. Ignoring", filename);
90                         return 0;
91                 }
92         }
93
94         LIST_FOREACH(static_addresses, address, network->static_addresses) {
95                 if (!address->family) {
96                         log_warning("Address section without Address field configured in %s. "
97                                     "Ignoring", filename);
98                         return 0;
99                 }
100         }
101
102         network = NULL;
103
104         return 0;
105 }
106
107 int network_load(Manager *manager) {
108         Network *network;
109         _cleanup_strv_free_ char **files = NULL;
110         char **f;
111         int r;
112
113         assert(manager);
114
115         while ((network = manager->networks))
116                 network_free(network);
117
118         r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
119         if (r < 0) {
120                 log_error("Failed to enumerate network files: %s", strerror(-r));
121                 return r;
122         }
123
124         STRV_FOREACH_BACKWARDS(f, files) {
125                 r = network_load_one(manager, *f);
126                 if (r < 0)
127                         return r;
128         }
129
130         return 0;
131 }
132
133 void network_free(Network *network) {
134         Route *route;
135         Address *address;
136
137         if (!network)
138                 return;
139
140         free(network->filename);
141
142         free(network->match_mac);
143         free(network->match_path);
144         free(network->match_driver);
145         free(network->match_type);
146         free(network->match_name);
147
148         free(network->description);
149
150         address_free(network->dns);
151
152         while ((route = network->static_routes))
153                 route_free(route);
154
155         while ((address = network->static_addresses))
156                 address_free(address);
157
158         hashmap_free(network->addresses_by_section);
159         hashmap_free(network->routes_by_section);
160
161         if (network->manager && network->manager->networks)
162                 LIST_REMOVE(networks, network->manager->networks, network);
163
164         free(network);
165 }
166
167 int network_get(Manager *manager, struct udev_device *device, Network **ret) {
168         Network *network;
169
170         assert(manager);
171         assert(device);
172         assert(ret);
173
174         LIST_FOREACH(networks, network, manager->networks) {
175                 if (net_match_config(network->match_mac, network->match_path,
176                                         network->match_driver, network->match_type,
177                                         network->match_name,
178                                         udev_device_get_sysattr_value(device, "address"),
179                                         udev_device_get_property_value(device, "ID_PATH"),
180                                         udev_device_get_driver(device),
181                                         udev_device_get_devtype(device),
182                                         udev_device_get_sysname(device))) {
183                         log_debug("%s: found matching network '%s'",
184                                         udev_device_get_sysname(device),
185                                         network->filename);
186                         *ret = network;
187                         return 0;
188                 }
189         }
190
191         *ret = NULL;
192
193         return -ENOENT;
194 }
195
196 int network_apply(Manager *manager, Network *network, Link *link) {
197         int r;
198
199         link->network = network;
200
201         r = link_configure(link);
202         if (r < 0)
203                 return r;
204
205         if (network->dns) {
206                 r = manager_update_resolv_conf(manager);
207                 if (r < 0)
208                         return r;
209         }
210
211         return 0;
212 }
213
214 int config_parse_bridge(const char *unit,
215                 const char *filename,
216                 unsigned line,
217                 const char *section,
218                 unsigned section_line,
219                 const char *lvalue,
220                 int ltype,
221                 const char *rvalue,
222                 void *data,
223                 void *userdata) {
224         Network *network = userdata;
225         Bridge *bridge;
226         int r;
227
228         assert(filename);
229         assert(lvalue);
230         assert(rvalue);
231         assert(data);
232
233         r = bridge_get(network->manager, rvalue, &bridge);
234         if (r < 0) {
235                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
236                            "Bridge is invalid, ignoring assignment: %s", rvalue);
237                 return 0;
238         }
239
240         network->bridge = bridge;
241
242         return 0;
243 }