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 "conf-files.h"
28 #include "conf-parser.h"
30 #include "siphash24.h"
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_IPVLAN
] = &ipvlan_vtable
,
38 [NETDEV_KIND_VXLAN
] = &vxlan_vtable
,
39 [NETDEV_KIND_IPIP
] = &ipip_vtable
,
40 [NETDEV_KIND_GRE
] = &gre_vtable
,
41 [NETDEV_KIND_GRETAP
] = &gretap_vtable
,
42 [NETDEV_KIND_IP6GRE
] = &ip6gre_vtable
,
43 [NETDEV_KIND_IP6GRETAP
] = &ip6gretap_vtable
,
44 [NETDEV_KIND_SIT
] = &sit_vtable
,
45 [NETDEV_KIND_VTI
] = &vti_vtable
,
46 [NETDEV_KIND_VTI6
] = &vti6_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_VTI6
] = "vti6",
70 [NETDEV_KIND_DUMMY
] = "dummy",
71 [NETDEV_KIND_TUN
] = "tun",
72 [NETDEV_KIND_TAP
] = "tap",
73 [NETDEV_KIND_IP6TNL
] = "ip6tnl",
76 DEFINE_STRING_TABLE_LOOKUP(netdev_kind
, NetDevKind
);
77 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind
, netdev_kind
, NetDevKind
, "Failed to parse netdev kind");
79 static void netdev_cancel_callbacks(NetDev
*netdev
) {
80 _cleanup_rtnl_message_unref_ sd_rtnl_message
*m
= NULL
;
81 netdev_join_callback
*callback
;
86 rtnl_message_new_synthetic_error(-ENODEV
, 0, &m
);
88 while ((callback
= netdev
->callbacks
)) {
90 assert(callback
->link
);
91 assert(callback
->callback
);
92 assert(netdev
->manager
);
93 assert(netdev
->manager
->rtnl
);
95 callback
->callback(netdev
->manager
->rtnl
, m
, link
);
98 LIST_REMOVE(callbacks
, netdev
->callbacks
, callback
);
103 static void netdev_free(NetDev
*netdev
) {
107 netdev_cancel_callbacks(netdev
);
110 hashmap_remove(netdev
->manager
->netdevs
, netdev
->ifname
);
112 free(netdev
->filename
);
114 free(netdev
->description
);
115 free(netdev
->ifname
);
118 condition_free_list(netdev
->match_host
);
119 condition_free_list(netdev
->match_virt
);
120 condition_free_list(netdev
->match_kernel
);
121 condition_free_list(netdev
->match_arch
);
123 if (NETDEV_VTABLE(netdev
) &&
124 NETDEV_VTABLE(netdev
)->done
)
125 NETDEV_VTABLE(netdev
)->done(netdev
);
130 NetDev
*netdev_unref(NetDev
*netdev
) {
131 if (netdev
&& (-- netdev
->n_ref
<= 0))
137 NetDev
*netdev_ref(NetDev
*netdev
) {
139 assert_se(++ netdev
->n_ref
>= 2);
144 void netdev_drop(NetDev
*netdev
) {
145 if (!netdev
|| netdev
->state
== NETDEV_STATE_LINGER
)
148 netdev
->state
= NETDEV_STATE_LINGER
;
150 log_netdev_debug(netdev
, "netdev removed");
152 netdev_cancel_callbacks(netdev
);
154 netdev_unref(netdev
);
159 int netdev_get(Manager
*manager
, const char *name
, NetDev
**ret
) {
166 netdev
= hashmap_get(manager
->netdevs
, name
);
177 static int netdev_enter_failed(NetDev
*netdev
) {
178 netdev
->state
= NETDEV_STATE_FAILED
;
183 static int netdev_enslave_ready(NetDev
*netdev
, Link
* link
, sd_rtnl_message_handler_t callback
) {
184 _cleanup_rtnl_message_unref_ sd_rtnl_message
*req
= NULL
;
188 assert(netdev
->state
== NETDEV_STATE_READY
);
189 assert(netdev
->manager
);
190 assert(netdev
->manager
->rtnl
);
191 assert(IN_SET(netdev
->kind
, NETDEV_KIND_BRIDGE
, NETDEV_KIND_BOND
));
195 r
= sd_rtnl_message_new_link(netdev
->manager
->rtnl
, &req
, RTM_SETLINK
, link
->ifindex
);
197 return log_netdev_error_errno(netdev
, r
, "Could not allocate RTM_SETLINK message: %m");
199 r
= sd_rtnl_message_append_u32(req
, IFLA_MASTER
, netdev
->ifindex
);
201 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_MASTER attribute: %m");
203 r
= sd_rtnl_call_async(netdev
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
205 return log_netdev_error(netdev
, "Could not send rtnetlink message: %m");
209 log_netdev_debug(netdev
, "Enslaving link '%s'", link
->ifname
);
214 static int netdev_enter_ready(NetDev
*netdev
) {
215 netdev_join_callback
*callback
, *callback_next
;
219 assert(netdev
->ifname
);
221 if (netdev
->state
!= NETDEV_STATE_CREATING
)
224 netdev
->state
= NETDEV_STATE_READY
;
226 log_netdev_info(netdev
, "netdev ready");
228 LIST_FOREACH_SAFE(callbacks
, callback
, callback_next
, netdev
->callbacks
) {
229 /* enslave the links that were attempted to be enslaved before the
231 r
= netdev_enslave_ready(netdev
, callback
->link
, callback
->callback
);
235 LIST_REMOVE(callbacks
, netdev
->callbacks
, callback
);
236 link_unref(callback
->link
);
243 /* callback for netdev's created without a backing Link */
244 static int netdev_create_handler(sd_rtnl
*rtnl
, sd_rtnl_message
*m
, void *userdata
) {
245 _cleanup_netdev_unref_ NetDev
*netdev
= userdata
;
248 assert(netdev
->state
!= _NETDEV_STATE_INVALID
);
250 r
= sd_rtnl_message_get_errno(m
);
252 log_netdev_info(netdev
, "netdev exists, using existing without changing its parameters");
254 log_netdev_warning_errno(netdev
, r
, "netdev could not be created: %m");
260 log_netdev_debug(netdev
, "Created");
265 int netdev_enslave(NetDev
*netdev
, Link
*link
, sd_rtnl_message_handler_t callback
) {
269 assert(IN_SET(netdev
->kind
, NETDEV_KIND_BRIDGE
, NETDEV_KIND_BOND
));
271 if (netdev
->state
== NETDEV_STATE_READY
) {
272 r
= netdev_enslave_ready(netdev
, link
, callback
);
276 /* the netdev is not yet read, save this request for when it is */
277 netdev_join_callback
*cb
;
279 cb
= new0(netdev_join_callback
, 1);
283 cb
->callback
= callback
;
287 LIST_PREPEND(callbacks
, netdev
->callbacks
, cb
);
289 log_netdev_debug(netdev
, "Will enslave '%s', when ready", link
->ifname
);
295 int netdev_set_ifindex(NetDev
*netdev
, sd_rtnl_message
*message
) {
298 const char *received_kind
;
299 const char *received_name
;
305 r
= sd_rtnl_message_get_type(message
, &type
);
307 return log_netdev_error_errno(netdev
, r
, "Could not get rtnl message type: %m");
309 if (type
!= RTM_NEWLINK
) {
310 log_netdev_error(netdev
, "Cannot set ifindex from unexpected rtnl message type.");
314 r
= sd_rtnl_message_link_get_ifindex(message
, &ifindex
);
316 log_netdev_error_errno(netdev
, r
, "Could not get ifindex: %m");
317 netdev_enter_failed(netdev
);
319 } else if (ifindex
<= 0) {
320 log_netdev_error(netdev
, "Got invalid ifindex: %d", ifindex
);
321 netdev_enter_failed(netdev
);
325 if (netdev
->ifindex
> 0) {
326 if (netdev
->ifindex
!= ifindex
) {
327 log_netdev_error(netdev
, "Could not set ifindex to %d, already set to %d",
328 ifindex
, netdev
->ifindex
);
329 netdev_enter_failed(netdev
);
332 /* ifindex already set to the same for this netdev */
336 r
= sd_rtnl_message_read_string(message
, IFLA_IFNAME
, &received_name
);
338 return log_netdev_error_errno(netdev
, r
, "Could not get IFNAME: %m");
340 if (!streq(netdev
->ifname
, received_name
)) {
341 log_netdev_error(netdev
, "Received newlink with wrong IFNAME %s", received_name
);
342 netdev_enter_failed(netdev
);
346 r
= sd_rtnl_message_enter_container(message
, IFLA_LINKINFO
);
348 return log_netdev_error_errno(netdev
, r
, "Could not get LINKINFO: %m");
350 r
= sd_rtnl_message_read_string(message
, IFLA_INFO_KIND
, &received_kind
);
352 return log_netdev_error_errno(netdev
, r
, "Could not get KIND: %m");
354 r
= sd_rtnl_message_exit_container(message
);
356 return log_netdev_error_errno(netdev
, r
, "Could not exit container: %m");
358 if (netdev
->kind
== NETDEV_KIND_TAP
)
359 /* the kernel does not distinguish between tun and tap */
362 kind
= netdev_kind_to_string(netdev
->kind
);
364 log_netdev_error(netdev
, "Could not get kind");
365 netdev_enter_failed(netdev
);
370 if (!streq(kind
, received_kind
)) {
371 log_netdev_error(netdev
,
372 "Received newlink with wrong KIND %s, "
373 "expected %s", received_kind
, kind
);
374 netdev_enter_failed(netdev
);
378 netdev
->ifindex
= ifindex
;
380 log_netdev_debug(netdev
, "netdev has index %d", netdev
->ifindex
);
382 netdev_enter_ready(netdev
);
387 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
389 int netdev_get_mac(const char *ifname
, struct ether_addr
**ret
) {
390 _cleanup_free_
struct ether_addr
*mac
= NULL
;
399 mac
= new0(struct ether_addr
, 1);
404 sz
= sizeof(sd_id128_t
) + l
;
407 /* fetch some persistent data unique to the machine */
408 r
= sd_id128_get_machine((sd_id128_t
*) v
);
412 /* combine with some data unique (on this machine) to this
414 memcpy(v
+ sizeof(sd_id128_t
), ifname
, l
);
416 /* Let's hash the host machine ID plus the container name. We
417 * use a fixed, but originally randomly created hash key here. */
418 siphash24(result
, v
, sz
, HASH_KEY
.bytes
);
420 assert_cc(ETH_ALEN
<= sizeof(result
));
421 memcpy(mac
->ether_addr_octet
, result
, ETH_ALEN
);
423 /* see eth_random_addr in the kernel */
424 mac
->ether_addr_octet
[0] &= 0xfe; /* clear multicast bit */
425 mac
->ether_addr_octet
[0] |= 0x02; /* set local assignment bit (IEEE802) */
433 static int netdev_create(NetDev
*netdev
, Link
*link
,
434 sd_rtnl_message_handler_t callback
) {
438 assert(!link
|| callback
);
441 if (NETDEV_VTABLE(netdev
)->create
) {
444 r
= NETDEV_VTABLE(netdev
)->create(netdev
);
448 log_netdev_debug(netdev
, "Created");
450 _cleanup_rtnl_message_unref_ sd_rtnl_message
*m
= NULL
;
452 r
= sd_rtnl_message_new_link(netdev
->manager
->rtnl
, &m
, RTM_NEWLINK
, 0);
454 return log_netdev_error_errno(netdev
, r
, "Could not allocate RTM_NEWLINK message: %m");
456 r
= sd_rtnl_message_append_string(m
, IFLA_IFNAME
, netdev
->ifname
);
458 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IFNAME, attribute: %m");
461 r
= sd_rtnl_message_append_ether_addr(m
, IFLA_ADDRESS
, netdev
->mac
);
463 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_ADDRESS attribute: %m");
467 r
= sd_rtnl_message_append_u32(m
, IFLA_MTU
, netdev
->mtu
);
469 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_MTU attribute: %m");
473 r
= sd_rtnl_message_append_u32(m
, IFLA_LINK
, link
->ifindex
);
475 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_LINK attribute: %m");
478 r
= sd_rtnl_message_open_container(m
, IFLA_LINKINFO
);
480 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_LINKINFO attribute: %m");
482 r
= sd_rtnl_message_open_container_union(m
, IFLA_INFO_DATA
, netdev_kind_to_string(netdev
->kind
));
484 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_INFO_DATA attribute: %m");
486 if (NETDEV_VTABLE(netdev
)->fill_message_create
) {
487 r
= NETDEV_VTABLE(netdev
)->fill_message_create(netdev
, link
, m
);
492 r
= sd_rtnl_message_close_container(m
);
494 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_LINKINFO attribute: %m");
496 r
= sd_rtnl_message_close_container(m
);
498 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_LINKINFO attribute: %m");
501 r
= sd_rtnl_call_async(netdev
->manager
->rtnl
, m
, callback
, link
, 0, NULL
);
503 return log_netdev_error_errno(netdev
, r
, "Could not send rtnetlink message: %m");
507 r
= sd_rtnl_call_async(netdev
->manager
->rtnl
, m
, netdev_create_handler
, netdev
, 0, NULL
);
509 return log_netdev_error_errno(netdev
, r
, "Could not send rtnetlink message: %m");
514 netdev
->state
= NETDEV_STATE_CREATING
;
516 log_netdev_debug(netdev
, "Creating");
522 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
523 int netdev_join(NetDev
*netdev
, Link
*link
, sd_rtnl_message_handler_t callback
) {
527 assert(netdev
->manager
);
528 assert(netdev
->manager
->rtnl
);
529 assert(NETDEV_VTABLE(netdev
));
531 switch (NETDEV_VTABLE(netdev
)->create_type
) {
532 case NETDEV_CREATE_MASTER
:
533 r
= netdev_enslave(netdev
, link
, callback
);
538 case NETDEV_CREATE_STACKED
:
539 r
= netdev_create(netdev
, link
, callback
);
545 assert_not_reached("Can not join independent netdev");
551 static int netdev_load_one(Manager
*manager
, const char *filename
) {
552 _cleanup_netdev_unref_ NetDev
*netdev
= NULL
;
553 _cleanup_free_ NetDev
*netdev_raw
= NULL
;
554 _cleanup_fclose_
FILE *file
= NULL
;
560 file
= fopen(filename
, "re");
568 if (null_or_empty_fd(fileno(file
))) {
569 log_debug("Skipping empty file: %s", filename
);
573 netdev_raw
= new0(NetDev
, 1);
577 netdev_raw
->kind
= _NETDEV_KIND_INVALID
;
579 r
= config_parse(NULL
, filename
, file
,
581 config_item_perf_lookup
, network_netdev_gperf_lookup
,
582 true, false, true, netdev_raw
);
586 r
= fseek(file
, 0, SEEK_SET
);
590 /* skip out early if configuration does not match the environment */
591 if (net_match_config(NULL
, NULL
, NULL
, NULL
, NULL
,
592 netdev_raw
->match_host
, netdev_raw
->match_virt
,
593 netdev_raw
->match_kernel
, netdev_raw
->match_arch
,
594 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) <= 0)
597 if (!NETDEV_VTABLE(netdev_raw
)) {
598 log_warning("NetDev with invalid Kind configured in %s. Ignoring", filename
);
602 if (!netdev_raw
->ifname
) {
603 log_warning("NetDev without Name configured in %s. Ignoring", filename
);
607 netdev
= malloc0(NETDEV_VTABLE(netdev_raw
)->object_size
);
612 netdev
->manager
= manager
;
613 netdev
->state
= _NETDEV_STATE_INVALID
;
614 netdev
->kind
= netdev_raw
->kind
;
615 netdev
->ifname
= netdev_raw
->ifname
;
617 if (NETDEV_VTABLE(netdev
)->init
)
618 NETDEV_VTABLE(netdev
)->init(netdev
);
620 r
= config_parse(NULL
, filename
, file
,
621 NETDEV_VTABLE(netdev
)->sections
,
622 config_item_perf_lookup
, network_netdev_gperf_lookup
,
623 false, false, false, netdev
);
627 /* verify configuration */
628 if (NETDEV_VTABLE(netdev
)->config_verify
) {
629 r
= NETDEV_VTABLE(netdev
)->config_verify(netdev
, filename
);
634 netdev
->filename
= strdup(filename
);
635 if (!netdev
->filename
)
639 r
= netdev_get_mac(netdev
->ifname
, &netdev
->mac
);
641 return log_error_errno(r
, "Failed to generate predictable MAC address for %s: %m", netdev
->ifname
);
644 r
= hashmap_put(netdev
->manager
->netdevs
, netdev
->ifname
, netdev
);
648 LIST_HEAD_INIT(netdev
->callbacks
);
650 log_netdev_debug(netdev
, "loaded %s", netdev_kind_to_string(netdev
->kind
));
652 switch (NETDEV_VTABLE(netdev
)->create_type
) {
653 case NETDEV_CREATE_MASTER
:
654 case NETDEV_CREATE_INDEPENDENT
:
655 r
= netdev_create(netdev
, NULL
, NULL
);
669 int netdev_load(Manager
*manager
) {
670 _cleanup_strv_free_
char **files
= NULL
;
677 while ((netdev
= hashmap_first(manager
->netdevs
)))
678 netdev_unref(netdev
);
680 r
= conf_files_list_strv(&files
, ".netdev", NULL
, network_dirs
);
682 return log_error_errno(r
, "Failed to enumerate netdev files: %m");
684 STRV_FOREACH_BACKWARDS(f
, files
) {
685 r
= netdev_load_one(manager
, *f
);