Line data Source code
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 <net/if.h>
23 :
24 : #include "networkd-netdev.h"
25 : #include "networkd-link.h"
26 : #include "network-internal.h"
27 : #include "conf-files.h"
28 : #include "conf-parser.h"
29 : #include "list.h"
30 : #include "siphash24.h"
31 :
32 : const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
33 : [NETDEV_KIND_BRIDGE] = &bridge_vtable,
34 : [NETDEV_KIND_BOND] = &bond_vtable,
35 : [NETDEV_KIND_VLAN] = &vlan_vtable,
36 : [NETDEV_KIND_MACVLAN] = &macvlan_vtable,
37 : [NETDEV_KIND_MACVTAP] = &macvtap_vtable,
38 : [NETDEV_KIND_IPVLAN] = &ipvlan_vtable,
39 : [NETDEV_KIND_VXLAN] = &vxlan_vtable,
40 : [NETDEV_KIND_IPIP] = &ipip_vtable,
41 : [NETDEV_KIND_GRE] = &gre_vtable,
42 : [NETDEV_KIND_GRETAP] = &gretap_vtable,
43 : [NETDEV_KIND_IP6GRE] = &ip6gre_vtable,
44 : [NETDEV_KIND_IP6GRETAP] = &ip6gretap_vtable,
45 : [NETDEV_KIND_SIT] = &sit_vtable,
46 : [NETDEV_KIND_VTI] = &vti_vtable,
47 : [NETDEV_KIND_VTI6] = &vti6_vtable,
48 : [NETDEV_KIND_VETH] = &veth_vtable,
49 : [NETDEV_KIND_DUMMY] = &dummy_vtable,
50 : [NETDEV_KIND_TUN] = &tun_vtable,
51 : [NETDEV_KIND_TAP] = &tap_vtable,
52 : [NETDEV_KIND_IP6TNL] = &ip6tnl_vtable,
53 : };
54 :
55 : static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
56 : [NETDEV_KIND_BRIDGE] = "bridge",
57 : [NETDEV_KIND_BOND] = "bond",
58 : [NETDEV_KIND_VLAN] = "vlan",
59 : [NETDEV_KIND_MACVLAN] = "macvlan",
60 : [NETDEV_KIND_MACVTAP] = "macvtap",
61 : [NETDEV_KIND_IPVLAN] = "ipvlan",
62 : [NETDEV_KIND_VXLAN] = "vxlan",
63 : [NETDEV_KIND_IPIP] = "ipip",
64 : [NETDEV_KIND_GRE] = "gre",
65 : [NETDEV_KIND_GRETAP] = "gretap",
66 : [NETDEV_KIND_IP6GRE] = "ip6gre",
67 : [NETDEV_KIND_IP6GRETAP] = "ip6gretap",
68 : [NETDEV_KIND_SIT] = "sit",
69 : [NETDEV_KIND_VETH] = "veth",
70 : [NETDEV_KIND_VTI] = "vti",
71 : [NETDEV_KIND_VTI6] = "vti6",
72 : [NETDEV_KIND_DUMMY] = "dummy",
73 : [NETDEV_KIND_TUN] = "tun",
74 : [NETDEV_KIND_TAP] = "tap",
75 : [NETDEV_KIND_IP6TNL] = "ip6tnl",
76 : };
77 :
78 44 : DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
79 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
80 :
81 0 : static void netdev_cancel_callbacks(NetDev *netdev) {
82 0 : _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
83 : netdev_join_callback *callback;
84 :
85 0 : if (!netdev)
86 0 : return;
87 :
88 0 : rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
89 :
90 0 : while ((callback = netdev->callbacks)) {
91 0 : if (m) {
92 0 : assert(callback->link);
93 0 : assert(callback->callback);
94 0 : assert(netdev->manager);
95 0 : assert(netdev->manager->rtnl);
96 :
97 0 : callback->callback(netdev->manager->rtnl, m, callback->link);
98 : }
99 :
100 0 : LIST_REMOVE(callbacks, netdev->callbacks, callback);
101 0 : link_unref(callback->link);
102 0 : free(callback);
103 : }
104 : }
105 :
106 0 : static void netdev_free(NetDev *netdev) {
107 0 : if (!netdev)
108 0 : return;
109 :
110 0 : netdev_cancel_callbacks(netdev);
111 :
112 0 : if (netdev->ifname)
113 0 : hashmap_remove(netdev->manager->netdevs, netdev->ifname);
114 :
115 0 : free(netdev->filename);
116 :
117 0 : free(netdev->description);
118 0 : free(netdev->ifname);
119 0 : free(netdev->mac);
120 :
121 0 : condition_free_list(netdev->match_host);
122 0 : condition_free_list(netdev->match_virt);
123 0 : condition_free_list(netdev->match_kernel);
124 0 : condition_free_list(netdev->match_arch);
125 :
126 0 : if (NETDEV_VTABLE(netdev) &&
127 0 : NETDEV_VTABLE(netdev)->done)
128 0 : NETDEV_VTABLE(netdev)->done(netdev);
129 :
130 0 : free(netdev);
131 : }
132 :
133 6 : NetDev *netdev_unref(NetDev *netdev) {
134 6 : if (netdev && (-- netdev->n_ref <= 0))
135 0 : netdev_free(netdev);
136 :
137 6 : return NULL;
138 : }
139 :
140 0 : NetDev *netdev_ref(NetDev *netdev) {
141 0 : if (netdev)
142 0 : assert_se(++ netdev->n_ref >= 2);
143 :
144 0 : return netdev;
145 : }
146 :
147 0 : void netdev_drop(NetDev *netdev) {
148 0 : if (!netdev || netdev->state == NETDEV_STATE_LINGER)
149 0 : return;
150 :
151 0 : netdev->state = NETDEV_STATE_LINGER;
152 :
153 0 : log_netdev_debug(netdev, "netdev removed");
154 :
155 0 : netdev_cancel_callbacks(netdev);
156 :
157 0 : netdev_unref(netdev);
158 :
159 0 : return;
160 : }
161 :
162 4 : int netdev_get(Manager *manager, const char *name, NetDev **ret) {
163 : NetDev *netdev;
164 :
165 4 : assert(manager);
166 4 : assert(name);
167 4 : assert(ret);
168 :
169 4 : netdev = hashmap_get(manager->netdevs, name);
170 4 : if (!netdev) {
171 4 : *ret = NULL;
172 4 : return -ENOENT;
173 : }
174 :
175 0 : *ret = netdev;
176 :
177 0 : return 0;
178 : }
179 :
180 0 : static int netdev_enter_failed(NetDev *netdev) {
181 0 : netdev->state = NETDEV_STATE_FAILED;
182 :
183 0 : netdev_cancel_callbacks(netdev);
184 :
185 0 : return 0;
186 : }
187 :
188 0 : static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_netlink_message_handler_t callback) {
189 0 : _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
190 : int r;
191 :
192 0 : assert(netdev);
193 0 : assert(netdev->state == NETDEV_STATE_READY);
194 0 : assert(netdev->manager);
195 0 : assert(netdev->manager->rtnl);
196 0 : assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
197 0 : assert(link);
198 0 : assert(callback);
199 :
200 0 : r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
201 0 : if (r < 0)
202 0 : return log_netdev_error_errno(netdev, r, "Could not allocate RTM_SETLINK message: %m");
203 :
204 0 : r = sd_netlink_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
205 0 : if (r < 0)
206 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_MASTER attribute: %m");
207 :
208 0 : r = sd_netlink_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
209 0 : if (r < 0)
210 0 : return log_netdev_error(netdev, "Could not send rtnetlink message: %m");
211 :
212 0 : link_ref(link);
213 :
214 0 : log_netdev_debug(netdev, "Enslaving link '%s'", link->ifname);
215 :
216 0 : return 0;
217 : }
218 :
219 0 : static int netdev_enter_ready(NetDev *netdev) {
220 : netdev_join_callback *callback, *callback_next;
221 : int r;
222 :
223 0 : assert(netdev);
224 0 : assert(netdev->ifname);
225 :
226 0 : if (netdev->state != NETDEV_STATE_CREATING)
227 0 : return 0;
228 :
229 0 : netdev->state = NETDEV_STATE_READY;
230 :
231 0 : log_netdev_info(netdev, "netdev ready");
232 :
233 0 : LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
234 : /* enslave the links that were attempted to be enslaved before the
235 : * link was ready */
236 0 : r = netdev_enslave_ready(netdev, callback->link, callback->callback);
237 0 : if (r < 0)
238 0 : return r;
239 :
240 0 : LIST_REMOVE(callbacks, netdev->callbacks, callback);
241 0 : link_unref(callback->link);
242 0 : free(callback);
243 : }
244 :
245 0 : return 0;
246 : }
247 :
248 : /* callback for netdev's created without a backing Link */
249 0 : static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
250 0 : _cleanup_netdev_unref_ NetDev *netdev = userdata;
251 : int r;
252 :
253 0 : assert(netdev->state != _NETDEV_STATE_INVALID);
254 :
255 0 : r = sd_netlink_message_get_errno(m);
256 0 : if (r == -EEXIST)
257 0 : log_netdev_info(netdev, "netdev exists, using existing without changing its parameters");
258 0 : else if (r < 0) {
259 0 : log_netdev_warning_errno(netdev, r, "netdev could not be created: %m");
260 0 : netdev_drop(netdev);
261 :
262 0 : return 1;
263 : }
264 :
265 0 : log_netdev_debug(netdev, "Created");
266 :
267 0 : return 1;
268 : }
269 :
270 0 : int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback) {
271 : int r;
272 :
273 0 : assert(netdev);
274 0 : assert(netdev->manager);
275 0 : assert(netdev->manager->rtnl);
276 0 : assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
277 :
278 0 : if (netdev->state == NETDEV_STATE_READY) {
279 0 : r = netdev_enslave_ready(netdev, link, callback);
280 0 : if (r < 0)
281 0 : return r;
282 0 : } else if (IN_SET(netdev->state, NETDEV_STATE_LINGER, NETDEV_STATE_FAILED)) {
283 0 : _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
284 :
285 0 : r = rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
286 0 : if (r >= 0)
287 0 : callback(netdev->manager->rtnl, m, link);
288 : } else {
289 : /* the netdev is not yet read, save this request for when it is */
290 : netdev_join_callback *cb;
291 :
292 0 : cb = new0(netdev_join_callback, 1);
293 0 : if (!cb)
294 0 : return log_oom();
295 :
296 0 : cb->callback = callback;
297 0 : cb->link = link;
298 0 : link_ref(link);
299 :
300 0 : LIST_PREPEND(callbacks, netdev->callbacks, cb);
301 :
302 0 : log_netdev_debug(netdev, "Will enslave '%s', when ready", link->ifname);
303 : }
304 :
305 0 : return 0;
306 : }
307 :
308 0 : int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) {
309 : uint16_t type;
310 : const char *kind;
311 : const char *received_kind;
312 : const char *received_name;
313 : int r, ifindex;
314 :
315 0 : assert(netdev);
316 0 : assert(message);
317 :
318 0 : r = sd_netlink_message_get_type(message, &type);
319 0 : if (r < 0)
320 0 : return log_netdev_error_errno(netdev, r, "Could not get rtnl message type: %m");
321 :
322 0 : if (type != RTM_NEWLINK) {
323 0 : log_netdev_error(netdev, "Cannot set ifindex from unexpected rtnl message type.");
324 0 : return -EINVAL;
325 : }
326 :
327 0 : r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
328 0 : if (r < 0) {
329 0 : log_netdev_error_errno(netdev, r, "Could not get ifindex: %m");
330 0 : netdev_enter_failed(netdev);
331 0 : return r;
332 0 : } else if (ifindex <= 0) {
333 0 : log_netdev_error(netdev, "Got invalid ifindex: %d", ifindex);
334 0 : netdev_enter_failed(netdev);
335 0 : return -EINVAL;
336 : }
337 :
338 0 : if (netdev->ifindex > 0) {
339 0 : if (netdev->ifindex != ifindex) {
340 0 : log_netdev_error(netdev, "Could not set ifindex to %d, already set to %d",
341 : ifindex, netdev->ifindex);
342 0 : netdev_enter_failed(netdev);
343 0 : return -EEXIST;
344 : } else
345 : /* ifindex already set to the same for this netdev */
346 0 : return 0;
347 : }
348 :
349 0 : r = sd_netlink_message_read_string(message, IFLA_IFNAME, &received_name);
350 0 : if (r < 0)
351 0 : return log_netdev_error_errno(netdev, r, "Could not get IFNAME: %m");
352 :
353 0 : if (!streq(netdev->ifname, received_name)) {
354 0 : log_netdev_error(netdev, "Received newlink with wrong IFNAME %s", received_name);
355 0 : netdev_enter_failed(netdev);
356 0 : return r;
357 : }
358 :
359 0 : r = sd_netlink_message_enter_container(message, IFLA_LINKINFO);
360 0 : if (r < 0)
361 0 : return log_netdev_error_errno(netdev, r, "Could not get LINKINFO: %m");
362 :
363 0 : r = sd_netlink_message_read_string(message, IFLA_INFO_KIND, &received_kind);
364 0 : if (r < 0)
365 0 : return log_netdev_error_errno(netdev, r, "Could not get KIND: %m");
366 :
367 0 : r = sd_netlink_message_exit_container(message);
368 0 : if (r < 0)
369 0 : return log_netdev_error_errno(netdev, r, "Could not exit container: %m");
370 :
371 0 : if (netdev->kind == NETDEV_KIND_TAP)
372 : /* the kernel does not distinguish between tun and tap */
373 0 : kind = "tun";
374 : else {
375 0 : kind = netdev_kind_to_string(netdev->kind);
376 0 : if (!kind) {
377 0 : log_netdev_error(netdev, "Could not get kind");
378 0 : netdev_enter_failed(netdev);
379 0 : return -EINVAL;
380 : }
381 : }
382 :
383 0 : if (!streq(kind, received_kind)) {
384 0 : log_netdev_error(netdev,
385 : "Received newlink with wrong KIND %s, "
386 : "expected %s", received_kind, kind);
387 0 : netdev_enter_failed(netdev);
388 0 : return r;
389 : }
390 :
391 0 : netdev->ifindex = ifindex;
392 :
393 0 : log_netdev_debug(netdev, "netdev has index %d", netdev->ifindex);
394 :
395 0 : netdev_enter_ready(netdev);
396 :
397 0 : return 0;
398 : }
399 :
400 : #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
401 :
402 0 : int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
403 0 : _cleanup_free_ struct ether_addr *mac = NULL;
404 : uint8_t result[8];
405 : size_t l, sz;
406 : uint8_t *v;
407 : int r;
408 :
409 0 : assert(ifname);
410 0 : assert(ret);
411 :
412 0 : mac = new0(struct ether_addr, 1);
413 0 : if (!mac)
414 0 : return -ENOMEM;
415 :
416 0 : l = strlen(ifname);
417 0 : sz = sizeof(sd_id128_t) + l;
418 0 : v = alloca(sz);
419 :
420 : /* fetch some persistent data unique to the machine */
421 0 : r = sd_id128_get_machine((sd_id128_t*) v);
422 0 : if (r < 0)
423 0 : return r;
424 :
425 : /* combine with some data unique (on this machine) to this
426 : * netdev */
427 0 : memcpy(v + sizeof(sd_id128_t), ifname, l);
428 :
429 : /* Let's hash the host machine ID plus the container name. We
430 : * use a fixed, but originally randomly created hash key here. */
431 0 : siphash24(result, v, sz, HASH_KEY.bytes);
432 :
433 : assert_cc(ETH_ALEN <= sizeof(result));
434 0 : memcpy(mac->ether_addr_octet, result, ETH_ALEN);
435 :
436 : /* see eth_random_addr in the kernel */
437 0 : mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
438 0 : mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
439 :
440 0 : *ret = mac;
441 0 : mac = NULL;
442 :
443 0 : return 0;
444 : }
445 :
446 0 : static int netdev_create(NetDev *netdev, Link *link,
447 : sd_netlink_message_handler_t callback) {
448 : int r;
449 :
450 0 : assert(netdev);
451 0 : assert(!link || callback);
452 :
453 : /* create netdev */
454 0 : if (NETDEV_VTABLE(netdev)->create) {
455 0 : assert(!link);
456 :
457 0 : r = NETDEV_VTABLE(netdev)->create(netdev);
458 0 : if (r < 0)
459 0 : return r;
460 :
461 0 : log_netdev_debug(netdev, "Created");
462 : } else {
463 0 : _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
464 :
465 0 : r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
466 0 : if (r < 0)
467 0 : return log_netdev_error_errno(netdev, r, "Could not allocate RTM_NEWLINK message: %m");
468 :
469 0 : r = sd_netlink_message_append_string(m, IFLA_IFNAME, netdev->ifname);
470 0 : if (r < 0)
471 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IFNAME, attribute: %m");
472 :
473 0 : if (netdev->mac) {
474 0 : r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
475 0 : if (r < 0)
476 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_ADDRESS attribute: %m");
477 : }
478 :
479 0 : if (netdev->mtu) {
480 0 : r = sd_netlink_message_append_u32(m, IFLA_MTU, netdev->mtu);
481 0 : if (r < 0)
482 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_MTU attribute: %m");
483 : }
484 :
485 0 : if (link) {
486 0 : r = sd_netlink_message_append_u32(m, IFLA_LINK, link->ifindex);
487 0 : if (r < 0)
488 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINK attribute: %m");
489 : }
490 :
491 0 : r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
492 0 : if (r < 0)
493 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
494 :
495 0 : r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind));
496 0 : if (r < 0)
497 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
498 :
499 0 : if (NETDEV_VTABLE(netdev)->fill_message_create) {
500 0 : r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, link, m);
501 0 : if (r < 0)
502 0 : return r;
503 : }
504 :
505 0 : r = sd_netlink_message_close_container(m);
506 0 : if (r < 0)
507 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
508 :
509 0 : r = sd_netlink_message_close_container(m);
510 0 : if (r < 0)
511 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
512 :
513 0 : if (link) {
514 0 : r = sd_netlink_call_async(netdev->manager->rtnl, m, callback, link, 0, NULL);
515 0 : if (r < 0)
516 0 : return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
517 :
518 0 : link_ref(link);
519 : } else {
520 0 : r = sd_netlink_call_async(netdev->manager->rtnl, m, netdev_create_handler, netdev, 0, NULL);
521 0 : if (r < 0)
522 0 : return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
523 :
524 0 : netdev_ref(netdev);
525 : }
526 :
527 0 : netdev->state = NETDEV_STATE_CREATING;
528 :
529 0 : log_netdev_debug(netdev, "Creating");
530 : }
531 :
532 0 : return 0;
533 : }
534 :
535 : /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
536 0 : int netdev_join(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback) {
537 : int r;
538 :
539 0 : assert(netdev);
540 0 : assert(netdev->manager);
541 0 : assert(netdev->manager->rtnl);
542 0 : assert(NETDEV_VTABLE(netdev));
543 :
544 0 : switch (NETDEV_VTABLE(netdev)->create_type) {
545 : case NETDEV_CREATE_MASTER:
546 0 : r = netdev_enslave(netdev, link, callback);
547 0 : if (r < 0)
548 0 : return r;
549 :
550 0 : break;
551 : case NETDEV_CREATE_STACKED:
552 0 : r = netdev_create(netdev, link, callback);
553 0 : if (r < 0)
554 0 : return r;
555 :
556 0 : break;
557 : default:
558 0 : assert_not_reached("Can not join independent netdev");
559 : }
560 :
561 0 : return 0;
562 : }
563 :
564 0 : static int netdev_load_one(Manager *manager, const char *filename) {
565 0 : _cleanup_netdev_unref_ NetDev *netdev = NULL;
566 0 : _cleanup_free_ NetDev *netdev_raw = NULL;
567 0 : _cleanup_fclose_ FILE *file = NULL;
568 : int r;
569 :
570 0 : assert(manager);
571 0 : assert(filename);
572 :
573 0 : file = fopen(filename, "re");
574 0 : if (!file) {
575 0 : if (errno == ENOENT)
576 0 : return 0;
577 : else
578 0 : return -errno;
579 : }
580 :
581 0 : if (null_or_empty_fd(fileno(file))) {
582 0 : log_debug("Skipping empty file: %s", filename);
583 0 : return 0;
584 : }
585 :
586 0 : netdev_raw = new0(NetDev, 1);
587 0 : if (!netdev_raw)
588 0 : return log_oom();
589 :
590 0 : netdev_raw->kind = _NETDEV_KIND_INVALID;
591 :
592 0 : r = config_parse(NULL, filename, file,
593 : "Match\0NetDev\0",
594 : config_item_perf_lookup, network_netdev_gperf_lookup,
595 : true, false, true, netdev_raw);
596 0 : if (r < 0)
597 0 : return r;
598 :
599 0 : r = fseek(file, 0, SEEK_SET);
600 0 : if (r < 0)
601 0 : return -errno;
602 :
603 : /* skip out early if configuration does not match the environment */
604 0 : if (net_match_config(NULL, NULL, NULL, NULL, NULL,
605 0 : netdev_raw->match_host, netdev_raw->match_virt,
606 0 : netdev_raw->match_kernel, netdev_raw->match_arch,
607 0 : NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
608 0 : return 0;
609 :
610 0 : if (!NETDEV_VTABLE(netdev_raw)) {
611 0 : log_warning("NetDev with invalid Kind configured in %s. Ignoring", filename);
612 0 : return 0;
613 : }
614 :
615 0 : if (!netdev_raw->ifname) {
616 0 : log_warning("NetDev without Name configured in %s. Ignoring", filename);
617 0 : return 0;
618 : }
619 :
620 0 : netdev = malloc0(NETDEV_VTABLE(netdev_raw)->object_size);
621 0 : if (!netdev)
622 0 : return log_oom();
623 :
624 0 : netdev->n_ref = 1;
625 0 : netdev->manager = manager;
626 0 : netdev->state = _NETDEV_STATE_INVALID;
627 0 : netdev->kind = netdev_raw->kind;
628 0 : netdev->ifname = netdev_raw->ifname;
629 :
630 0 : if (NETDEV_VTABLE(netdev)->init)
631 0 : NETDEV_VTABLE(netdev)->init(netdev);
632 :
633 0 : r = config_parse(NULL, filename, file,
634 0 : NETDEV_VTABLE(netdev)->sections,
635 : config_item_perf_lookup, network_netdev_gperf_lookup,
636 : false, false, false, netdev);
637 0 : if (r < 0)
638 0 : return r;
639 :
640 : /* verify configuration */
641 0 : if (NETDEV_VTABLE(netdev)->config_verify) {
642 0 : r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
643 0 : if (r < 0)
644 0 : return 0;
645 : }
646 :
647 0 : netdev->filename = strdup(filename);
648 0 : if (!netdev->filename)
649 0 : return log_oom();
650 :
651 0 : if (!netdev->mac) {
652 0 : r = netdev_get_mac(netdev->ifname, &netdev->mac);
653 0 : if (r < 0)
654 0 : return log_error_errno(r, "Failed to generate predictable MAC address for %s: %m", netdev->ifname);
655 : }
656 :
657 0 : r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
658 0 : if (r < 0)
659 0 : return r;
660 :
661 0 : LIST_HEAD_INIT(netdev->callbacks);
662 :
663 0 : log_netdev_debug(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
664 :
665 0 : switch (NETDEV_VTABLE(netdev)->create_type) {
666 : case NETDEV_CREATE_MASTER:
667 : case NETDEV_CREATE_INDEPENDENT:
668 0 : r = netdev_create(netdev, NULL, NULL);
669 0 : if (r < 0)
670 0 : return 0;
671 :
672 0 : break;
673 : default:
674 0 : break;
675 : }
676 :
677 0 : netdev = NULL;
678 :
679 0 : return 0;
680 : }
681 :
682 1 : int netdev_load(Manager *manager) {
683 2 : _cleanup_strv_free_ char **files = NULL;
684 : NetDev *netdev;
685 : char **f;
686 : int r;
687 :
688 1 : assert(manager);
689 :
690 2 : while ((netdev = hashmap_first(manager->netdevs)))
691 0 : netdev_unref(netdev);
692 :
693 1 : r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
694 1 : if (r < 0)
695 0 : return log_error_errno(r, "Failed to enumerate netdev files: %m");
696 :
697 1 : STRV_FOREACH_BACKWARDS(f, files) {
698 0 : r = netdev_load_one(manager, *f);
699 0 : if (r < 0)
700 0 : return r;
701 : }
702 :
703 1 : return 0;
704 : }
|