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