]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-manager.c
No need to canonicalize fixed paths
[thirdparty/systemd.git] / src / network / networkd-manager.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 "path-util.h"
23 #include "networkd.h"
24 #include "libudev-private.h"
25 #include "udev-util.h"
26
27 const char* const network_dirs[] = {
28 "/etc/systemd/network",
29 "/run/systemd/network",
30 "/usr/lib/systemd/network",
31 #ifdef HAVE_SPLIT_USER
32 "/lib/systemd/network",
33 #endif
34 NULL};
35
36 int manager_new(Manager **ret) {
37 _cleanup_manager_free_ Manager *m = NULL;
38 int r;
39
40 m = new0(Manager, 1);
41 if (!m)
42 return -ENOMEM;
43
44 r = sd_event_default(&m->event);
45 if (r < 0)
46 return r;
47
48 sd_event_set_watchdog(m->event, true);
49
50 r = sd_rtnl_open(RTMGRP_LINK | RTMGRP_IPV4_IFADDR, &m->rtnl);
51 if (r < 0)
52 return r;
53
54 m->udev = udev_new();
55 if (!m->udev)
56 return -ENOMEM;
57
58 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
59 if (!m->udev_monitor)
60 return -ENOMEM;
61
62 m->links = hashmap_new(uint64_hash_func, uint64_compare_func);
63 if (!m->links)
64 return -ENOMEM;
65
66 m->bridges = hashmap_new(string_hash_func, string_compare_func);
67 if (!m->bridges)
68 return -ENOMEM;
69
70 LIST_HEAD_INIT(m->networks);
71
72 *ret = m;
73 m = NULL;
74
75 return 0;
76 }
77
78 void manager_free(Manager *m) {
79 Network *network;
80 Bridge *bridge;
81 Link *link;
82
83 udev_monitor_unref(m->udev_monitor);
84 udev_unref(m->udev);
85 sd_event_source_unref(m->udev_event_source);
86 sd_event_unref(m->event);
87
88 while ((network = m->networks))
89 network_free(network);
90
91 while ((link = hashmap_first(m->links)))
92 link_free(link);
93 hashmap_free(m->links);
94
95 while ((bridge = hashmap_first(m->bridges)))
96 bridge_free(bridge);
97 hashmap_free(m->bridges);
98
99 sd_rtnl_unref(m->rtnl);
100
101 free(m);
102 }
103
104 int manager_load_config(Manager *m) {
105 int r;
106
107 /* update timestamp */
108 paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
109
110 r = bridge_load(m);
111 if (r < 0)
112 return r;
113
114 r = network_load(m);
115 if (r < 0)
116 return r;
117
118 return 0;
119 }
120
121 bool manager_should_reload(Manager *m) {
122 return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
123 }
124
125 static int manager_process_link(Manager *m, struct udev_device *device) {
126 Link *link;
127 int r;
128
129 if (streq_ptr(udev_device_get_action(device), "remove")) {
130 uint64_t ifindex;
131
132 log_debug("%s: link removed", udev_device_get_sysname(device));
133
134 ifindex = udev_device_get_ifindex(device);
135 link = hashmap_get(m->links, &ifindex);
136 if (!link)
137 return 0;
138
139 link_free(link);
140 } else {
141 r = link_add(m, device, &link);
142 if (r < 0) {
143 if (r == -EEXIST)
144 log_debug("%s: link already exists, ignoring",
145 link->ifname);
146 else
147 log_error("%s: could not handle link: %s",
148 udev_device_get_sysname(device),
149 strerror(-r));
150 } else
151 log_debug("%s: link (with ifindex %" PRIu64") added",
152 link->ifname, link->ifindex);
153 }
154
155 return 0;
156 }
157
158 int manager_udev_enumerate_links(Manager *m) {
159 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
160 struct udev_list_entry *item = NULL, *first = NULL;
161 int r;
162
163 assert(m);
164
165 e = udev_enumerate_new(m->udev);
166 if (!e)
167 return -ENOMEM;
168
169 r = udev_enumerate_add_match_subsystem(e, "net");
170 if (r < 0)
171 return r;
172
173 r = udev_enumerate_add_match_is_initialized(e);
174 if (r < 0)
175 return r;
176
177 r = udev_enumerate_scan_devices(e);
178 if (r < 0)
179 return r;
180
181 first = udev_enumerate_get_list_entry(e);
182 udev_list_entry_foreach(item, first) {
183 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
184 int k;
185
186 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
187 if (!d)
188 return -ENOMEM;
189
190 k = manager_process_link(m, d);
191 if (k < 0)
192 r = k;
193 }
194
195 return r;
196 }
197
198 static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
199 Manager *m = userdata;
200 struct udev_monitor *monitor = m->udev_monitor;
201 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
202
203 device = udev_monitor_receive_device(monitor);
204 if (!device)
205 return -ENOMEM;
206
207 manager_process_link(m, device);
208 return 0;
209 }
210
211 int manager_udev_listen(Manager *m) {
212 int r;
213
214 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
215 if (r < 0) {
216 log_error("Could not add udev monitor filter: %s", strerror(-r));
217 return r;
218 }
219
220 r = udev_monitor_enable_receiving(m->udev_monitor);
221 if (r < 0) {
222 log_error("Could not enable udev monitor");
223 return r;
224 }
225
226 r = sd_event_add_io(m->event,
227 udev_monitor_get_fd(m->udev_monitor),
228 EPOLLIN, manager_dispatch_link_udev,
229 m, &m->udev_event_source);
230 if (r < 0)
231 return r;
232
233 return 0;
234 }
235
236 static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
237 Manager *m = userdata;
238 Link *link;
239 uint64_t ifindex_64;
240 int r, ifindex;
241
242 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
243 if (r < 0) {
244 log_debug("received RTM_NEWLINK message without valid ifindex");
245 return 0;
246 }
247
248 ifindex_64 = ifindex;
249 link = hashmap_get(m->links, &ifindex_64);
250 if (!link) {
251 log_debug("received RTM_NEWLINK message for untracked ifindex %d", ifindex);
252 return 0;
253 }
254
255 /* only track the status of links we want to manage */
256 if (link->network) {
257 r = link_update(link, message);
258 if (r < 0)
259 return 0;
260 } else
261 log_debug("%s: received RTM_NEWLINK message for unmanaged link", link->ifname);
262
263 return 1;
264 }
265
266 int manager_rtnl_listen(Manager *m) {
267 int r;
268
269 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
270 if (r < 0)
271 return r;
272
273 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
274 if (r < 0)
275 return r;
276
277 return 0;
278 }