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