]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-wait-online-manager.c
Merge pull request #178 from utezduyar/man-sd_bus_message_get_creds
[thirdparty/systemd.git] / src / network / networkd-wait-online-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 <netinet/ether.h>
23 #include <linux/if.h>
24 #include <fnmatch.h>
25
26 #include "netlink-util.h"
27
28 #include "network-internal.h"
29 #include "networkd-wait-online-link.h"
30 #include "networkd-wait-online.h"
31
32 #include "util.h"
33 #include "time-util.h"
34
35 bool manager_ignore_link(Manager *m, Link *link) {
36 char **ignore;
37
38 assert(m);
39 assert(link);
40
41 if (link->flags & IFF_LOOPBACK)
42 return true;
43
44 STRV_FOREACH(ignore, m->ignore)
45 if (fnmatch(*ignore, link->ifname, 0) == 0)
46 return true;
47
48 return false;
49 }
50
51 bool manager_all_configured(Manager *m) {
52 Iterator i;
53 Link *l;
54 char **ifname;
55 bool one_ready = false;
56
57 /* wait for all the links given on the command line to appear */
58 STRV_FOREACH(ifname, m->interfaces) {
59 l = hashmap_get(m->links_by_name, *ifname);
60 if (!l) {
61 log_debug("still waiting for %s", *ifname);
62 return false;
63 }
64 }
65
66 /* wait for all links networkd manages to be in admin state 'configured'
67 and at least one link to gain a carrier */
68 HASHMAP_FOREACH(l, m->links, i) {
69 if (manager_ignore_link(m, l)) {
70 log_info("ignoring: %s", l->ifname);
71 continue;
72 }
73
74 if (!l->state) {
75 log_debug("link %s has not yet been processed by udev",
76 l->ifname);
77 return false;
78 }
79
80 if (streq(l->state, "configuring")) {
81 log_debug("link %s is being processed by networkd",
82 l->ifname);
83 return false;
84 }
85
86 if (l->operational_state &&
87 STR_IN_SET(l->operational_state, "degraded", "routable"))
88 /* we wait for at least one link to be ready,
89 regardless of who manages it */
90 one_ready = true;
91 }
92
93 return one_ready;
94 }
95
96 static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
97 Manager *m = userdata;
98 uint16_t type;
99 Link *l;
100 const char *ifname;
101 int ifindex, r;
102
103 assert(rtnl);
104 assert(m);
105 assert(mm);
106
107 r = sd_netlink_message_get_type(mm, &type);
108 if (r < 0)
109 goto fail;
110
111 r = sd_rtnl_message_link_get_ifindex(mm, &ifindex);
112 if (r < 0)
113 goto fail;
114
115 r = sd_netlink_message_read_string(mm, IFLA_IFNAME, &ifname);
116 if (r < 0)
117 goto fail;
118
119 l = hashmap_get(m->links, INT_TO_PTR(ifindex));
120
121 switch (type) {
122
123 case RTM_NEWLINK:
124 if (!l) {
125 log_debug("Found link %i", ifindex);
126
127 r = link_new(m, &l, ifindex, ifname);
128 if (r < 0)
129 goto fail;
130
131 r = link_update_monitor(l);
132 if (r < 0)
133 goto fail;
134 }
135
136 r = link_update_rtnl(l, mm);
137 if (r < 0)
138 goto fail;
139
140 break;
141
142 case RTM_DELLINK:
143 if (l) {
144 log_debug("Removing link %i", l->ifindex);
145 link_free(l);
146 }
147
148 break;
149 }
150
151 return 0;
152
153 fail:
154 log_warning_errno(r, "Failed to process RTNL link message: %m");
155 return 0;
156 }
157
158 static int on_rtnl_event(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
159 Manager *m = userdata;
160 int r;
161
162 r = manager_process_link(rtnl, mm, m);
163 if (r < 0)
164 return r;
165
166 if (manager_all_configured(m))
167 sd_event_exit(m->event, 0);
168
169 return 1;
170 }
171
172 static int manager_rtnl_listen(Manager *m) {
173 _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
174 sd_netlink_message *i;
175 int r;
176
177 assert(m);
178
179 /* First, subscribe to interfaces coming and going */
180 r = sd_netlink_open(&m->rtnl);
181 if (r < 0)
182 return r;
183
184 r = sd_netlink_attach_event(m->rtnl, m->event, 0);
185 if (r < 0)
186 return r;
187
188 r = sd_netlink_add_match(m->rtnl, RTM_NEWLINK, on_rtnl_event, m);
189 if (r < 0)
190 return r;
191
192 r = sd_netlink_add_match(m->rtnl, RTM_DELLINK, on_rtnl_event, m);
193 if (r < 0)
194 return r;
195
196 /* Then, enumerate all links */
197 r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
198 if (r < 0)
199 return r;
200
201 r = sd_netlink_message_request_dump(req, true);
202 if (r < 0)
203 return r;
204
205 r = sd_netlink_call(m->rtnl, req, 0, &reply);
206 if (r < 0)
207 return r;
208
209 for (i = reply; i; i = sd_netlink_message_next(i)) {
210 r = manager_process_link(m->rtnl, i, m);
211 if (r < 0)
212 return r;
213 }
214
215 return r;
216 }
217
218 static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
219 Manager *m = userdata;
220 Iterator i;
221 Link *l;
222 int r;
223
224 assert(m);
225
226 sd_network_monitor_flush(m->network_monitor);
227
228 HASHMAP_FOREACH(l, m->links, i) {
229 r = link_update_monitor(l);
230 if (r < 0)
231 log_warning_errno(r, "Failed to update monitor information for %i: %m", l->ifindex);
232 }
233
234 if (manager_all_configured(m))
235 sd_event_exit(m->event, 0);
236
237 return 0;
238 }
239
240 static int manager_network_monitor_listen(Manager *m) {
241 int r, fd, events;
242
243 assert(m);
244
245 r = sd_network_monitor_new(&m->network_monitor, NULL);
246 if (r < 0)
247 return r;
248
249 fd = sd_network_monitor_get_fd(m->network_monitor);
250 if (fd < 0)
251 return fd;
252
253 events = sd_network_monitor_get_events(m->network_monitor);
254 if (events < 0)
255 return events;
256
257 r = sd_event_add_io(m->event, &m->network_monitor_event_source,
258 fd, events, &on_network_event, m);
259 if (r < 0)
260 return r;
261
262 return 0;
263 }
264
265 int manager_new(Manager **ret, char **interfaces, char **ignore, usec_t timeout) {
266 _cleanup_(manager_freep) Manager *m = NULL;
267 int r;
268
269 assert(ret);
270
271 m = new0(Manager, 1);
272 if (!m)
273 return -ENOMEM;
274
275 m->interfaces = interfaces;
276 m->ignore = ignore;
277
278 r = sd_event_default(&m->event);
279 if (r < 0)
280 return r;
281
282 sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
283 sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
284
285 if (timeout > 0) {
286 usec_t usec;
287
288 usec = now(clock_boottime_or_monotonic()) + timeout;
289
290 r = sd_event_add_time(m->event, NULL, clock_boottime_or_monotonic(), usec, 0, NULL, INT_TO_PTR(-ETIMEDOUT));
291 if (r < 0)
292 return r;
293 }
294
295 sd_event_set_watchdog(m->event, true);
296
297 r = manager_network_monitor_listen(m);
298 if (r < 0)
299 return r;
300
301 r = manager_rtnl_listen(m);
302 if (r < 0)
303 return r;
304
305 *ret = m;
306 m = NULL;
307
308 return 0;
309 }
310
311 void manager_free(Manager *m) {
312 Link *l;
313
314 if (!m)
315 return;
316
317 while ((l = hashmap_first(m->links)))
318 link_free(l);
319 hashmap_free(m->links);
320 hashmap_free(m->links_by_name);
321
322 sd_event_source_unref(m->network_monitor_event_source);
323 sd_network_monitor_unref(m->network_monitor);
324
325 sd_event_source_unref(m->rtnl_event_source);
326 sd_netlink_unref(m->rtnl);
327
328 sd_event_unref(m->event);
329 free(m);
330
331 return;
332 }