1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2015 Lennart Poettering
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/>.
22 #include <linux/veth.h>
27 #include "sd-netlink.h"
29 #include "alloc-util.h"
30 #include "ether-addr-util.h"
31 #include "netlink-util.h"
32 #include "nspawn-network.h"
33 #include "siphash24.h"
34 #include "string-util.h"
35 #include "udev-util.h"
38 #define HOST_HASH_KEY SD_ID128_MAKE(1a,37,6f,c7,46,ec,45,0b,ad,a3,d5,31,06,60,5d,b1)
39 #define CONTAINER_HASH_KEY SD_ID128_MAKE(c3,c4,f9,19,b5,57,b2,1c,e6,cf,14,27,03,9c,ee,a2)
40 #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)
41 #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)
42 #define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f)
44 static int generate_mac(
45 const char *machine_name
,
46 struct ether_addr
*mac
,
55 l
= strlen(machine_name
);
56 sz
= sizeof(sd_id128_t
) + l
;
62 /* fetch some persistent data unique to the host */
63 r
= sd_id128_get_machine((sd_id128_t
*) v
);
67 /* combine with some data unique (on this host) to this
68 * container instance */
69 i
= mempcpy(v
+ sizeof(sd_id128_t
), machine_name
, l
);
72 memcpy(i
, &idx
, sizeof(idx
));
75 /* Let's hash the host machine ID plus the container name. We
76 * use a fixed, but originally randomly created hash key here. */
77 result
= htole64(siphash24(v
, sz
, hash_key
.bytes
));
79 assert_cc(ETH_ALEN
<= sizeof(result
));
80 memcpy(mac
->ether_addr_octet
, &result
, ETH_ALEN
);
82 /* see eth_random_addr in the kernel */
83 mac
->ether_addr_octet
[0] &= 0xfe; /* clear multicast bit */
84 mac
->ether_addr_octet
[0] |= 0x02; /* set local assignment bit (IEEE802) */
92 const char *ifname_host
,
93 const struct ether_addr
*mac_host
,
94 const char *ifname_container
,
95 const struct ether_addr
*mac_container
) {
97 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
103 assert(ifname_container
);
104 assert(mac_container
);
106 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_NEWLINK
, 0);
108 return log_error_errno(r
, "Failed to allocate netlink message: %m");
110 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, ifname_host
);
112 return log_error_errno(r
, "Failed to add netlink interface name: %m");
114 r
= sd_netlink_message_append_ether_addr(m
, IFLA_ADDRESS
, mac_host
);
116 return log_error_errno(r
, "Failed to add netlink MAC address: %m");
118 r
= sd_netlink_message_open_container(m
, IFLA_LINKINFO
);
120 return log_error_errno(r
, "Failed to open netlink container: %m");
122 r
= sd_netlink_message_open_container_union(m
, IFLA_INFO_DATA
, "veth");
124 return log_error_errno(r
, "Failed to open netlink container: %m");
126 r
= sd_netlink_message_open_container(m
, VETH_INFO_PEER
);
128 return log_error_errno(r
, "Failed to open netlink container: %m");
130 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, ifname_container
);
132 return log_error_errno(r
, "Failed to add netlink interface name: %m");
134 r
= sd_netlink_message_append_ether_addr(m
, IFLA_ADDRESS
, mac_container
);
136 return log_error_errno(r
, "Failed to add netlink MAC address: %m");
138 r
= sd_netlink_message_append_u32(m
, IFLA_NET_NS_PID
, pid
);
140 return log_error_errno(r
, "Failed to add netlink namespace field: %m");
142 r
= sd_netlink_message_close_container(m
);
144 return log_error_errno(r
, "Failed to close netlink container: %m");
146 r
= sd_netlink_message_close_container(m
);
148 return log_error_errno(r
, "Failed to close netlink container: %m");
150 r
= sd_netlink_message_close_container(m
);
152 return log_error_errno(r
, "Failed to close netlink container: %m");
154 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
156 return log_error_errno(r
, "Failed to add new veth interfaces (%s:%s): %m", ifname_host
, ifname_container
);
161 int setup_veth(const char *machine_name
,
163 char iface_name
[IFNAMSIZ
],
166 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
167 struct ether_addr mac_host
, mac_container
;
170 assert(machine_name
);
174 /* Use two different interface name prefixes depending whether
175 * we are in bridge mode or not. */
176 snprintf(iface_name
, IFNAMSIZ
- 1, "%s-%s",
177 bridge
? "vb" : "ve", machine_name
);
179 r
= generate_mac(machine_name
, &mac_container
, CONTAINER_HASH_KEY
, 0);
181 return log_error_errno(r
, "Failed to generate predictable MAC address for container side: %m");
183 r
= generate_mac(machine_name
, &mac_host
, HOST_HASH_KEY
, 0);
185 return log_error_errno(r
, "Failed to generate predictable MAC address for host side: %m");
187 r
= sd_netlink_open(&rtnl
);
189 return log_error_errno(r
, "Failed to connect to netlink: %m");
191 r
= add_veth(rtnl
, pid
, iface_name
, &mac_host
, "host0", &mac_container
);
195 i
= (int) if_nametoindex(iface_name
);
197 return log_error_errno(errno
, "Failed to resolve interface %s: %m", iface_name
);
202 int setup_veth_extra(
203 const char *machine_name
,
207 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
212 assert(machine_name
);
215 if (strv_isempty(pairs
))
218 r
= sd_netlink_open(&rtnl
);
220 return log_error_errno(r
, "Failed to connect to netlink: %m");
222 STRV_FOREACH_PAIR(a
, b
, pairs
) {
223 struct ether_addr mac_host
, mac_container
;
225 r
= generate_mac(machine_name
, &mac_container
, VETH_EXTRA_CONTAINER_HASH_KEY
, idx
);
227 return log_error_errno(r
, "Failed to generate predictable MAC address for container side of extra veth link: %m");
229 r
= generate_mac(machine_name
, &mac_host
, VETH_EXTRA_HOST_HASH_KEY
, idx
);
231 return log_error_errno(r
, "Failed to generate predictable MAC address for container side of extra veth link: %m");
233 r
= add_veth(rtnl
, pid
, *a
, &mac_host
, *b
, &mac_container
);
243 int setup_bridge(const char *veth_name
, const char *bridge_name
) {
244 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
245 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
251 bridge_ifi
= (int) if_nametoindex(bridge_name
);
253 return log_error_errno(errno
, "Failed to resolve interface %s: %m", bridge_name
);
255 r
= sd_netlink_open(&rtnl
);
257 return log_error_errno(r
, "Failed to connect to netlink: %m");
259 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_SETLINK
, 0);
261 return log_error_errno(r
, "Failed to allocate netlink message: %m");
263 r
= sd_rtnl_message_link_set_flags(m
, IFF_UP
, IFF_UP
);
265 return log_error_errno(r
, "Failed to set IFF_UP flag: %m");
267 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, veth_name
);
269 return log_error_errno(r
, "Failed to add netlink interface name field: %m");
271 r
= sd_netlink_message_append_u32(m
, IFLA_MASTER
, bridge_ifi
);
273 return log_error_errno(r
, "Failed to add netlink master field: %m");
275 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
277 return log_error_errno(r
, "Failed to add veth interface to bridge: %m");
282 static int parse_interface(struct udev
*udev
, const char *name
) {
283 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
284 char ifi_str
[2 + DECIMAL_STR_MAX(int)];
287 ifi
= (int) if_nametoindex(name
);
289 return log_error_errno(errno
, "Failed to resolve interface %s: %m", name
);
291 sprintf(ifi_str
, "n%i", ifi
);
292 d
= udev_device_new_from_device_id(udev
, ifi_str
);
294 return log_error_errno(errno
, "Failed to get udev device for interface %s: %m", name
);
296 if (udev_device_get_is_initialized(d
) <= 0) {
297 log_error("Network interface %s is not initialized yet.", name
);
304 int move_network_interfaces(pid_t pid
, char **ifaces
) {
305 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
306 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
310 if (strv_isempty(ifaces
))
313 r
= sd_netlink_open(&rtnl
);
315 return log_error_errno(r
, "Failed to connect to netlink: %m");
319 log_error("Failed to connect to udev.");
323 STRV_FOREACH(i
, ifaces
) {
324 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
327 ifi
= parse_interface(udev
, *i
);
331 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_SETLINK
, ifi
);
333 return log_error_errno(r
, "Failed to allocate netlink message: %m");
335 r
= sd_netlink_message_append_u32(m
, IFLA_NET_NS_PID
, pid
);
337 return log_error_errno(r
, "Failed to append namespace PID to netlink message: %m");
339 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
341 return log_error_errno(r
, "Failed to move interface %s to namespace: %m", *i
);
347 int setup_macvlan(const char *machine_name
, pid_t pid
, char **ifaces
) {
348 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
349 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
354 if (strv_isempty(ifaces
))
357 r
= sd_netlink_open(&rtnl
);
359 return log_error_errno(r
, "Failed to connect to netlink: %m");
363 log_error("Failed to connect to udev.");
367 STRV_FOREACH(i
, ifaces
) {
368 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
369 _cleanup_free_
char *n
= NULL
;
370 struct ether_addr mac
;
373 ifi
= parse_interface(udev
, *i
);
377 r
= generate_mac(machine_name
, &mac
, MACVLAN_HASH_KEY
, idx
++);
379 return log_error_errno(r
, "Failed to create MACVLAN MAC address: %m");
381 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_NEWLINK
, 0);
383 return log_error_errno(r
, "Failed to allocate netlink message: %m");
385 r
= sd_netlink_message_append_u32(m
, IFLA_LINK
, ifi
);
387 return log_error_errno(r
, "Failed to add netlink interface index: %m");
389 n
= strappend("mv-", *i
);
393 strshorten(n
, IFNAMSIZ
-1);
395 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, n
);
397 return log_error_errno(r
, "Failed to add netlink interface name: %m");
399 r
= sd_netlink_message_append_ether_addr(m
, IFLA_ADDRESS
, &mac
);
401 return log_error_errno(r
, "Failed to add netlink MAC address: %m");
403 r
= sd_netlink_message_append_u32(m
, IFLA_NET_NS_PID
, pid
);
405 return log_error_errno(r
, "Failed to add netlink namespace field: %m");
407 r
= sd_netlink_message_open_container(m
, IFLA_LINKINFO
);
409 return log_error_errno(r
, "Failed to open netlink container: %m");
411 r
= sd_netlink_message_open_container_union(m
, IFLA_INFO_DATA
, "macvlan");
413 return log_error_errno(r
, "Failed to open netlink container: %m");
415 r
= sd_netlink_message_append_u32(m
, IFLA_MACVLAN_MODE
, MACVLAN_MODE_BRIDGE
);
417 return log_error_errno(r
, "Failed to append macvlan mode: %m");
419 r
= sd_netlink_message_close_container(m
);
421 return log_error_errno(r
, "Failed to close netlink container: %m");
423 r
= sd_netlink_message_close_container(m
);
425 return log_error_errno(r
, "Failed to close netlink container: %m");
427 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
429 return log_error_errno(r
, "Failed to add new macvlan interfaces: %m");
435 int setup_ipvlan(const char *machine_name
, pid_t pid
, char **ifaces
) {
436 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
437 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
441 if (strv_isempty(ifaces
))
444 r
= sd_netlink_open(&rtnl
);
446 return log_error_errno(r
, "Failed to connect to netlink: %m");
450 log_error("Failed to connect to udev.");
454 STRV_FOREACH(i
, ifaces
) {
455 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
456 _cleanup_free_
char *n
= NULL
;
459 ifi
= parse_interface(udev
, *i
);
463 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_NEWLINK
, 0);
465 return log_error_errno(r
, "Failed to allocate netlink message: %m");
467 r
= sd_netlink_message_append_u32(m
, IFLA_LINK
, ifi
);
469 return log_error_errno(r
, "Failed to add netlink interface index: %m");
471 n
= strappend("iv-", *i
);
475 strshorten(n
, IFNAMSIZ
-1);
477 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, n
);
479 return log_error_errno(r
, "Failed to add netlink interface name: %m");
481 r
= sd_netlink_message_append_u32(m
, IFLA_NET_NS_PID
, pid
);
483 return log_error_errno(r
, "Failed to add netlink namespace field: %m");
485 r
= sd_netlink_message_open_container(m
, IFLA_LINKINFO
);
487 return log_error_errno(r
, "Failed to open netlink container: %m");
489 r
= sd_netlink_message_open_container_union(m
, IFLA_INFO_DATA
, "ipvlan");
491 return log_error_errno(r
, "Failed to open netlink container: %m");
493 r
= sd_netlink_message_append_u16(m
, IFLA_IPVLAN_MODE
, IPVLAN_MODE_L2
);
495 return log_error_errno(r
, "Failed to add ipvlan mode: %m");
497 r
= sd_netlink_message_close_container(m
);
499 return log_error_errno(r
, "Failed to close netlink container: %m");
501 r
= sd_netlink_message_close_container(m
);
503 return log_error_errno(r
, "Failed to close netlink container: %m");
505 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
507 return log_error_errno(r
, "Failed to add new ipvlan interfaces: %m");
513 int veth_extra_parse(char ***l
, const char *p
) {
514 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
517 r
= extract_first_word(&p
, &a
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
520 if (r
== 0 || isempty(a
))
523 r
= extract_first_word(&p
, &b
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
526 if (r
== 0 || isempty(b
)) {
536 r
= strv_push_pair(l
, a
, b
);