1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
24 #include "networkd-netdev.h"
25 #include "networkd-link.h"
26 #include "network-internal.h"
27 #include "path-util.h"
28 #include "conf-files.h"
29 #include "conf-parser.h"
31 #include "siphash24.h"
33 const NetDevVTable
* const netdev_vtable
[_NETDEV_KIND_MAX
] = {
34 [NETDEV_KIND_BRIDGE
] = &bridge_vtable
,
35 [NETDEV_KIND_BOND
] = &bond_vtable
,
36 [NETDEV_KIND_VLAN
] = &vlan_vtable
,
37 [NETDEV_KIND_MACVLAN
] = &macvlan_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_VETH
] = &veth_vtable
,
48 [NETDEV_KIND_DUMMY
] = &dummy_vtable
,
49 [NETDEV_KIND_TUN
] = &tun_vtable
,
50 [NETDEV_KIND_TAP
] = &tap_vtable
,
51 [NETDEV_KIND_IP6TNL
] = &ip6tnl_vtable
,
54 static const char* const netdev_kind_table
[_NETDEV_KIND_MAX
] = {
55 [NETDEV_KIND_BRIDGE
] = "bridge",
56 [NETDEV_KIND_BOND
] = "bond",
57 [NETDEV_KIND_VLAN
] = "vlan",
58 [NETDEV_KIND_MACVLAN
] = "macvlan",
59 [NETDEV_KIND_IPVLAN
] = "ipvlan",
60 [NETDEV_KIND_VXLAN
] = "vxlan",
61 [NETDEV_KIND_IPIP
] = "ipip",
62 [NETDEV_KIND_GRE
] = "gre",
63 [NETDEV_KIND_GRETAP
] = "gretap",
64 [NETDEV_KIND_IP6GRE
] = "ip6gre",
65 [NETDEV_KIND_IP6GRETAP
] = "ip6gretap",
66 [NETDEV_KIND_SIT
] = "sit",
67 [NETDEV_KIND_VETH
] = "veth",
68 [NETDEV_KIND_VTI
] = "vti",
69 [NETDEV_KIND_DUMMY
] = "dummy",
70 [NETDEV_KIND_TUN
] = "tun",
71 [NETDEV_KIND_TAP
] = "tap",
72 [NETDEV_KIND_IP6TNL
] = "ip6tnl",
75 DEFINE_STRING_TABLE_LOOKUP(netdev_kind
, NetDevKind
);
76 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind
, netdev_kind
, NetDevKind
, "Failed to parse netdev kind");
78 static void netdev_cancel_callbacks(NetDev
*netdev
) {
79 _cleanup_rtnl_message_unref_ sd_rtnl_message
*m
= NULL
;
80 netdev_join_callback
*callback
;
85 rtnl_message_new_synthetic_error(-ENODEV
, 0, &m
);
87 while ((callback
= netdev
->callbacks
)) {
89 assert(callback
->link
);
90 assert(callback
->callback
);
91 assert(netdev
->manager
);
92 assert(netdev
->manager
->rtnl
);
94 callback
->callback(netdev
->manager
->rtnl
, m
, link
);
97 LIST_REMOVE(callbacks
, netdev
->callbacks
, callback
);
102 static void netdev_free(NetDev
*netdev
) {
106 netdev_cancel_callbacks(netdev
);
109 hashmap_remove(netdev
->manager
->netdevs
, netdev
->ifname
);
111 free(netdev
->filename
);
113 free(netdev
->description
);
114 free(netdev
->ifname
);
117 condition_free_list(netdev
->match_host
);
118 condition_free_list(netdev
->match_virt
);
119 condition_free_list(netdev
->match_kernel
);
120 condition_free_list(netdev
->match_arch
);
122 if (NETDEV_VTABLE(netdev
) &&
123 NETDEV_VTABLE(netdev
)->done
)
124 NETDEV_VTABLE(netdev
)->done(netdev
);
129 NetDev
*netdev_unref(NetDev
*netdev
) {
130 if (netdev
&& (-- netdev
->n_ref
<= 0))
136 NetDev
*netdev_ref(NetDev
*netdev
) {
138 assert_se(++ netdev
->n_ref
>= 2);
143 void netdev_drop(NetDev
*netdev
) {
144 if (!netdev
|| netdev
->state
== NETDEV_STATE_LINGER
)
147 netdev
->state
= NETDEV_STATE_LINGER
;
149 log_netdev_debug(netdev
, "netdev removed");
151 netdev_cancel_callbacks(netdev
);
153 netdev_unref(netdev
);
158 int netdev_get(Manager
*manager
, const char *name
, NetDev
**ret
) {
165 netdev
= hashmap_get(manager
->netdevs
, name
);
176 static int netdev_enter_failed(NetDev
*netdev
) {
177 netdev
->state
= NETDEV_STATE_FAILED
;
182 static int netdev_enslave_ready(NetDev
*netdev
, Link
* link
, sd_rtnl_message_handler_t callback
) {
183 _cleanup_rtnl_message_unref_ sd_rtnl_message
*req
= NULL
;
187 assert(netdev
->state
== NETDEV_STATE_READY
);
188 assert(netdev
->manager
);
189 assert(netdev
->manager
->rtnl
);
190 assert(IN_SET(netdev
->kind
, NETDEV_KIND_BRIDGE
, NETDEV_KIND_BOND
));
194 r
= sd_rtnl_message_new_link(netdev
->manager
->rtnl
, &req
,
195 RTM_SETLINK
, link
->ifindex
);
197 log_netdev_error(netdev
,
198 "Could not allocate RTM_SETLINK message: %s",
203 r
= sd_rtnl_message_append_u32(req
, IFLA_MASTER
, netdev
->ifindex
);
205 log_netdev_error(netdev
,
206 "Could not append IFLA_MASTER attribute: %s",
211 r
= sd_rtnl_call_async(netdev
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
213 log_netdev_error(netdev
,
214 "Could not send rtnetlink message: %s",
221 log_netdev_debug(netdev
, "enslaving link '%s'", link
->ifname
);
226 static int netdev_enter_ready(NetDev
*netdev
) {
227 netdev_join_callback
*callback
, *callback_next
;
231 assert(netdev
->ifname
);
233 if (netdev
->state
!= NETDEV_STATE_CREATING
)
236 netdev
->state
= NETDEV_STATE_READY
;
238 log_info_netdev(netdev
, "netdev ready");
240 LIST_FOREACH_SAFE(callbacks
, callback
, callback_next
, netdev
->callbacks
) {
241 /* enslave the links that were attempted to be enslaved before the
243 r
= netdev_enslave_ready(netdev
, callback
->link
, callback
->callback
);
247 LIST_REMOVE(callbacks
, netdev
->callbacks
, callback
);
248 link_unref(callback
->link
);
255 /* callback for netdev's created without a backing Link */
256 static int netdev_create_handler(sd_rtnl
*rtnl
, sd_rtnl_message
*m
, void *userdata
) {
257 _cleanup_netdev_unref_ NetDev
*netdev
= userdata
;
260 assert(netdev
->state
!= _NETDEV_STATE_INVALID
);
262 r
= sd_rtnl_message_get_errno(m
);
264 log_netdev_debug(netdev
, "netdev exists, using existing");
266 log_warning_netdev(netdev
, "netdev could not be created: %s", strerror(-r
));
272 log_netdev_debug(netdev
, "created");
277 int netdev_enslave(NetDev
*netdev
, Link
*link
, sd_rtnl_message_handler_t callback
) {
281 assert(IN_SET(netdev
->kind
, NETDEV_KIND_BRIDGE
, NETDEV_KIND_BOND
));
283 if (netdev
->state
== NETDEV_STATE_READY
) {
284 r
= netdev_enslave_ready(netdev
, link
, callback
);
288 /* the netdev is not yet read, save this request for when it is */
289 netdev_join_callback
*cb
;
291 cb
= new0(netdev_join_callback
, 1);
295 cb
->callback
= callback
;
299 LIST_PREPEND(callbacks
, netdev
->callbacks
, cb
);
301 log_netdev_debug(netdev
, "will enslave '%s', when reday",
308 int netdev_set_ifindex(NetDev
*netdev
, sd_rtnl_message
*message
) {
311 const char *received_kind
;
312 const char *received_name
;
318 r
= sd_rtnl_message_get_type(message
, &type
);
320 log_netdev_error(netdev
, "Could not get rtnl message type");
324 if (type
!= RTM_NEWLINK
) {
325 log_netdev_error(netdev
, "Can not set ifindex from unexpected rtnl message type");
329 r
= sd_rtnl_message_link_get_ifindex(message
, &ifindex
);
331 log_netdev_error(netdev
, "Could not get ifindex: %s", strerror(-r
));
332 netdev_enter_failed(netdev
);
334 } else if (ifindex
<= 0) {
335 log_netdev_error(netdev
, "Got invalid ifindex: %d", ifindex
);
336 netdev_enter_failed(netdev
);
340 if (netdev
->ifindex
> 0) {
341 if (netdev
->ifindex
!= ifindex
) {
342 log_netdev_error(netdev
, "Could not set ifindex to %d, already set to %d",
343 ifindex
, netdev
->ifindex
);
344 netdev_enter_failed(netdev
);
347 /* ifindex already set to the same for this netdev */
351 r
= sd_rtnl_message_read_string(message
, IFLA_IFNAME
, &received_name
);
353 log_netdev_error(netdev
, "Could not get IFNAME");
357 if (!streq(netdev
->ifname
, received_name
)) {
358 log_netdev_error(netdev
, "Received newlink with wrong IFNAME %s",
360 netdev_enter_failed(netdev
);
364 r
= sd_rtnl_message_enter_container(message
, IFLA_LINKINFO
);
366 log_netdev_error(netdev
, "Could not get LINKINFO");
370 r
= sd_rtnl_message_read_string(message
, IFLA_INFO_KIND
, &received_kind
);
372 log_netdev_error(netdev
, "Could not get KIND");
376 r
= sd_rtnl_message_exit_container(message
);
378 log_netdev_error(netdev
, "Could not exit container");
382 if (netdev
->kind
== NETDEV_KIND_TAP
)
383 /* the kernel does not distinguish between tun and tap */
386 kind
= netdev_kind_to_string(netdev
->kind
);
388 log_netdev_error(netdev
, "Could not get kind");
389 netdev_enter_failed(netdev
);
394 if (!streq(kind
, received_kind
)) {
395 log_netdev_error(netdev
,
396 "Received newlink with wrong KIND %s, "
397 "expected %s", received_kind
, kind
);
398 netdev_enter_failed(netdev
);
402 netdev
->ifindex
= ifindex
;
404 log_netdev_debug(netdev
, "netdev has index %d", netdev
->ifindex
);
406 netdev_enter_ready(netdev
);
411 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
413 int netdev_get_mac(const char *ifname
, struct ether_addr
**ret
) {
414 _cleanup_free_
struct ether_addr
*mac
= NULL
;
423 mac
= new0(struct ether_addr
, 1);
428 sz
= sizeof(sd_id128_t
) + l
;
431 /* fetch some persistent data unique to the machine */
432 r
= sd_id128_get_machine((sd_id128_t
*) v
);
436 /* combine with some data unique (on this machine) to this
438 memcpy(v
+ sizeof(sd_id128_t
), ifname
, l
);
440 /* Let's hash the host machine ID plus the container name. We
441 * use a fixed, but originally randomly created hash key here. */
442 siphash24(result
, v
, sz
, HASH_KEY
.bytes
);
444 assert_cc(ETH_ALEN
<= sizeof(result
));
445 memcpy(mac
->ether_addr_octet
, result
, ETH_ALEN
);
447 /* see eth_random_addr in the kernel */
448 mac
->ether_addr_octet
[0] &= 0xfe; /* clear multicast bit */
449 mac
->ether_addr_octet
[0] |= 0x02; /* set local assignment bit (IEEE802) */
457 static int netdev_create(NetDev
*netdev
, Link
*link
,
458 sd_rtnl_message_handler_t callback
) {
462 assert(!link
|| callback
);
465 if (NETDEV_VTABLE(netdev
)->create
) {
468 r
= NETDEV_VTABLE(netdev
)->create(netdev
);
472 log_netdev_debug(netdev
, "created");
474 _cleanup_rtnl_message_unref_ sd_rtnl_message
*m
= NULL
;
476 r
= sd_rtnl_message_new_link(netdev
->manager
->rtnl
, &m
, RTM_NEWLINK
, 0);
478 log_netdev_error(netdev
,
479 "Could not allocate RTM_NEWLINK message: %s",
484 r
= sd_rtnl_message_append_string(m
, IFLA_IFNAME
, netdev
->ifname
);
486 log_netdev_error(netdev
,
487 "Could not append IFLA_IFNAME, attribute: %s",
493 r
= sd_rtnl_message_append_ether_addr(m
, IFLA_ADDRESS
, netdev
->mac
);
495 log_netdev_error(netdev
,
496 "Could not append IFLA_ADDRESS attribute: %s",
503 r
= sd_rtnl_message_append_u32(m
, IFLA_MTU
, netdev
->mtu
);
505 log_netdev_error(netdev
,
506 "Could not append IFLA_MTU attribute: %s",
513 r
= sd_rtnl_message_append_u32(m
, IFLA_LINK
, link
->ifindex
);
515 log_netdev_error(netdev
,
516 "Could not append IFLA_LINK attribute: %s",
522 r
= sd_rtnl_message_open_container(m
, IFLA_LINKINFO
);
524 log_netdev_error(netdev
,
525 "Could not append IFLA_LINKINFO attribute: %s",
530 r
= sd_rtnl_message_open_container_union(m
, IFLA_INFO_DATA
,
531 netdev_kind_to_string(netdev
->kind
));
533 log_netdev_error(netdev
,
534 "Could not append IFLA_INFO_DATA attribute: %s",
539 if (NETDEV_VTABLE(netdev
)->fill_message_create
) {
540 r
= NETDEV_VTABLE(netdev
)->fill_message_create(netdev
, link
, m
);
545 r
= sd_rtnl_message_close_container(m
);
547 log_netdev_error(netdev
,
548 "Could not append IFLA_LINKINFO attribute: %s",
553 r
= sd_rtnl_message_close_container(m
);
555 log_netdev_error(netdev
,
556 "Could not append IFLA_LINKINFO attribute: %s",
563 r
= sd_rtnl_call_async(netdev
->manager
->rtnl
, m
,
564 callback
, link
, 0, NULL
);
566 log_netdev_error(netdev
,
567 "Could not send rtnetlink message: %s",
574 r
= sd_rtnl_call_async(netdev
->manager
->rtnl
, m
,
575 netdev_create_handler
, netdev
, 0,
578 log_netdev_error(netdev
,
579 "Could not send rtnetlink message: %s",
587 netdev
->state
= NETDEV_STATE_CREATING
;
589 log_netdev_debug(netdev
, "creating");
595 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
596 int netdev_join(NetDev
*netdev
, Link
*link
, sd_rtnl_message_handler_t callback
) {
600 assert(netdev
->manager
);
601 assert(netdev
->manager
->rtnl
);
602 assert(NETDEV_VTABLE(netdev
));
604 switch (NETDEV_VTABLE(netdev
)->create_type
) {
605 case NETDEV_CREATE_MASTER
:
606 r
= netdev_enslave(netdev
, link
, callback
);
611 case NETDEV_CREATE_STACKED
:
612 r
= netdev_create(netdev
, link
, callback
);
618 assert_not_reached("Can not join independent netdev");
624 static int netdev_load_one(Manager
*manager
, const char *filename
) {
625 _cleanup_netdev_unref_ NetDev
*netdev
= NULL
;
626 _cleanup_free_ NetDev
*netdev_raw
= NULL
;
627 _cleanup_fclose_
FILE *file
= NULL
;
633 file
= fopen(filename
, "re");
641 if (null_or_empty_fd(fileno(file
))) {
642 log_debug("Skipping empty file: %s", filename
);
646 netdev_raw
= new0(NetDev
, 1);
650 netdev_raw
->kind
= _NETDEV_KIND_INVALID
;
652 r
= config_parse(NULL
, filename
, file
,
654 config_item_perf_lookup
, network_netdev_gperf_lookup
,
655 true, false, true, netdev_raw
);
659 r
= fseek(file
, 0, SEEK_SET
);
663 /* skip out early if configuration does not match the environment */
664 if (net_match_config(NULL
, NULL
, NULL
, NULL
, NULL
,
665 netdev_raw
->match_host
, netdev_raw
->match_virt
,
666 netdev_raw
->match_kernel
, netdev_raw
->match_arch
,
667 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) <= 0)
670 if (!NETDEV_VTABLE(netdev_raw
)) {
671 log_warning("NetDev with invalid Kind configured in %s. Ignoring", filename
);
675 if (!netdev_raw
->ifname
) {
676 log_warning("NetDev without Name configured in %s. Ignoring", filename
);
680 netdev
= malloc0(NETDEV_VTABLE(netdev_raw
)->object_size
);
685 netdev
->manager
= manager
;
686 netdev
->state
= _NETDEV_STATE_INVALID
;
687 netdev
->kind
= netdev_raw
->kind
;
688 netdev
->ifname
= netdev_raw
->ifname
;
690 if (NETDEV_VTABLE(netdev
)->init
)
691 NETDEV_VTABLE(netdev
)->init(netdev
);
693 r
= config_parse(NULL
, filename
, file
,
694 NETDEV_VTABLE(netdev
)->sections
,
695 config_item_perf_lookup
, network_netdev_gperf_lookup
,
696 false, false, false, netdev
);
700 /* verify configuration */
701 if (NETDEV_VTABLE(netdev
)->config_verify
) {
702 r
= NETDEV_VTABLE(netdev
)->config_verify(netdev
, filename
);
707 netdev
->filename
= strdup(filename
);
708 if (!netdev
->filename
)
712 r
= netdev_get_mac(netdev
->ifname
, &netdev
->mac
);
714 log_error("Failed to generate predictable MAC address for %s",
720 r
= hashmap_put(netdev
->manager
->netdevs
, netdev
->ifname
, netdev
);
724 LIST_HEAD_INIT(netdev
->callbacks
);
726 log_netdev_debug(netdev
, "loaded %s", netdev_kind_to_string(netdev
->kind
));
728 switch (NETDEV_VTABLE(netdev
)->create_type
) {
729 case NETDEV_CREATE_MASTER
:
730 case NETDEV_CREATE_INDEPENDENT
:
731 r
= netdev_create(netdev
, NULL
, NULL
);
745 int netdev_load(Manager
*manager
) {
752 while ((netdev
= hashmap_first(manager
->netdevs
)))
753 netdev_unref(netdev
);
755 r
= conf_files_list_strv(&files
, ".netdev", NULL
, network_dirs
);
757 return log_error_errno(r
, "Failed to enumerate netdev files: %m");
759 STRV_FOREACH_BACKWARDS(f
, files
) {
760 r
= netdev_load_one(manager
, *f
);