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