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