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