chiark / gitweb /
nspawn: make host0's MAC address persistent
authorTom Gundersen <teg@jklm.no>
Thu, 13 Mar 2014 16:47:30 +0000 (17:47 +0100)
committerTom Gundersen <teg@jklm.no>
Thu, 13 Mar 2014 16:47:33 +0000 (17:47 +0100)
We still need to make sure that no two MAC addresses are the same, so we use
a logic similar to what is used in udev to generate MAC addresses, and base
it on a hash of the host's machine ID and thecontainer's name.

src/nspawn/nspawn.c

index 084929dcdedaf0d94ececaba460bf18d6d420b23..b637b51f61b8739575ec4c35239644cb793cbb2e 100644 (file)
@@ -86,6 +86,7 @@
 #include "udev-util.h"
 #include "blkid-util.h"
 #include "gpt.h"
+#include "siphash24.h"
 
 #ifdef HAVE_SECCOMP
 #include "seccomp-util.h"
@@ -1399,9 +1400,46 @@ static int reset_audit_loginuid(void) {
         return 0;
 }
 
+#define HASH_KEY SD_ID128_MAKE(c3,c4,f9,19,b5,57,b2,1c,e6,cf,14,27,03,9c,ee,a2)
+
+static int get_mac(struct ether_addr *mac) {
+        int r;
+
+        uint8_t result[8];
+        size_t l, sz;
+        uint8_t *v;
+
+        l = strlen(arg_machine);
+        sz = sizeof(sd_id128_t) + l;
+        v = alloca(sz);
+
+        /* fetch some persistent data unique to the host */
+        r = sd_id128_get_machine((sd_id128_t*) v);
+        if (r < 0)
+                return r;
+
+        /* combine with some data unique (on this host) to this
+         * container instance */
+        memcpy(v + sizeof(sd_id128_t), arg_machine, l);
+
+        /* Let's hash the host machine ID plus the container name. We
+         * use a fixed, but originally randomly created hash key here. */
+        siphash24(result, v, sz, HASH_KEY.bytes);
+
+        assert_cc(ETH_ALEN <= sizeof(result));
+        memcpy(mac->ether_addr_octet, result, ETH_ALEN);
+
+        /* see eth_random_addr in the kernel */
+        mac->ether_addr_octet[0] &= 0xfe;        /* clear multicast bit */
+        mac->ether_addr_octet[0] |= 0x02;        /* set local assignment bit (IEEE802) */
+
+        return 0;
+}
+
 static int setup_veth(pid_t pid, char iface_name[IFNAMSIZ]) {
         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        struct ether_addr mac;
         int r;
 
         if (!arg_private_network)
@@ -1416,9 +1454,14 @@ static int setup_veth(pid_t pid, char iface_name[IFNAMSIZ]) {
                 memcpy(iface_name, "vb-", 3);
         else
                 memcpy(iface_name, "ve-", 3);
-
         strncpy(iface_name+3, arg_machine, IFNAMSIZ - 3);
 
+        r = get_mac(&mac);
+        if (r < 0) {
+                log_error("Failed to generate predictable MAC address for host0");
+                return r;
+        }
+
         r = sd_rtnl_open(&rtnl, 0);
         if (r < 0) {
                 log_error("Failed to connect to netlink: %s", strerror(-r));
@@ -1467,6 +1510,12 @@ static int setup_veth(pid_t pid, char iface_name[IFNAMSIZ]) {
                 return r;
         }
 
+        r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, &mac);
+        if (r < 0) {
+                log_error("Failed to add netlink MAC address: %s", strerror(-r));
+                return r;
+        }
+
         r = sd_rtnl_message_append_u32(m, IFLA_NET_NS_PID, pid);
         if (r < 0) {
                 log_error("Failed to add netlink namespace field: %s", strerror(-r));