14a41f02433890d19b2f871156271e3388cd0845Jens Elkner This file is part of systemd.
9ec7787531611654e8f50932473aa48963eaba55Trond Norbye Copyright 2015 Lennart Poettering
9ec7787531611654e8f50932473aa48963eaba55Trond Norbye systemd is free software; you can redistribute it and/or modify it
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen under the terms of the GNU Lesser General Public License as published by
9ec7787531611654e8f50932473aa48963eaba55Trond Norbye the Free Software Foundation; either version 2.1 of the License, or
9ec7787531611654e8f50932473aa48963eaba55Trond Norbye (at your option) any later version.
9ec7787531611654e8f50932473aa48963eaba55Trond Norbye systemd is distributed in the hope that it will be useful, but
9ec7787531611654e8f50932473aa48963eaba55Trond Norbye WITHOUT ANY WARRANTY; without even the implied warranty of
9ec7787531611654e8f50932473aa48963eaba55Trond Norbye MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9ec7787531611654e8f50932473aa48963eaba55Trond Norbye Lesser General Public License for more details.
9ec7787531611654e8f50932473aa48963eaba55Trond Norbye You should have received a copy of the GNU Lesser General Public License
9ec7787531611654e8f50932473aa48963eaba55Trond Norbye along with systemd; If not, see <http://www.gnu.org/licenses/>.
be72dc8ed6dfce2445cea09638f601a08b9175e2Trond Norbye#define HOST_HASH_KEY SD_ID128_MAKE(1a,37,6f,c7,46,ec,45,0b,ad,a3,d5,31,06,60,5d,b1)
14a41f02433890d19b2f871156271e3388cd0845Jens Elkner#define CONTAINER_HASH_KEY SD_ID128_MAKE(c3,c4,f9,19,b5,57,b2,1c,e6,cf,14,27,03,9c,ee,a2)
14a41f02433890d19b2f871156271e3388cd0845Jens Elkner#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)
14a41f02433890d19b2f871156271e3388cd0845Jens Elkner#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)
14a41f02433890d19b2f871156271e3388cd0845Jens Elkner#define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f)
cd9fbd3b531043a6a754f7013f542087727b9321Kryštof Tulinger /* fetch some persistent data unique to the host */
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen /* combine with some data unique (on this host) to this
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen * container instance */
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen i = mempcpy(v + sizeof(sd_id128_t), machine_name, l);
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen /* Let's hash the host machine ID plus the container name. We
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen * use a fixed, but originally randomly created hash key here. */
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen result = htole64(siphash24(v, sz, hash_key.bytes));
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen /* see eth_random_addr in the kernel */
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
981e542f40f5acaf95b69c5854e5ffb080204242Lubos Kosco mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
99b4056e2c5b0a51f7f480ebcefb1f917613ce2aLubos Kosco _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
8d5daad4d9da04018b562f0dd12044f5f53c1a66Kryštof Tulinger return log_error_errno(r, "Failed to allocate netlink message: %m");
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_host);
9a4361e23046cda58b9a5b8f4e11910dc433badaLubos Kosco return log_error_errno(r, "Failed to add netlink interface name: %m");
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_host);
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen return log_error_errno(r, "Failed to add netlink MAC address: %m");
8d5daad4d9da04018b562f0dd12044f5f53c1a66Kryštof Tulinger r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen return log_error_errno(r, "Failed to open netlink container: %m");
0660813d1476ce33b006694581155bf28067687bSven-Kristofer Pilz r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "veth");
73189ea86c6fb0af01e16eaa5b0da3f2bb775c41Harry Pan return log_error_errno(r, "Failed to open netlink container: %m");
0660813d1476ce33b006694581155bf28067687bSven-Kristofer Pilz r = sd_netlink_message_open_container(m, VETH_INFO_PEER);
0660813d1476ce33b006694581155bf28067687bSven-Kristofer Pilz return log_error_errno(r, "Failed to open netlink container: %m");
0660813d1476ce33b006694581155bf28067687bSven-Kristofer Pilz r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_container);
0660813d1476ce33b006694581155bf28067687bSven-Kristofer Pilz return log_error_errno(r, "Failed to add netlink interface name: %m");
0660813d1476ce33b006694581155bf28067687bSven-Kristofer Pilz r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_container);
0660813d1476ce33b006694581155bf28067687bSven-Kristofer Pilz return log_error_errno(r, "Failed to add netlink MAC address: %m");
0660813d1476ce33b006694581155bf28067687bSven-Kristofer Pilz r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
14a41f02433890d19b2f871156271e3388cd0845Jens Elkner return log_error_errno(r, "Failed to add netlink namespace field: %m");
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen r = sd_netlink_message_close_container(m);
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen return log_error_errno(r, "Failed to close netlink container: %m");
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen r = sd_netlink_message_close_container(m);
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen return log_error_errno(r, "Failed to close netlink container: %m");
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen r = sd_netlink_message_close_container(m);
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen return log_error_errno(r, "Failed to close netlink container: %m");
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen return log_error_errno(r, "Failed to add new veth interfaces (%s:%s): %m", ifname_host, ifname_container);
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen struct ether_addr mac_host, mac_container;
117599e68158f1cdc904c452d5948136744e3e4dKryštof Tulinger /* Use two different interface name prefixes depending whether
117599e68158f1cdc904c452d5948136744e3e4dKryštof Tulinger * we are in bridge mode or not. */
117599e68158f1cdc904c452d5948136744e3e4dKryštof Tulinger snprintf(iface_name, IFNAMSIZ - 1, "%s-%s",
14a41f02433890d19b2f871156271e3388cd0845Jens Elkner r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0);
14a41f02433890d19b2f871156271e3388cd0845Jens Elkner return log_error_errno(r, "Failed to generate predictable MAC address for container side: %m");
3df9409a61b23dd736d9ce7bea6e4256bc449ff2Kryštof Tulinger r = generate_mac(machine_name, &mac_host, HOST_HASH_KEY, 0);
59b6a8c0cc6ef741a7180504b3c371e67c2aa338Knut Anders Hatlen return log_error_errno(r, "Failed to generate predictable MAC address for host side: %m");
3df9409a61b23dd736d9ce7bea6e4256bc449ff2Kryštof Tulinger return log_error_errno(r, "Failed to connect to netlink: %m");
3df9409a61b23dd736d9ce7bea6e4256bc449ff2Kryštof Tulinger r = add_veth(rtnl, pid, iface_name, &mac_host, "host0", &mac_container);
d470e59c0405a31b7e5f194bd9b705e91b12bf0aKryštof Tulinger return log_error_errno(errno, "Failed to resolve interface %s: %m", iface_name);
d8d744ec4741226cba1ed387037d5f8dafc3d813Kryštof Tulinger _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
d8d744ec4741226cba1ed387037d5f8dafc3d813Kryštof Tulinger char **a, **b;
d470e59c0405a31b7e5f194bd9b705e91b12bf0aKryštof Tulinger return log_error_errno(r, "Failed to connect to netlink: %m");
d8d744ec4741226cba1ed387037d5f8dafc3d813Kryštof Tulinger r = generate_mac(machine_name, &mac_container, VETH_EXTRA_CONTAINER_HASH_KEY, idx);
d8d744ec4741226cba1ed387037d5f8dafc3d813Kryštof Tulinger return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m");
d470e59c0405a31b7e5f194bd9b705e91b12bf0aKryštof Tulinger r = generate_mac(machine_name, &mac_host, VETH_EXTRA_HOST_HASH_KEY, idx);
d8d744ec4741226cba1ed387037d5f8dafc3d813Kryštof Tulinger return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m");
d470e59c0405a31b7e5f194bd9b705e91b12bf0aKryštof Tulinger r = add_veth(rtnl, pid, *a, &mac_host, *b, &mac_container);
14a41f02433890d19b2f871156271e3388cd0845Jens Elknerint setup_bridge(const char *veth_name, const char *bridge_name) {
117599e68158f1cdc904c452d5948136744e3e4dKryštof Tulinger _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
14a41f02433890d19b2f871156271e3388cd0845Jens Elkner _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
if (bridge_ifi <= 0)
return bridge_ifi;
if (ifi <= 0)
if (udev_device_get_is_initialized(d) <= 0) {
return -EBUSY;
return ifi;
if (!udev) {
return -ENOMEM;
if (ifi < 0)
return ifi;
if (!udev) {
return -ENOMEM;
if (ifi < 0)
return ifi;
return log_oom();
if (!udev) {
return -ENOMEM;
if (ifi < 0)
return ifi;
return log_oom();
if (r == 0 || isempty(a))
return -EINVAL;
if (r == 0 || isempty(b)) {
free(b);
b = strdup(a);
return -ENOMEM;
return -EINVAL;
r = strv_push_pair(l, a, b);
return -ENOMEM;
a = b = NULL;