All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] libxl: made vm mac address assignment deterministic
@ 2018-09-05 12:25 Joshua Perrett
  2018-09-06 15:51 ` Wei Liu
  0 siblings, 1 reply; 9+ messages in thread
From: Joshua Perrett @ 2018-09-05 12:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Ian Jackson, George Dunlap, Joshua Perrett

Uses MD5 on the host mac address, vm name and vif index to generate the
last three bytes of the vm mac address (for each vm).

It uses the vif index to account for multiple vifs.

MD5 code is originally from the public domain (written by Colin Plumb in
1993), files found in xen/tools/blktap2/drivers/.

Reported-by: George Dunlap <george.dunlap@citrix.com>
Signed-off-by: Joshua Perrett <jperrett256@gmail.com>
---
 tools/libxl/Makefile    |   2 +-
 tools/libxl/libxl_nic.c |  68 +++++++++++--
 tools/libxl/md5.c       | 266 ++++++++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/md5.h       |  26 +++++
 4 files changed, 355 insertions(+), 7 deletions(-)
 create mode 100644 tools/libxl/md5.c
 create mode 100644 tools/libxl/md5.h

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 6da342ed61..6e7db11367 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -142,7 +142,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
 			libxl_9pfs.o libxl_domain.o libxl_vdispl.o \
 			libxl_pvcalls.o libxl_vsnd.o libxl_vkb.o $(LIBXL_OBJS-y)
 LIBXL_OBJS += libxl_genid.o
-LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
+LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o md5.o
 
 LIBXL_TESTS += timedereg
 LIBXL_TESTS_PROGS = $(LIBXL_TESTS) fdderegrace
diff --git a/tools/libxl/libxl_nic.c b/tools/libxl/libxl_nic.c
index 01b711b84e..8907df8187 100644
--- a/tools/libxl/libxl_nic.c
+++ b/tools/libxl/libxl_nic.c
@@ -17,6 +17,18 @@
 
 #include "libxl_internal.h"
 
+#include <string.h>
+
+#include "md5.h"
+
+#ifdef __linux__
+#include <sys/types.h>
+#include <ifaddrs.h>
+#include <sys/socket.h>
+#include <linux/if_packet.h>
+#include <net/ethernet.h>
+#endif
+
 int libxl_mac_to_device_nic(libxl_ctx *ctx, uint32_t domid,
                             const char *mac, libxl_device_nic *nic)
 {
@@ -53,8 +65,41 @@ int libxl_mac_to_device_nic(libxl_ctx *ctx, uint32_t domid,
     return rc;
 }
 
+static int libxl__get_host_mac(libxl__gc *gc, unsigned char *buf)
+{
+    int rc = ERROR_FAIL;
+    #ifdef __linux__
+    struct ifaddrs *iface_list;
+    uint64_t largest = 0;
+
+    if (getifaddrs(&iface_list) == 0) {
+        for (struct ifaddrs *iface = iface_list;
+            iface != NULL; iface = iface->ifa_next) {
+            if (iface->ifa_addr && iface->ifa_addr->sa_family == AF_PACKET) {
+                struct sockaddr_ll *s = (struct sockaddr_ll *)iface->ifa_addr;
+                if (s->sll_halen == 6) {
+                    uint64_t value = 0;
+                    memcpy(&value, s->sll_addr, 6);
+                    if (value > largest) {
+                        memcpy(buf, s->sll_addr, 6);
+                        largest = value;
+                        rc = 0;
+                    }
+                }
+            }
+        }
+        freeifaddrs(iface_list);
+    } else {
+        LOG(WARN, "getifaddrs\n");
+    }
+    #endif
+
+    return rc;
+}
+
 static int libxl__device_nic_setdefault(libxl__gc *gc, uint32_t domid,
-                                        libxl_device_nic *nic, bool hotplug)
+                                        libxl_device_nic *nic, const char *name,
+                                        const int nic_index, bool hotplug)
 {
     int rc;
 
@@ -65,11 +110,22 @@ static int libxl__device_nic_setdefault(libxl__gc *gc, uint32_t domid,
         if (!nic->model) return ERROR_NOMEM;
     }
     if (libxl__mac_is_default(&nic->mac)) {
-        const uint8_t *r;
-        libxl_uuid uuid;
+        uint8_t r[16];
+
+        MD5_CTX ctx;
+        MD5Init(&ctx);
+
+        uint8_t hostmac[6];
+
+        if(libxl__get_host_mac(gc, hostmac) == 0) {
+            MD5Update(&ctx, hostmac, sizeof(hostmac));
+        } else {
+            LOGD(INFO, domid, "failed to get host mac address, will generate vm mac address without\n");
+        }
 
-        libxl_uuid_generate(&uuid);
-        r = libxl_uuid_bytearray(&uuid);
+        MD5Update(&ctx, (uint8_t *) name, strlen(name));
+        MD5Update(&ctx, (uint8_t *) &nic_index, sizeof(nic_index));
+        MD5Final(r, &ctx);
 
         nic->mac[0] = 0x00;
         nic->mac[1] = 0x16;
@@ -478,7 +534,7 @@ int libxl__device_nic_set_devids(libxl__gc *gc, libxl_domain_config *d_config,
          * but qemu needs the nic information to be complete.
          */
         ret = libxl__device_nic_setdefault(gc, domid, &d_config->nics[i],
-                                           false);
+                                           d_config->c_info.name, i, false);
         if (ret) {
             LOGD(ERROR, domid, "Unable to set nic defaults for nic %d", i);
             goto out;
diff --git a/tools/libxl/md5.c b/tools/libxl/md5.c
new file mode 100644
index 0000000000..88ea13938a
--- /dev/null
+++ b/tools/libxl/md5.c
@@ -0,0 +1,266 @@
+/* start - public domain MD5 implementation */
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include "md5.h"
+
+static void MD5Transform(uint32_t buf[4], uint32_t const in[16]);
+
+
+/**
+ * md5_sum - MD5 hash for a data block
+ * @addr: Pointers to the data area
+ * @len: Lengths of the data block
+ * @mac: Buffer for the hash
+ */
+void md5_sum(const uint8_t *addr, const size_t len, uint8_t *mac)
+{
+        MD5_CTX ctx;
+
+        MD5Init(&ctx);
+        MD5Update(&ctx, addr, len);
+        MD5Final(mac, &ctx);
+}
+
+
+#ifndef WORDS_BIGENDIAN
+#define byteReverse(buf, len)   /* Nothing */
+#else
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+    uint32_t t;
+    do {
+        t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+            ((unsigned) buf[1] << 8 | buf[0]);
+        *(uint32_t *) buf = t;
+        buf += 4;
+    } while (--longs);
+}
+#endif
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->bits[0] = 0;
+    ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+    uint32_t t;
+
+    /* Update bitcount */
+
+    t = ctx->bits[0];
+    if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
+        ctx->bits[1]++;         /* Carry from low to high */
+    ctx->bits[1] += len >> 29;
+
+    t = (t >> 3) & 0x3f;        /* Bytes already in shsInfo->data */
+
+    /* Handle any leading odd-sized chunks */
+
+    if (t) {
+        unsigned char *p = (unsigned char *) ctx->in + t;
+
+        t = 64 - t;
+        if (len < t) {
+            memcpy(p, buf, len);
+            return;
+        }
+        memcpy(p, buf, t);
+        byteReverse(ctx->in, 16);
+        MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+        buf += t;
+        len -= t;
+    }
+    /* Process data in 64-byte chunks */
+
+    while (len >= 64) {
+        memcpy(ctx->in, buf, 64);
+        byteReverse(ctx->in, 16);
+        MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+        buf += 64;
+        len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+
+    memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+    unsigned count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->bits[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8) {
+        /* Two lots of padding:  Pad the first block to 64 bytes */
+        memset(p, 0, count);
+        byteReverse(ctx->in, 16);
+        MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+
+        /* Now fill the next block with 56 bytes */
+        memset(ctx->in, 0, 56);
+    } else {
+        /* Pad block to 56 bytes */
+        memset(p, 0, count - 8);
+    }
+    byteReverse(ctx->in, 14);
+
+    /* Append length in bits and transform */
+    ((uint32_t *) ctx->in)[14] = ctx->bits[0];
+    ((uint32_t *) ctx->in)[15] = ctx->bits[1];
+
+    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+    byteReverse((unsigned char *) ctx->buf, 4);
+    memcpy(digest, ctx->buf, 16);
+    memset(ctx, 0, sizeof(*ctx));     /* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+        ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(uint32_t buf[4], uint32_t const in[16])
+{
+    register uint32_t a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
diff --git a/tools/libxl/md5.h b/tools/libxl/md5.h
new file mode 100644
index 0000000000..09c27e2968
--- /dev/null
+++ b/tools/libxl/md5.h
@@ -0,0 +1,26 @@
+#ifndef MD5_H
+#define MD5_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/**
+ * md5_sum - MD5 hash for a data block
+ * @addr: Pointers to the data area
+ * @len: Lengths of the data block
+ * @mac: Buffer for the hash
+ */
+void md5_sum(const uint8_t *addr, const size_t len, uint8_t *mac);
+
+
+struct MD5Context {
+        uint32_t buf[4];
+        uint32_t bits[2];
+        uint8_t in[64];
+};
+typedef struct MD5Context MD5_CTX;
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf, unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+
+#endif
-- 
2.11.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH] libxl: made vm mac address assignment deterministic
  2018-09-05 12:25 [PATCH] libxl: made vm mac address assignment deterministic Joshua Perrett
@ 2018-09-06 15:51 ` Wei Liu
  2018-09-06 16:18   ` Ian Jackson
  0 siblings, 1 reply; 9+ messages in thread
From: Wei Liu @ 2018-09-06 15:51 UTC (permalink / raw)
  To: Joshua Perrett; +Cc: xen-devel, Ian Jackson, George Dunlap, Wei Liu

On Wed, Sep 05, 2018 at 12:25:55PM +0000, Joshua Perrett wrote:
> Uses MD5 on the host mac address, vm name and vif index to generate the
> last three bytes of the vm mac address (for each vm).
> 
> It uses the vif index to account for multiple vifs.
> 
> MD5 code is originally from the public domain (written by Colin Plumb in
> 1993), files found in xen/tools/blktap2/drivers/.
> 
> Reported-by: George Dunlap <george.dunlap@citrix.com>
> Signed-off-by: Joshua Perrett <jperrett256@gmail.com>
[...]
>  int libxl_mac_to_device_nic(libxl_ctx *ctx, uint32_t domid,
>                              const char *mac, libxl_device_nic *nic)
>  {
> @@ -53,8 +65,41 @@ int libxl_mac_to_device_nic(libxl_ctx *ctx, uint32_t domid,
>      return rc;
>  }
>  
> +static int libxl__get_host_mac(libxl__gc *gc, unsigned char *buf)
> +{
> +    int rc = ERROR_FAIL;

Having a blank line makes things a bit clearer.

> +    #ifdef __linux__
> +    struct ifaddrs *iface_list;
> +    uint64_t largest = 0;
> +
> +    if (getifaddrs(&iface_list) == 0) {
> +        for (struct ifaddrs *iface = iface_list;
> +            iface != NULL; iface = iface->ifa_next) {
> +            if (iface->ifa_addr && iface->ifa_addr->sa_family == AF_PACKET) {
> +                struct sockaddr_ll *s = (struct sockaddr_ll *)iface->ifa_addr;

Blank line here.

Generally please add a blank line between variable declarations and
statements.

> +                if (s->sll_halen == 6) {
> +                    uint64_t value = 0;

Blank line here.

> +                    memcpy(&value, s->sll_addr, 6);

Please use sizeof(s->sll_addr) instead of 6.

Also please add an assert before the memcpy

   assert(sizeof(value) >= sizeof(s->sll-addr));

This will help catch potential buffer overflow issue. Not that there is
one in your code, it is just good habit to have.

> +                    if (value > largest) {
> +                        memcpy(buf, s->sll_addr, 6);
> +                        largest = value;
> +                        rc = 0;

Interesting algorithm, but I don't know anything better at the moment.
:)

> +                    }
> +                }
> +            }
> +        }
> +        freeifaddrs(iface_list);
> +    } else {
> +        LOG(WARN, "getifaddrs\n");

Use LOGE here to log errno too. And please say

  getifaddrs failed

And there is no need to have '\n' at the end of the line. LOG* macros
add that themselves.

> +    }
> +    #endif
> +
> +    return rc;
> +}
> +
>  static int libxl__device_nic_setdefault(libxl__gc *gc, uint32_t domid,
> -                                        libxl_device_nic *nic, bool hotplug)
> +                                        libxl_device_nic *nic, const char *name,
> +                                        const int nic_index, bool hotplug)
>  {
>      int rc;
>  
> @@ -65,11 +110,22 @@ static int libxl__device_nic_setdefault(libxl__gc *gc, uint32_t domid,
>          if (!nic->model) return ERROR_NOMEM;
>      }
>      if (libxl__mac_is_default(&nic->mac)) {
> -        const uint8_t *r;
> -        libxl_uuid uuid;
> +        uint8_t r[16];
> +
> +        MD5_CTX ctx;
> +        MD5Init(&ctx);
> +
> +        uint8_t hostmac[6];
> +
> +        if(libxl__get_host_mac(gc, hostmac) == 0) {

Missing a space after `if' here.

> +            MD5Update(&ctx, hostmac, sizeof(hostmac));
> +        } else {
> +            LOGD(INFO, domid, "failed to get host mac address, will generate vm mac address without\n");

Remove '\n'.

Wei.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] libxl: made vm mac address assignment deterministic
  2018-09-06 15:51 ` Wei Liu
@ 2018-09-06 16:18   ` Ian Jackson
  0 siblings, 0 replies; 9+ messages in thread
From: Ian Jackson @ 2018-09-06 16:18 UTC (permalink / raw)
  To: Wei Liu; +Cc: xen-devel, Joshua Perrett, George Dunlap

Wei Liu writes ("Re: [PATCH] libxl: made vm mac address assignment deterministic"):
> On Wed, Sep 05, 2018 at 12:25:55PM +0000, Joshua Perrett wrote:
> > Uses MD5 on the host mac address, vm name and vif index to generate the
> > last three bytes of the vm mac address (for each vm).

There is no such thing as "the" host mac address.  The host might
have several.  However, generally there is a specific interface that
will be used for this guest, depending on the vif connection mode.  In
bridge mode, for example, there is the mac address of the bridge.  I
think you should make sure to use the right interface.

I think you need to add something to the documentation.  You should
mention that this approach is only deterministic *on the same host*
(so in setups where the guest might be started on multiple hosts, with
networked storage, it won't work) and only *with the same physical
nic* (so swapping out the physical nic will change all the guests'
addresses).

> > MD5 code is originally from the public domain (written by Colin Plumb in
> > 1993), files found in xen/tools/blktap2/drivers/.

You are duplicating these files within the Xen tree.  That's pretty
ugly.  Can we not do this a better way ?

> > +static int libxl__get_host_mac(libxl__gc *gc, unsigned char *buf)
> > +{
> > +    int rc = ERROR_FAIL;
> 
> Having a blank line makes things a bit clearer.
> 
> > +    #ifdef __linux__
> > +    struct ifaddrs *iface_list;

Can we not have #ifdefs here please ?  The Linux-specific part should
go in libxl_linux.c.

> > +                    memcpy(&value, s->sll_addr, 6);
> 
> Please use sizeof(s->sll_addr) instead of 6.

Err, are you sure ?  Let me quote the proposed code:

> > +                if (s->sll_halen == 6) {
> > +                    uint64_t value = 0;
> > +                    memcpy(&value, s->sll_addr, 6);

This is very strange.  How can it possibly be right to overwrite the
first 6 bytes of value ?  That does a different thing on big-endian
and little-endian machines.  (

Also why are we not checking sll_hatype ?

> > +                    if (value > largest) {
> > +                        memcpy(buf, s->sll_addr, 6);
> > +                        largest = value;
> > +                        rc = 0;
> 
> Interesting algorithm, but I don't know anything better at the moment.
> :)

There is some reason for choosing the lexically largest address, IIRC.
But the reason should be in a comment in the code.  (ISTR reading
something about this in the Debian bridge-interfaces(5) manpage.)

Thanks,
Ian.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] libxl: made vm mac address assignment deterministic
  2018-09-12  9:54 Marcus Granado
@ 2018-09-12 10:52 ` George Dunlap
  0 siblings, 0 replies; 9+ messages in thread
From: George Dunlap @ 2018-09-12 10:52 UTC (permalink / raw)
  To: Marcus Granado, Ian Jackson
  Cc: George Dunlap, xen-devel, Wei Liu, joshua Perrett 256

On 09/12/2018 10:54 AM, Marcus Granado wrote:
>> Wei Liu writes ("Re: [PATCH] libxl: made vm mac address assignment
>> deterministic"):
>>> On Wed, Sep 05, 2018 at 12:25:55PM +0000, Joshua Perrett wrote:
>>> > Uses MD5 on the host mac address, vm name and vif index to generate
>>> the
>>> > last three bytes of the vm mac address (for each vm).
>>
>> There is no such thing as "the" host mac address.  The host might
>> have several.  However, generally there is a specific interface that
>> will be used for this guest, depending on the vif connection mode.  In
>> bridge mode, for example, there is the mac address of the bridge.  I
>> think you should make sure to use the right interface.
>>
>> I think you need to add something to the documentation.  You should
>> mention that this approach is only deterministic *on the same host*
>> (so in setups where the guest might be started on multiple hosts, with
>> networked storage, it won't work) and only *with the same physical
>> nic* (so swapping out the physical nic will change all the guests'
>> addresses).
> 
> As discussed, it looks like the use of a mac address from one of the
> host physical nics is actually a sort of fixed seed to create a
> non-changing context for the vm name and the vif index. I noticed two
> different, simpler to obtain seeds that are designed to be unique,
> non-changing values for a specific host:
> 
> - systemd-based systems use /etc/machine-id as a unique
> id:https://www.freedesktop.org/software/systemd/man/machine-id.html
> - libc-based systems use gethostid() as a unique id:
> http://man7.org/linux/man-pages/man3/gethostid.3.html
> 
> 
> I wonder if it is sufficient for the purposes of
> https://xenproject.atlassian.net/browse/XEN-110 to create the
> non-changing seed using the following algorithm, instead of using a mac
> address:
> 
> 1) if the seed is in the libxl config file, then use it. Useful to
> create a logical group of hosts sharing the same seed, so that the mac
> address won't change when vm migrates to another host in this group. Not
> to be added to the current patch being worked out, but can be easily
> added in the future.
> 
> 2) if the seed is not present in the libxl config file, then use
> /etc/machine-id if present as the seed.
> 
> 3) if /etc/machine-id is not present, then fall back to gethostid() as
> the seed. This call seems to be present in both linux and bsds' libc, so
> I believe this means it's always available for libxl. The reason for
> using gethostid() only as a fallback is that its man page says it
> attempts to return a unique id but it doesn't guarantee this in some
> situations.

This sounds like a good plan; unfortunately, I'm not sure gethostid() is
fit for purpose.

So it looks like the `hostid` command, part of coreutils, calls this and
returns the result [1].  I just ran `hostid` on both my desktop and
another machine under my desk, and got the same value:

---
$ hostname && hostid
elijah
007f0101
---
# hostname && hostid
immortal
007f0101
---

It looks like if /etc/hostid isn't set (which it doesn't seem to be on
three of my systems), this is actually derived from one of the host IP
addresses [2]; and in the above two cases for some reason it's picked up
127.0.1.1 as the IP address.

So although the description looks like exactly what we want, I don't
think we can rely on it to be unique.

 -George

[1] https://github.com/coreutils/coreutils/blob/master/src/hostid.c
[2]
https://www.redhat.com/archives/redhat-install-list/2001-December/msg00014.html


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] libxl: made vm mac address assignment deterministic
@ 2018-09-12  9:54 Marcus Granado
  2018-09-12 10:52 ` George Dunlap
  0 siblings, 1 reply; 9+ messages in thread
From: Marcus Granado @ 2018-09-12  9:54 UTC (permalink / raw)
  To: Ian Jackson; +Cc: George Dunlap, xen-devel, Wei Liu, joshua Perrett 256

> Wei Liu writes ("Re: [PATCH] libxl: made vm mac address assignment 
> deterministic"):
>> On Wed, Sep 05, 2018 at 12:25:55PM +0000, Joshua Perrett wrote:
>> > Uses MD5 on the host mac address, vm name and vif index to generate the
>> > last three bytes of the vm mac address (for each vm).
> 
> There is no such thing as "the" host mac address.  The host might
> have several.  However, generally there is a specific interface that
> will be used for this guest, depending on the vif connection mode.  In
> bridge mode, for example, there is the mac address of the bridge.  I
> think you should make sure to use the right interface.
> 
> I think you need to add something to the documentation.  You should
> mention that this approach is only deterministic *on the same host*
> (so in setups where the guest might be started on multiple hosts, with
> networked storage, it won't work) and only *with the same physical
> nic* (so swapping out the physical nic will change all the guests'
> addresses).

As discussed, it looks like the use of a mac address from one of the 
host physical nics is actually a sort of fixed seed to create a 
non-changing context for the vm name and the vif index. I noticed two 
different, simpler to obtain seeds that are designed to be unique, 
non-changing values for a specific host:

- systemd-based systems use /etc/machine-id as a unique 
id:https://www.freedesktop.org/software/systemd/man/machine-id.html
- libc-based systems use gethostid() as a unique id: 
http://man7.org/linux/man-pages/man3/gethostid.3.html


I wonder if it is sufficient for the purposes of 
https://xenproject.atlassian.net/browse/XEN-110 to create the 
non-changing seed using the following algorithm, instead of using a mac 
address:

1) if the seed is in the libxl config file, then use it. Useful to 
create a logical group of hosts sharing the same seed, so that the mac 
address won't change when vm migrates to another host in this group. Not 
to be added to the current patch being worked out, but can be easily 
added in the future.

2) if the seed is not present in the libxl config file, then use 
/etc/machine-id if present as the seed.

3) if /etc/machine-id is not present, then fall back to gethostid() as 
the seed. This call seems to be present in both linux and bsds' libc, so 
I believe this means it's always available for libxl. The reason for 
using gethostid() only as a fallback is that its man page says it 
attempts to return a unique id but it doesn't guarantee this in some 
situations.


The purpose of the above should be simple to understand and improve if 
necessary from a cursory glance at the code.

Thoughts?

Marcus


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] libxl: made vm mac address assignment deterministic
  2018-08-30 15:18 Joshua Perrett
@ 2018-08-31 17:05 ` Wei Liu
  0 siblings, 0 replies; 9+ messages in thread
From: Wei Liu @ 2018-08-31 17:05 UTC (permalink / raw)
  To: Joshua Perrett; +Cc: xen-devel, Ian Jackson, George Dunlap, Wei Liu

On Thu, Aug 30, 2018 at 03:18:04PM +0000, Joshua Perrett wrote:
> Uses MD5 on the host mac address, vm name and vif index to generate the
> last three bytes of the vm mac address (for each vm).
> 
> It uses the vif index to account for multiple vifs.
> 
> MD5 code is originally from the public domain (written by Colin Plumb in
> 1993), files found in xen/tools/blktap2/drivers/.
> 
> Reported-by: George Dunlap <george.dunlap@citrix.com>
> Signed-off-by: Joshua Perrett <jperrett256@gmail.com>
> ---
>  tools/libxl/Makefile    |   2 +-
>  tools/libxl/libxl_nic.c |  65 ++++++++++--
>  tools/libxl/md5.c       | 266 ++++++++++++++++++++++++++++++++++++++++++++++++
>  tools/libxl/md5.h       |  26 +++++
>  4 files changed, 352 insertions(+), 7 deletions(-)
>  create mode 100644 tools/libxl/md5.c
>  create mode 100644 tools/libxl/md5.h
> 
> diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
> index 6da342ed61..6e7db11367 100644
> --- a/tools/libxl/Makefile
> +++ b/tools/libxl/Makefile
> @@ -142,7 +142,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
>  			libxl_9pfs.o libxl_domain.o libxl_vdispl.o \
>  			libxl_pvcalls.o libxl_vsnd.o libxl_vkb.o $(LIBXL_OBJS-y)
>  LIBXL_OBJS += libxl_genid.o
> -LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
> +LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o md5.o
>  
>  LIBXL_TESTS += timedereg
>  LIBXL_TESTS_PROGS = $(LIBXL_TESTS) fdderegrace
> diff --git a/tools/libxl/libxl_nic.c b/tools/libxl/libxl_nic.c
> index 01b711b84e..9a1c0fb16f 100644
> --- a/tools/libxl/libxl_nic.c
> +++ b/tools/libxl/libxl_nic.c
> @@ -17,6 +17,18 @@
>  
>  #include "libxl_internal.h"
>  
> +#include <string.h>
> +
> +#include "md5.h"
> +
> +#ifdef __linux__
> +#include <sys/types.h>
> +#include <ifaddrs.h>
> +#include <sys/socket.h>
> +#include <linux/if_packet.h>
> +#include <net/ethernet.h>
> +#endif
> +
>  int libxl_mac_to_device_nic(libxl_ctx *ctx, uint32_t domid,
>                              const char *mac, libxl_device_nic *nic)
>  {
> @@ -53,8 +65,38 @@ int libxl_mac_to_device_nic(libxl_ctx *ctx, uint32_t domid,
>      return rc;
>  }
>  
> +static int libxl__get_host_mac(libxl__gc *gc, unsigned char *buf)
> +{
> +    int rc = -1;

rc should be initialised to ERROR_FAIL;

> +    #ifdef __linux__
> +    struct ifaddrs *iface_list;
> +
> +    if (getifaddrs(&iface_list) == 0) {

You haven't answered my question regarding stability of this list.

> +        for (struct ifaddrs *iface = iface_list;
> +            iface != NULL; iface = iface->ifa_next) {
> +            if (iface->ifa_addr && iface->ifa_addr->sa_family == AF_PACKET) {
> +                struct sockaddr_ll *s = (struct sockaddr_ll *)iface->ifa_addr;
> +                if (s->sll_halen == 6) {
> +                    memcpy(buf, s->sll_addr, 6);
> +                    if(buf[0] || buf[1] || buf[2] || buf[3] || buf[4] || buf[5]) {

Missing space after if.

Also please wrap the line around 80 characters.


> +                        rc = 0;
> +                        break;
> +                    }
> +                }
> +            }
> +        }
> +        freeifaddrs(iface_list);
> +    } else {
> +        LOG(ERROR, "getifaddrs\n");

If this is not a fatal error you should use WARN here.

> +    }
> +    #endif
> +
> +    return rc;
> +}
> +
>  static int libxl__device_nic_setdefault(libxl__gc *gc, uint32_t domid,
> -                                        libxl_device_nic *nic, bool hotplug)
> +                                        libxl_device_nic *nic, const char *name,
> +                                        const int nic_index, bool hotplug)
>  {
>      int rc;
>  
> @@ -65,11 +107,22 @@ static int libxl__device_nic_setdefault(libxl__gc *gc, uint32_t domid,
>          if (!nic->model) return ERROR_NOMEM;
>      }
>      if (libxl__mac_is_default(&nic->mac)) {
> -        const uint8_t *r;
> -        libxl_uuid uuid;
> +        uint8_t r[16];
> +
> +        MD5_CTX ctx;
> +        MD5Init(&ctx);
> +
> +        uint8_t hostmac[6] = {0};
> +
> +        if(libxl__get_host_mac(gc, hostmac) == 0) {
> +            MD5Update(&ctx, hostmac, sizeof(hostmac));
> +        } else {
> +            LOGD(WARN, domid, "failed to get host mac address, will generate vm mac address without\n");

Turn WARN into INFO.

Wei.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH] libxl: made vm mac address assignment deterministic
@ 2018-08-30 15:18 Joshua Perrett
  2018-08-31 17:05 ` Wei Liu
  0 siblings, 1 reply; 9+ messages in thread
From: Joshua Perrett @ 2018-08-30 15:18 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Ian Jackson, George Dunlap, Joshua Perrett

Uses MD5 on the host mac address, vm name and vif index to generate the
last three bytes of the vm mac address (for each vm).

It uses the vif index to account for multiple vifs.

MD5 code is originally from the public domain (written by Colin Plumb in
1993), files found in xen/tools/blktap2/drivers/.

Reported-by: George Dunlap <george.dunlap@citrix.com>
Signed-off-by: Joshua Perrett <jperrett256@gmail.com>
---
 tools/libxl/Makefile    |   2 +-
 tools/libxl/libxl_nic.c |  65 ++++++++++--
 tools/libxl/md5.c       | 266 ++++++++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/md5.h       |  26 +++++
 4 files changed, 352 insertions(+), 7 deletions(-)
 create mode 100644 tools/libxl/md5.c
 create mode 100644 tools/libxl/md5.h

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 6da342ed61..6e7db11367 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -142,7 +142,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
 			libxl_9pfs.o libxl_domain.o libxl_vdispl.o \
 			libxl_pvcalls.o libxl_vsnd.o libxl_vkb.o $(LIBXL_OBJS-y)
 LIBXL_OBJS += libxl_genid.o
-LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
+LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o md5.o
 
 LIBXL_TESTS += timedereg
 LIBXL_TESTS_PROGS = $(LIBXL_TESTS) fdderegrace
diff --git a/tools/libxl/libxl_nic.c b/tools/libxl/libxl_nic.c
index 01b711b84e..9a1c0fb16f 100644
--- a/tools/libxl/libxl_nic.c
+++ b/tools/libxl/libxl_nic.c
@@ -17,6 +17,18 @@
 
 #include "libxl_internal.h"
 
+#include <string.h>
+
+#include "md5.h"
+
+#ifdef __linux__
+#include <sys/types.h>
+#include <ifaddrs.h>
+#include <sys/socket.h>
+#include <linux/if_packet.h>
+#include <net/ethernet.h>
+#endif
+
 int libxl_mac_to_device_nic(libxl_ctx *ctx, uint32_t domid,
                             const char *mac, libxl_device_nic *nic)
 {
@@ -53,8 +65,38 @@ int libxl_mac_to_device_nic(libxl_ctx *ctx, uint32_t domid,
     return rc;
 }
 
+static int libxl__get_host_mac(libxl__gc *gc, unsigned char *buf)
+{
+    int rc = -1;
+    #ifdef __linux__
+    struct ifaddrs *iface_list;
+
+    if (getifaddrs(&iface_list) == 0) {
+        for (struct ifaddrs *iface = iface_list;
+            iface != NULL; iface = iface->ifa_next) {
+            if (iface->ifa_addr && iface->ifa_addr->sa_family == AF_PACKET) {
+                struct sockaddr_ll *s = (struct sockaddr_ll *)iface->ifa_addr;
+                if (s->sll_halen == 6) {
+                    memcpy(buf, s->sll_addr, 6);
+                    if(buf[0] || buf[1] || buf[2] || buf[3] || buf[4] || buf[5]) {
+                        rc = 0;
+                        break;
+                    }
+                }
+            }
+        }
+        freeifaddrs(iface_list);
+    } else {
+        LOG(ERROR, "getifaddrs\n");
+    }
+    #endif
+
+    return rc;
+}
+
 static int libxl__device_nic_setdefault(libxl__gc *gc, uint32_t domid,
-                                        libxl_device_nic *nic, bool hotplug)
+                                        libxl_device_nic *nic, const char *name,
+                                        const int nic_index, bool hotplug)
 {
     int rc;
 
@@ -65,11 +107,22 @@ static int libxl__device_nic_setdefault(libxl__gc *gc, uint32_t domid,
         if (!nic->model) return ERROR_NOMEM;
     }
     if (libxl__mac_is_default(&nic->mac)) {
-        const uint8_t *r;
-        libxl_uuid uuid;
+        uint8_t r[16];
+
+        MD5_CTX ctx;
+        MD5Init(&ctx);
+
+        uint8_t hostmac[6] = {0};
+
+        if(libxl__get_host_mac(gc, hostmac) == 0) {
+            MD5Update(&ctx, hostmac, sizeof(hostmac));
+        } else {
+            LOGD(WARN, domid, "failed to get host mac address, will generate vm mac address without\n");
+        }
 
-        libxl_uuid_generate(&uuid);
-        r = libxl_uuid_bytearray(&uuid);
+        MD5Update(&ctx, (uint8_t *) name, strlen(name));
+        MD5Update(&ctx, (uint8_t *) &nic_index, sizeof(nic_index));
+        MD5Final(r, &ctx);
 
         nic->mac[0] = 0x00;
         nic->mac[1] = 0x16;
@@ -478,7 +531,7 @@ int libxl__device_nic_set_devids(libxl__gc *gc, libxl_domain_config *d_config,
          * but qemu needs the nic information to be complete.
          */
         ret = libxl__device_nic_setdefault(gc, domid, &d_config->nics[i],
-                                           false);
+                                           d_config->c_info.name, i, false);
         if (ret) {
             LOGD(ERROR, domid, "Unable to set nic defaults for nic %d", i);
             goto out;
diff --git a/tools/libxl/md5.c b/tools/libxl/md5.c
new file mode 100644
index 0000000000..88ea13938a
--- /dev/null
+++ b/tools/libxl/md5.c
@@ -0,0 +1,266 @@
+/* start - public domain MD5 implementation */
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include "md5.h"
+
+static void MD5Transform(uint32_t buf[4], uint32_t const in[16]);
+
+
+/**
+ * md5_sum - MD5 hash for a data block
+ * @addr: Pointers to the data area
+ * @len: Lengths of the data block
+ * @mac: Buffer for the hash
+ */
+void md5_sum(const uint8_t *addr, const size_t len, uint8_t *mac)
+{
+        MD5_CTX ctx;
+
+        MD5Init(&ctx);
+        MD5Update(&ctx, addr, len);
+        MD5Final(mac, &ctx);
+}
+
+
+#ifndef WORDS_BIGENDIAN
+#define byteReverse(buf, len)   /* Nothing */
+#else
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+    uint32_t t;
+    do {
+        t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+            ((unsigned) buf[1] << 8 | buf[0]);
+        *(uint32_t *) buf = t;
+        buf += 4;
+    } while (--longs);
+}
+#endif
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->bits[0] = 0;
+    ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+    uint32_t t;
+
+    /* Update bitcount */
+
+    t = ctx->bits[0];
+    if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
+        ctx->bits[1]++;         /* Carry from low to high */
+    ctx->bits[1] += len >> 29;
+
+    t = (t >> 3) & 0x3f;        /* Bytes already in shsInfo->data */
+
+    /* Handle any leading odd-sized chunks */
+
+    if (t) {
+        unsigned char *p = (unsigned char *) ctx->in + t;
+
+        t = 64 - t;
+        if (len < t) {
+            memcpy(p, buf, len);
+            return;
+        }
+        memcpy(p, buf, t);
+        byteReverse(ctx->in, 16);
+        MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+        buf += t;
+        len -= t;
+    }
+    /* Process data in 64-byte chunks */
+
+    while (len >= 64) {
+        memcpy(ctx->in, buf, 64);
+        byteReverse(ctx->in, 16);
+        MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+        buf += 64;
+        len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+
+    memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+    unsigned count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->bits[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8) {
+        /* Two lots of padding:  Pad the first block to 64 bytes */
+        memset(p, 0, count);
+        byteReverse(ctx->in, 16);
+        MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+
+        /* Now fill the next block with 56 bytes */
+        memset(ctx->in, 0, 56);
+    } else {
+        /* Pad block to 56 bytes */
+        memset(p, 0, count - 8);
+    }
+    byteReverse(ctx->in, 14);
+
+    /* Append length in bits and transform */
+    ((uint32_t *) ctx->in)[14] = ctx->bits[0];
+    ((uint32_t *) ctx->in)[15] = ctx->bits[1];
+
+    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+    byteReverse((unsigned char *) ctx->buf, 4);
+    memcpy(digest, ctx->buf, 16);
+    memset(ctx, 0, sizeof(*ctx));     /* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+        ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(uint32_t buf[4], uint32_t const in[16])
+{
+    register uint32_t a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
diff --git a/tools/libxl/md5.h b/tools/libxl/md5.h
new file mode 100644
index 0000000000..09c27e2968
--- /dev/null
+++ b/tools/libxl/md5.h
@@ -0,0 +1,26 @@
+#ifndef MD5_H
+#define MD5_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/**
+ * md5_sum - MD5 hash for a data block
+ * @addr: Pointers to the data area
+ * @len: Lengths of the data block
+ * @mac: Buffer for the hash
+ */
+void md5_sum(const uint8_t *addr, const size_t len, uint8_t *mac);
+
+
+struct MD5Context {
+        uint32_t buf[4];
+        uint32_t bits[2];
+        uint8_t in[64];
+};
+typedef struct MD5Context MD5_CTX;
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf, unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+
+#endif
-- 
2.11.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH] libxl: made vm mac address assignment deterministic
  2018-08-29 16:34 Joshua Perrett
@ 2018-08-30  8:27 ` Wei Liu
  0 siblings, 0 replies; 9+ messages in thread
From: Wei Liu @ 2018-08-30  8:27 UTC (permalink / raw)
  To: Joshua Perrett; +Cc: xen-devel, Ian Jackson, Wei Liu

Also CC George

We had a race -- I commented on your patch on github. I will redo my
review here.

On Wed, Aug 29, 2018 at 04:34:28PM +0000, Joshua Perrett wrote:
> Uses MD5 on the host mac address, vm name and vif index to generate the last three
> bytes of the vm mac address (for each vm).
> It uses the vif index to account for multiple vifs.
> MD5 code is originally from the public domain (written by Colin Plumb in 1993), files
> found in xen/tools/blktap2/drivers/.

It would be better to reformat the commit message a bit.

Uses MD5 on the host mac address, vm name and vif index to generate the
last three bytes of the vm mac address (for each vm).

It uses the vif index to account for multiple vifs.

MD5 code is originally from the public domain (written by Colin Plumb in
1993), files found in xen/tools/blktap2/drivers/.

Add a blank line between paragraphs.

> 
> Reported-by: George Dunlap <george.dunlap@citrix.com>
> Signed-off-by: Joshua Perrett <jperrett256@gmail.com>

Do you have a Citrix email address?

> ---
>  tools/libxl/Makefile    |   2 +-
>  tools/libxl/libxl_nic.c |  59 +++++++++--
>  tools/libxl/md5.c       | 266 ++++++++++++++++++++++++++++++++++++++++++++++++
>  tools/libxl/md5.h       |  26 +++++
>  4 files changed, 346 insertions(+), 7 deletions(-)
>  create mode 100644 tools/libxl/md5.c
>  create mode 100644 tools/libxl/md5.h
> 
> diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
> index 6da342ed61..6e7db11367 100644
> --- a/tools/libxl/Makefile
> +++ b/tools/libxl/Makefile
> @@ -142,7 +142,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
>  			libxl_9pfs.o libxl_domain.o libxl_vdispl.o \
>  			libxl_pvcalls.o libxl_vsnd.o libxl_vkb.o $(LIBXL_OBJS-y)
>  LIBXL_OBJS += libxl_genid.o
> -LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
> +LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o md5.o
>  
>  LIBXL_TESTS += timedereg
>  LIBXL_TESTS_PROGS = $(LIBXL_TESTS) fdderegrace
> diff --git a/tools/libxl/libxl_nic.c b/tools/libxl/libxl_nic.c
> index 01b711b84e..37de5ffb04 100644
> --- a/tools/libxl/libxl_nic.c
> +++ b/tools/libxl/libxl_nic.c
> @@ -17,6 +17,16 @@
>  
>  #include "libxl_internal.h"
>  
> +#include <string.h>
> +
> +#include "md5.h"
> +
> +#include <sys/types.h>
> +#include <ifaddrs.h>
> +#include <sys/socket.h>
> +#include <linux/if_packet.h>
> +#include <net/ethernet.h>
> +


This will break BSDs. They will probably need to be enclosed in ifdef
__linux__.

It isn't always clear at the beginning that Xen can use other Unix-like
systems as Dom0.

>  int libxl_mac_to_device_nic(libxl_ctx *ctx, uint32_t domid,
>                              const char *mac, libxl_device_nic *nic)
>  {
> @@ -53,8 +63,36 @@ int libxl_mac_to_device_nic(libxl_ctx *ctx, uint32_t domid,
>      return rc;
>  }
>  
> +static int libxl__get_host_mac(unsigned char *buf)
> +{
> +    int success = -1;

Change this to rc and use it to store libxl error code. Please read
CODING_STYLE in libxl.

> +    struct ifaddrs *iface_list;

Blank line here.

> +    if (getifaddrs(&iface_list) == 0) {

Is the list stable?

> +        for (struct ifaddrs *iface = iface_list;
> +            iface != NULL; iface = iface->ifa_next) {
> +            if (iface->ifa_addr && iface->ifa_addr->sa_family == AF_PACKET) {
> +                struct sockaddr_ll *s = (struct sockaddr_ll *)iface->ifa_addr;

So the first mac is used?

> +                if (s->sll_halen == 6) {
> +                    for (int i = 0; i < 6; i++) {
> +                        buf[i] = s->sll_addr[i];
> +                    }

This can probably be replaced by a call to memcpy.

> +                    if(buf[0] || buf[1] || buf[2] || buf[3] || buf[4] || buf[5]) {
> +                        success = 0;
> +                        break;
> +                    }
> +                }
> +            }
> +        }
> +        freeifaddrs(iface_list);
> +    } else {
> +        perror("ERROR: getifaddrs\n");

Use one of the LOG macros here. You will need to pass in a gc to this
function.

> +    }

Blank line here.

> +    return success;
> +}
> +
>  static int libxl__device_nic_setdefault(libxl__gc *gc, uint32_t domid,
> -                                        libxl_device_nic *nic, bool hotplug)
> +                                        libxl_device_nic *nic, const char *name,
> +                                        const int nic_index, bool hotplug)
>  {
>      int rc;
>  
> @@ -65,11 +103,20 @@ static int libxl__device_nic_setdefault(libxl__gc *gc, uint32_t domid,
>          if (!nic->model) return ERROR_NOMEM;
>      }
>      if (libxl__mac_is_default(&nic->mac)) {
> -        const uint8_t *r;
> -        libxl_uuid uuid;
> +        uint8_t r[16];
> +
> +        uint8_t hostmac[6] = {0};
> +
> +        if(libxl__get_host_mac(hostmac)) {
> +            perror("WARNING: failed to get host mac address\n");

LOG here. And you should probably bail instead of continuing?

Again, you might want to make hostmac a Linux only thing.

> +        }
>  
> -        libxl_uuid_generate(&uuid);
> -        r = libxl_uuid_bytearray(&uuid);
> +        MD5_CTX ctx;
> +        MD5Init(&ctx);
> +        MD5Update(&ctx, hostmac, sizeof(hostmac));
> +        MD5Update(&ctx, (uint8_t *) name, strlen(name));
> +        MD5Update(&ctx, (uint8_t *) &nic_index, sizeof(nic_index));
> +        MD5Final(r, &ctx);
>  
>          nic->mac[0] = 0x00;
>          nic->mac[1] = 0x16;
> @@ -478,7 +525,7 @@ int libxl__device_nic_set_devids(libxl__gc *gc, libxl_domain_config *d_config,
>           * but qemu needs the nic information to be complete.
>           */
>          ret = libxl__device_nic_setdefault(gc, domid, &d_config->nics[i],
> -                                           false);
> +                                           d_config->c_info.name, i, false);
>          if (ret) {
>              LOGD(ERROR, domid, "Unable to set nic defaults for nic %d", i);
>              goto out;
> diff --git a/tools/libxl/md5.c b/tools/libxl/md5.c
> new file mode 100644
> index 0000000000..88ea13938a
> --- /dev/null
> +++ b/tools/libxl/md5.c

I have skipped this file.

Wei.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH] libxl: made vm mac address assignment deterministic
@ 2018-08-29 16:34 Joshua Perrett
  2018-08-30  8:27 ` Wei Liu
  0 siblings, 1 reply; 9+ messages in thread
From: Joshua Perrett @ 2018-08-29 16:34 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Ian Jackson, Joshua Perrett

Uses MD5 on the host mac address, vm name and vif index to generate the last three
bytes of the vm mac address (for each vm).
It uses the vif index to account for multiple vifs.
MD5 code is originally from the public domain (written by Colin Plumb in 1993), files
found in xen/tools/blktap2/drivers/.

Reported-by: George Dunlap <george.dunlap@citrix.com>
Signed-off-by: Joshua Perrett <jperrett256@gmail.com>
---
 tools/libxl/Makefile    |   2 +-
 tools/libxl/libxl_nic.c |  59 +++++++++--
 tools/libxl/md5.c       | 266 ++++++++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/md5.h       |  26 +++++
 4 files changed, 346 insertions(+), 7 deletions(-)
 create mode 100644 tools/libxl/md5.c
 create mode 100644 tools/libxl/md5.h

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 6da342ed61..6e7db11367 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -142,7 +142,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
 			libxl_9pfs.o libxl_domain.o libxl_vdispl.o \
 			libxl_pvcalls.o libxl_vsnd.o libxl_vkb.o $(LIBXL_OBJS-y)
 LIBXL_OBJS += libxl_genid.o
-LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
+LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o md5.o
 
 LIBXL_TESTS += timedereg
 LIBXL_TESTS_PROGS = $(LIBXL_TESTS) fdderegrace
diff --git a/tools/libxl/libxl_nic.c b/tools/libxl/libxl_nic.c
index 01b711b84e..37de5ffb04 100644
--- a/tools/libxl/libxl_nic.c
+++ b/tools/libxl/libxl_nic.c
@@ -17,6 +17,16 @@
 
 #include "libxl_internal.h"
 
+#include <string.h>
+
+#include "md5.h"
+
+#include <sys/types.h>
+#include <ifaddrs.h>
+#include <sys/socket.h>
+#include <linux/if_packet.h>
+#include <net/ethernet.h>
+
 int libxl_mac_to_device_nic(libxl_ctx *ctx, uint32_t domid,
                             const char *mac, libxl_device_nic *nic)
 {
@@ -53,8 +63,36 @@ int libxl_mac_to_device_nic(libxl_ctx *ctx, uint32_t domid,
     return rc;
 }
 
+static int libxl__get_host_mac(unsigned char *buf)
+{
+    int success = -1;
+    struct ifaddrs *iface_list;
+    if (getifaddrs(&iface_list) == 0) {
+        for (struct ifaddrs *iface = iface_list;
+            iface != NULL; iface = iface->ifa_next) {
+            if (iface->ifa_addr && iface->ifa_addr->sa_family == AF_PACKET) {
+                struct sockaddr_ll *s = (struct sockaddr_ll *)iface->ifa_addr;
+                if (s->sll_halen == 6) {
+                    for (int i = 0; i < 6; i++) {
+                        buf[i] = s->sll_addr[i];
+                    }
+                    if(buf[0] || buf[1] || buf[2] || buf[3] || buf[4] || buf[5]) {
+                        success = 0;
+                        break;
+                    }
+                }
+            }
+        }
+        freeifaddrs(iface_list);
+    } else {
+        perror("ERROR: getifaddrs\n");
+    }
+    return success;
+}
+
 static int libxl__device_nic_setdefault(libxl__gc *gc, uint32_t domid,
-                                        libxl_device_nic *nic, bool hotplug)
+                                        libxl_device_nic *nic, const char *name,
+                                        const int nic_index, bool hotplug)
 {
     int rc;
 
@@ -65,11 +103,20 @@ static int libxl__device_nic_setdefault(libxl__gc *gc, uint32_t domid,
         if (!nic->model) return ERROR_NOMEM;
     }
     if (libxl__mac_is_default(&nic->mac)) {
-        const uint8_t *r;
-        libxl_uuid uuid;
+        uint8_t r[16];
+
+        uint8_t hostmac[6] = {0};
+
+        if(libxl__get_host_mac(hostmac)) {
+            perror("WARNING: failed to get host mac address\n");
+        }
 
-        libxl_uuid_generate(&uuid);
-        r = libxl_uuid_bytearray(&uuid);
+        MD5_CTX ctx;
+        MD5Init(&ctx);
+        MD5Update(&ctx, hostmac, sizeof(hostmac));
+        MD5Update(&ctx, (uint8_t *) name, strlen(name));
+        MD5Update(&ctx, (uint8_t *) &nic_index, sizeof(nic_index));
+        MD5Final(r, &ctx);
 
         nic->mac[0] = 0x00;
         nic->mac[1] = 0x16;
@@ -478,7 +525,7 @@ int libxl__device_nic_set_devids(libxl__gc *gc, libxl_domain_config *d_config,
          * but qemu needs the nic information to be complete.
          */
         ret = libxl__device_nic_setdefault(gc, domid, &d_config->nics[i],
-                                           false);
+                                           d_config->c_info.name, i, false);
         if (ret) {
             LOGD(ERROR, domid, "Unable to set nic defaults for nic %d", i);
             goto out;
diff --git a/tools/libxl/md5.c b/tools/libxl/md5.c
new file mode 100644
index 0000000000..88ea13938a
--- /dev/null
+++ b/tools/libxl/md5.c
@@ -0,0 +1,266 @@
+/* start - public domain MD5 implementation */
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include "md5.h"
+
+static void MD5Transform(uint32_t buf[4], uint32_t const in[16]);
+
+
+/**
+ * md5_sum - MD5 hash for a data block
+ * @addr: Pointers to the data area
+ * @len: Lengths of the data block
+ * @mac: Buffer for the hash
+ */
+void md5_sum(const uint8_t *addr, const size_t len, uint8_t *mac)
+{
+        MD5_CTX ctx;
+
+        MD5Init(&ctx);
+        MD5Update(&ctx, addr, len);
+        MD5Final(mac, &ctx);
+}
+
+
+#ifndef WORDS_BIGENDIAN
+#define byteReverse(buf, len)   /* Nothing */
+#else
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+    uint32_t t;
+    do {
+        t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+            ((unsigned) buf[1] << 8 | buf[0]);
+        *(uint32_t *) buf = t;
+        buf += 4;
+    } while (--longs);
+}
+#endif
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->bits[0] = 0;
+    ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+    uint32_t t;
+
+    /* Update bitcount */
+
+    t = ctx->bits[0];
+    if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
+        ctx->bits[1]++;         /* Carry from low to high */
+    ctx->bits[1] += len >> 29;
+
+    t = (t >> 3) & 0x3f;        /* Bytes already in shsInfo->data */
+
+    /* Handle any leading odd-sized chunks */
+
+    if (t) {
+        unsigned char *p = (unsigned char *) ctx->in + t;
+
+        t = 64 - t;
+        if (len < t) {
+            memcpy(p, buf, len);
+            return;
+        }
+        memcpy(p, buf, t);
+        byteReverse(ctx->in, 16);
+        MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+        buf += t;
+        len -= t;
+    }
+    /* Process data in 64-byte chunks */
+
+    while (len >= 64) {
+        memcpy(ctx->in, buf, 64);
+        byteReverse(ctx->in, 16);
+        MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+        buf += 64;
+        len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+
+    memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+    unsigned count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->bits[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8) {
+        /* Two lots of padding:  Pad the first block to 64 bytes */
+        memset(p, 0, count);
+        byteReverse(ctx->in, 16);
+        MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+
+        /* Now fill the next block with 56 bytes */
+        memset(ctx->in, 0, 56);
+    } else {
+        /* Pad block to 56 bytes */
+        memset(p, 0, count - 8);
+    }
+    byteReverse(ctx->in, 14);
+
+    /* Append length in bits and transform */
+    ((uint32_t *) ctx->in)[14] = ctx->bits[0];
+    ((uint32_t *) ctx->in)[15] = ctx->bits[1];
+
+    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+    byteReverse((unsigned char *) ctx->buf, 4);
+    memcpy(digest, ctx->buf, 16);
+    memset(ctx, 0, sizeof(*ctx));     /* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+        ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(uint32_t buf[4], uint32_t const in[16])
+{
+    register uint32_t a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
diff --git a/tools/libxl/md5.h b/tools/libxl/md5.h
new file mode 100644
index 0000000000..09c27e2968
--- /dev/null
+++ b/tools/libxl/md5.h
@@ -0,0 +1,26 @@
+#ifndef MD5_H
+#define MD5_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/**
+ * md5_sum - MD5 hash for a data block
+ * @addr: Pointers to the data area
+ * @len: Lengths of the data block
+ * @mac: Buffer for the hash
+ */
+void md5_sum(const uint8_t *addr, const size_t len, uint8_t *mac);
+
+
+struct MD5Context {
+        uint32_t buf[4];
+        uint32_t bits[2];
+        uint8_t in[64];
+};
+typedef struct MD5Context MD5_CTX;
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf, unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+
+#endif
-- 
2.11.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2018-09-12 10:52 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-05 12:25 [PATCH] libxl: made vm mac address assignment deterministic Joshua Perrett
2018-09-06 15:51 ` Wei Liu
2018-09-06 16:18   ` Ian Jackson
  -- strict thread matches above, loose matches on Subject: below --
2018-09-12  9:54 Marcus Granado
2018-09-12 10:52 ` George Dunlap
2018-08-30 15:18 Joshua Perrett
2018-08-31 17:05 ` Wei Liu
2018-08-29 16:34 Joshua Perrett
2018-08-30  8:27 ` Wei Liu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.