1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include <linux/veth.h>
8 #include "sd-netlink.h"
10 #include "alloc-util.h"
11 #include "ether-addr-util.h"
12 #include "lockfile-util.h"
13 #include "missing_network.h"
14 #include "netlink-util.h"
15 #include "nspawn-network.h"
16 #include "parse-util.h"
17 #include "siphash24.h"
18 #include "socket-util.h"
19 #include "stat-util.h"
20 #include "string-util.h"
22 #include "udev-util.h"
25 #define HOST_HASH_KEY SD_ID128_MAKE(1a,37,6f,c7,46,ec,45,0b,ad,a3,d5,31,06,60,5d,b1)
26 #define CONTAINER_HASH_KEY SD_ID128_MAKE(c3,c4,f9,19,b5,57,b2,1c,e6,cf,14,27,03,9c,ee,a2)
27 #define VETH_EXTRA_HOST_HASH_KEY SD_ID128_MAKE(48,c7,f6,b7,ea,9d,4c,9e,b7,28,d4,de,91,d5,bf,66)
28 #define VETH_EXTRA_CONTAINER_HASH_KEY SD_ID128_MAKE(af,50,17,61,ce,f9,4d,35,84,0d,2b,20,54,be,ce,59)
29 #define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f)
31 static int remove_one_link(sd_netlink
*rtnl
, const char *name
) {
32 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
38 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_DELLINK
, 0);
40 return log_error_errno(r
, "Failed to allocate netlink message: %m");
42 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, name
);
44 return log_error_errno(r
, "Failed to add netlink interface name: %m");
46 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
47 if (r
== -ENODEV
) /* Already gone */
50 return log_error_errno(r
, "Failed to remove interface %s: %m", name
);
55 static int generate_mac(
56 const char *machine_name
,
57 struct ether_addr
*mac
,
66 l
= strlen(machine_name
);
67 sz
= sizeof(sd_id128_t
) + l
;
71 v
= newa(uint8_t, sz
);
73 /* fetch some persistent data unique to the host */
74 r
= sd_id128_get_machine((sd_id128_t
*) v
);
78 /* combine with some data unique (on this host) to this
79 * container instance */
80 i
= mempcpy(v
+ sizeof(sd_id128_t
), machine_name
, l
);
83 memcpy(i
, &idx
, sizeof(idx
));
86 /* Let's hash the host machine ID plus the container name. We
87 * use a fixed, but originally randomly created hash key here. */
88 result
= htole64(siphash24(v
, sz
, hash_key
.bytes
));
90 assert_cc(ETH_ALEN
<= sizeof(result
));
91 memcpy(mac
->ether_addr_octet
, &result
, ETH_ALEN
);
93 /* see eth_random_addr in the kernel */
94 mac
->ether_addr_octet
[0] &= 0xfe; /* clear multicast bit */
95 mac
->ether_addr_octet
[0] |= 0x02; /* set local assignment bit (IEEE802) */
103 const char *ifname_host
,
104 const struct ether_addr
*mac_host
,
105 const char *ifname_container
,
106 const struct ether_addr
*mac_container
) {
108 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
114 assert(ifname_container
);
115 assert(mac_container
);
117 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_NEWLINK
, 0);
119 return log_error_errno(r
, "Failed to allocate netlink message: %m");
121 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, ifname_host
);
123 return log_error_errno(r
, "Failed to add netlink interface name: %m");
125 r
= sd_netlink_message_append_ether_addr(m
, IFLA_ADDRESS
, mac_host
);
127 return log_error_errno(r
, "Failed to add netlink MAC address: %m");
129 r
= sd_netlink_message_open_container(m
, IFLA_LINKINFO
);
131 return log_error_errno(r
, "Failed to open netlink container: %m");
133 r
= sd_netlink_message_open_container_union(m
, IFLA_INFO_DATA
, "veth");
135 return log_error_errno(r
, "Failed to open netlink container: %m");
137 r
= sd_netlink_message_open_container(m
, VETH_INFO_PEER
);
139 return log_error_errno(r
, "Failed to open netlink container: %m");
141 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, ifname_container
);
143 return log_error_errno(r
, "Failed to add netlink interface name: %m");
145 r
= sd_netlink_message_append_ether_addr(m
, IFLA_ADDRESS
, mac_container
);
147 return log_error_errno(r
, "Failed to add netlink MAC address: %m");
149 r
= sd_netlink_message_append_u32(m
, IFLA_NET_NS_PID
, pid
);
151 return log_error_errno(r
, "Failed to add netlink namespace field: %m");
153 r
= sd_netlink_message_close_container(m
);
155 return log_error_errno(r
, "Failed to close netlink container: %m");
157 r
= sd_netlink_message_close_container(m
);
159 return log_error_errno(r
, "Failed to close netlink container: %m");
161 r
= sd_netlink_message_close_container(m
);
163 return log_error_errno(r
, "Failed to close netlink container: %m");
165 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
167 return log_error_errno(r
, "Failed to add new veth interfaces (%s:%s): %m", ifname_host
, ifname_container
);
172 int setup_veth(const char *machine_name
,
174 char iface_name
[IFNAMSIZ
],
177 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
178 struct ether_addr mac_host
, mac_container
;
181 assert(machine_name
);
185 /* Use two different interface name prefixes depending whether
186 * we are in bridge mode or not. */
187 snprintf(iface_name
, IFNAMSIZ
- 1, "%s-%s",
188 bridge
? "vb" : "ve", machine_name
);
190 r
= generate_mac(machine_name
, &mac_container
, CONTAINER_HASH_KEY
, 0);
192 return log_error_errno(r
, "Failed to generate predictable MAC address for container side: %m");
194 r
= generate_mac(machine_name
, &mac_host
, HOST_HASH_KEY
, 0);
196 return log_error_errno(r
, "Failed to generate predictable MAC address for host side: %m");
198 r
= sd_netlink_open(&rtnl
);
200 return log_error_errno(r
, "Failed to connect to netlink: %m");
202 r
= add_veth(rtnl
, pid
, iface_name
, &mac_host
, "host0", &mac_container
);
206 r
= parse_ifindex_or_ifname(iface_name
, &i
);
208 return log_error_errno(r
, "Failed to resolve interface %s: %m", iface_name
);
213 int setup_veth_extra(
214 const char *machine_name
,
218 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
223 assert(machine_name
);
226 if (strv_isempty(pairs
))
229 r
= sd_netlink_open(&rtnl
);
231 return log_error_errno(r
, "Failed to connect to netlink: %m");
233 STRV_FOREACH_PAIR(a
, b
, pairs
) {
234 struct ether_addr mac_host
, mac_container
;
236 r
= generate_mac(machine_name
, &mac_container
, VETH_EXTRA_CONTAINER_HASH_KEY
, idx
);
238 return log_error_errno(r
, "Failed to generate predictable MAC address for container side of extra veth link: %m");
240 r
= generate_mac(machine_name
, &mac_host
, VETH_EXTRA_HOST_HASH_KEY
, idx
);
242 return log_error_errno(r
, "Failed to generate predictable MAC address for container side of extra veth link: %m");
244 r
= add_veth(rtnl
, pid
, *a
, &mac_host
, *b
, &mac_container
);
254 static int join_bridge(sd_netlink
*rtnl
, const char *veth_name
, const char *bridge_name
) {
255 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
262 r
= parse_ifindex_or_ifname(bridge_name
, &bridge_ifi
);
266 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_SETLINK
, 0);
270 r
= sd_rtnl_message_link_set_flags(m
, IFF_UP
, IFF_UP
);
274 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, veth_name
);
278 r
= sd_netlink_message_append_u32(m
, IFLA_MASTER
, bridge_ifi
);
282 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
289 static int create_bridge(sd_netlink
*rtnl
, const char *bridge_name
) {
290 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
293 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_NEWLINK
, 0);
297 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, bridge_name
);
301 r
= sd_netlink_message_open_container(m
, IFLA_LINKINFO
);
305 r
= sd_netlink_message_open_container_union(m
, IFLA_INFO_DATA
, "bridge");
309 r
= sd_netlink_message_close_container(m
);
313 r
= sd_netlink_message_close_container(m
);
317 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
324 int setup_bridge(const char *veth_name
, const char *bridge_name
, bool create
) {
325 _cleanup_(release_lock_file
) LockFile bridge_lock
= LOCK_FILE_INIT
;
326 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
333 r
= sd_netlink_open(&rtnl
);
335 return log_error_errno(r
, "Failed to connect to netlink: %m");
338 /* We take a system-wide lock here, so that we can safely check whether there's still a member in the
339 * bridge before removing it, without risking interference from other nspawn instances. */
341 r
= make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX
, &bridge_lock
);
343 return log_error_errno(r
, "Failed to take network zone lock: %m");
347 bridge_ifi
= join_bridge(rtnl
, veth_name
, bridge_name
);
350 if (bridge_ifi
!= -ENODEV
|| !create
|| n
> 10)
351 return log_error_errno(bridge_ifi
, "Failed to add interface %s to bridge %s: %m", veth_name
, bridge_name
);
353 /* Count attempts, so that we don't enter an endless loop here. */
356 /* The bridge doesn't exist yet. Let's create it */
357 r
= create_bridge(rtnl
, bridge_name
);
359 return log_error_errno(r
, "Failed to create bridge interface %s: %m", bridge_name
);
361 /* Try again, now that the bridge exists */
365 int remove_bridge(const char *bridge_name
) {
366 _cleanup_(release_lock_file
) LockFile bridge_lock
= LOCK_FILE_INIT
;
367 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
371 /* Removes the specified bridge, but only if it is currently empty */
373 if (isempty(bridge_name
))
376 r
= make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX
, &bridge_lock
);
378 return log_error_errno(r
, "Failed to take network zone lock: %m");
380 path
= strjoina("/sys/class/net/", bridge_name
, "/brif");
382 r
= dir_is_empty(path
);
383 if (r
== -ENOENT
) /* Already gone? */
386 return log_error_errno(r
, "Can't detect if bridge %s is empty: %m", bridge_name
);
387 if (r
== 0) /* Still populated, leave it around */
390 r
= sd_netlink_open(&rtnl
);
392 return log_error_errno(r
, "Failed to connect to netlink: %m");
394 return remove_one_link(rtnl
, bridge_name
);
397 static int parse_interface(const char *name
) {
398 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
401 r
= parse_ifindex_or_ifname(name
, &ifi
);
403 return log_error_errno(r
, "Failed to resolve interface %s: %m", name
);
405 if (path_is_read_only_fs("/sys") <= 0) {
406 char ifi_str
[2 + DECIMAL_STR_MAX(int)];
408 /* udev should be around. */
410 sprintf(ifi_str
, "n%i", ifi
);
411 r
= sd_device_new_from_device_id(&d
, ifi_str
);
413 return log_error_errno(r
, "Failed to get device %s: %m", name
);
415 r
= sd_device_get_is_initialized(d
);
417 return log_error_errno(r
, "Failed to determine whether interface %s is initialized: %m", name
);
419 return log_error_errno(SYNTHETIC_ERRNO(EBUSY
), "Network interface %s is not initialized yet.", name
);
421 r
= device_is_renaming(d
);
423 return log_error_errno(r
, "Failed to determine the interface %s is being renamed: %m", name
);
425 return log_error_errno(SYNTHETIC_ERRNO(EBUSY
), "Interface %s is being renamed.", name
);
431 int move_network_interfaces(pid_t pid
, char **ifaces
) {
432 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
436 if (strv_isempty(ifaces
))
439 r
= sd_netlink_open(&rtnl
);
441 return log_error_errno(r
, "Failed to connect to netlink: %m");
443 STRV_FOREACH(i
, ifaces
) {
444 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
447 ifi
= parse_interface(*i
);
451 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_SETLINK
, ifi
);
453 return log_error_errno(r
, "Failed to allocate netlink message: %m");
455 r
= sd_netlink_message_append_u32(m
, IFLA_NET_NS_PID
, pid
);
457 return log_error_errno(r
, "Failed to append namespace PID to netlink message: %m");
459 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
461 return log_error_errno(r
, "Failed to move interface %s to namespace: %m", *i
);
467 int setup_macvlan(const char *machine_name
, pid_t pid
, char **ifaces
) {
468 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
473 if (strv_isempty(ifaces
))
476 r
= sd_netlink_open(&rtnl
);
478 return log_error_errno(r
, "Failed to connect to netlink: %m");
480 STRV_FOREACH(i
, ifaces
) {
481 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
482 _cleanup_free_
char *n
= NULL
;
483 struct ether_addr mac
;
486 ifi
= parse_interface(*i
);
490 r
= generate_mac(machine_name
, &mac
, MACVLAN_HASH_KEY
, idx
++);
492 return log_error_errno(r
, "Failed to create MACVLAN MAC address: %m");
494 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_NEWLINK
, 0);
496 return log_error_errno(r
, "Failed to allocate netlink message: %m");
498 r
= sd_netlink_message_append_u32(m
, IFLA_LINK
, ifi
);
500 return log_error_errno(r
, "Failed to add netlink interface index: %m");
502 n
= strjoin("mv-", *i
);
506 strshorten(n
, IFNAMSIZ
-1);
508 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, n
);
510 return log_error_errno(r
, "Failed to add netlink interface name: %m");
512 r
= sd_netlink_message_append_ether_addr(m
, IFLA_ADDRESS
, &mac
);
514 return log_error_errno(r
, "Failed to add netlink MAC address: %m");
516 r
= sd_netlink_message_append_u32(m
, IFLA_NET_NS_PID
, pid
);
518 return log_error_errno(r
, "Failed to add netlink namespace field: %m");
520 r
= sd_netlink_message_open_container(m
, IFLA_LINKINFO
);
522 return log_error_errno(r
, "Failed to open netlink container: %m");
524 r
= sd_netlink_message_open_container_union(m
, IFLA_INFO_DATA
, "macvlan");
526 return log_error_errno(r
, "Failed to open netlink container: %m");
528 r
= sd_netlink_message_append_u32(m
, IFLA_MACVLAN_MODE
, MACVLAN_MODE_BRIDGE
);
530 return log_error_errno(r
, "Failed to append macvlan mode: %m");
532 r
= sd_netlink_message_close_container(m
);
534 return log_error_errno(r
, "Failed to close netlink container: %m");
536 r
= sd_netlink_message_close_container(m
);
538 return log_error_errno(r
, "Failed to close netlink container: %m");
540 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
542 return log_error_errno(r
, "Failed to add new macvlan interfaces: %m");
548 int setup_ipvlan(const char *machine_name
, pid_t pid
, char **ifaces
) {
549 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
553 if (strv_isempty(ifaces
))
556 r
= sd_netlink_open(&rtnl
);
558 return log_error_errno(r
, "Failed to connect to netlink: %m");
560 STRV_FOREACH(i
, ifaces
) {
561 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
562 _cleanup_free_
char *n
= NULL
;
565 ifi
= parse_interface(*i
);
569 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_NEWLINK
, 0);
571 return log_error_errno(r
, "Failed to allocate netlink message: %m");
573 r
= sd_netlink_message_append_u32(m
, IFLA_LINK
, ifi
);
575 return log_error_errno(r
, "Failed to add netlink interface index: %m");
577 n
= strjoin("iv-", *i
);
581 strshorten(n
, IFNAMSIZ
-1);
583 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, n
);
585 return log_error_errno(r
, "Failed to add netlink interface name: %m");
587 r
= sd_netlink_message_append_u32(m
, IFLA_NET_NS_PID
, pid
);
589 return log_error_errno(r
, "Failed to add netlink namespace field: %m");
591 r
= sd_netlink_message_open_container(m
, IFLA_LINKINFO
);
593 return log_error_errno(r
, "Failed to open netlink container: %m");
595 r
= sd_netlink_message_open_container_union(m
, IFLA_INFO_DATA
, "ipvlan");
597 return log_error_errno(r
, "Failed to open netlink container: %m");
599 r
= sd_netlink_message_append_u16(m
, IFLA_IPVLAN_MODE
, IPVLAN_MODE_L2
);
601 return log_error_errno(r
, "Failed to add ipvlan mode: %m");
603 r
= sd_netlink_message_close_container(m
);
605 return log_error_errno(r
, "Failed to close netlink container: %m");
607 r
= sd_netlink_message_close_container(m
);
609 return log_error_errno(r
, "Failed to close netlink container: %m");
611 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
613 return log_error_errno(r
, "Failed to add new ipvlan interfaces: %m");
619 int veth_extra_parse(char ***l
, const char *p
) {
620 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
623 r
= extract_first_word(&p
, &a
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
626 if (r
== 0 || !ifname_valid(a
))
629 r
= extract_first_word(&p
, &b
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
632 if (r
== 0 || !ifname_valid(b
)) {
642 r
= strv_push_pair(l
, a
, b
);
650 int remove_veth_links(const char *primary
, char **pairs
) {
651 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
655 /* In some cases the kernel might pin the veth links between host and container even after the namespace
656 * died. Hence, let's better remove them explicitly too. */
658 if (isempty(primary
) && strv_isempty(pairs
))
661 r
= sd_netlink_open(&rtnl
);
663 return log_error_errno(r
, "Failed to connect to netlink: %m");
665 remove_one_link(rtnl
, primary
);
667 STRV_FOREACH_PAIR(a
, b
, pairs
)
668 remove_one_link(rtnl
, *a
);