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