chiark / gitweb /
networkd: dhcp - by default ignore the MTU
[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_hostname = true;
70         network->dhcp_domainname = true;
71
72         r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCPv4\0", config_item_perf_lookup,
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;
77         }
78
79         LIST_PREPEND(networks, manager->networks, network);
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
103         network = NULL;
104
105         return 0;
106 }
107
108 int network_load(Manager *manager) {
109         Network *network;
110         _cleanup_strv_free_ char **files = NULL;
111         char **f;
112         int r;
113
114         assert(manager);
115
116         while ((network = manager->networks))
117                 network_free(network);
118
119         r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
120         if (r < 0) {
121                 log_error("Failed to enumerate network files: %s", strerror(-r));
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
131         return 0;
132 }
133
134 void 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
151         address_free(network->dns);
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         Bridge *bridge;
227         int r;
228
229         assert(filename);
230         assert(lvalue);
231         assert(rvalue);
232         assert(data);
233
234         r = bridge_get(network->manager, rvalue, &bridge);
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         network->bridge = bridge;
242
243         return 0;
244 }