]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-wait-online-manager.c
treewide: auto-convert the simple cases to log_*_errno()
[thirdparty/systemd.git] / src / network / networkd-wait-online-manager.c
CommitLineData
7de12ae7
TG
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
34bool manager_all_configured(Manager *m) {
35 Iterator i;
36 Link *l;
37 char **ifname;
38 bool one_ready = false;
39
3f85ef0f 40 /* wait for all the links given on the command line to appear */
7de12ae7
TG
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
79static int manager_process_link(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
80 Manager *m = userdata;
81 uint16_t type;
82 Link *l;
d2437732 83 const char *ifname;
7de12ae7
TG
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
136fail:
0a1beeb6 137 log_warning_errno(-r, "Failed to process RTNL link message: %m");
7de12ae7
TG
138 return 0;
139}
140
141static 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
155static 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
201static 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)
0a1beeb6 214 log_warning_errno(-r, "Failed to update monitor information for %i: %m", l->ifindex);
7de12ae7
TG
215 }
216
217 if (manager_all_configured(m))
218 sd_event_exit(m->event, 0);
219
220 return 0;
221}
222
223static 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
248int 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
283void 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}