[libvirt] [PATCH 6/8] util: Introduce virMACMap module

Michal Privoznik mprivozn at redhat.com
Wed Nov 30 09:59:33 UTC 2016


This module will be used to track:

  <domain, mac address list>

pairs. It will be important to know these mappings without
libvirt connection (that is from a JSON file), because NSS
module will use those to provide better host name translation.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 po/POTFILES.in                       |   1 +
 src/Makefile.am                      |   1 +
 src/libvirt_private.syms             |   9 +
 src/util/virmacmap.c                 | 399 +++++++++++++++++++++++++++++++++++
 src/util/virmacmap.h                 |  48 +++++
 tests/Makefile.am                    |  14 ++
 tests/virmacmapmock.c                |  29 +++
 tests/virmacmaptest.c                | 232 ++++++++++++++++++++
 tests/virmacmaptestdata/complex.json |  45 ++++
 tests/virmacmaptestdata/empty.json   |   3 +
 tests/virmacmaptestdata/simple.json  |   8 +
 tests/virmacmaptestdata/simple2.json |  16 ++
 12 files changed, 805 insertions(+)
 create mode 100644 src/util/virmacmap.c
 create mode 100644 src/util/virmacmap.h
 create mode 100644 tests/virmacmapmock.c
 create mode 100644 tests/virmacmaptest.c
 create mode 100644 tests/virmacmaptestdata/complex.json
 create mode 100644 tests/virmacmaptestdata/empty.json
 create mode 100644 tests/virmacmaptestdata/simple.json
 create mode 100644 tests/virmacmaptestdata/simple2.json

diff --git a/po/POTFILES.in b/po/POTFILES.in
index bdff679..b0a1ed4 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -213,6 +213,7 @@ src/util/virkeyfile.c
 src/util/virlease.c
 src/util/virlockspace.c
 src/util/virlog.c
+src/util/virmacmap.c
 src/util/virnetdev.c
 src/util/virnetdevbandwidth.c
 src/util/virnetdevbridge.c
diff --git a/src/Makefile.am b/src/Makefile.am
index d440548..a9106fa 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -137,6 +137,7 @@ UTIL_SOURCES =							\
 		util/virlockspace.c util/virlockspace.h		\
 		util/virlog.c util/virlog.h			\
 		util/virmacaddr.h util/virmacaddr.c		\
+		util/virmacmap.h util/virmacmap.c		\
 		util/virnetdev.h util/virnetdev.c		\
 		util/virnetdevbandwidth.h util/virnetdevbandwidth.c \
 		util/virnetdevbridge.h util/virnetdevbridge.c	\
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 0641030..963876b 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1926,6 +1926,15 @@ virMacAddrSet;
 virMacAddrSetRaw;
 
 
+# util/virmacmap.h
+virMACMapMgrAdd;
+virMACMapMgrFlush;
+virMACMapMgrFlushStr;
+virMACMapMgrLookup;
+virMACMapMgrNew;
+virMACMapMgrRemove;
+
+
 # util/virnetdev.h
 virNetDevAddMulti;
 virNetDevDelMulti;
diff --git a/src/util/virmacmap.c b/src/util/virmacmap.c
new file mode 100644
index 0000000..38c2ffd
--- /dev/null
+++ b/src/util/virmacmap.c
@@ -0,0 +1,399 @@
+/*
+ * virmacmap.c: MAC address <-> Domain name mapping
+ *
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *     Michal Privoznik <mprivozn at redhat.com>
+ */
+
+#include <config.h>
+
+#include "virmacmap.h"
+#include "virobject.h"
+#include "virlog.h"
+#include "virjson.h"
+#include "virfile.h"
+#include "virhash.h"
+#include "virstring.h"
+#include "viralloc.h"
+
+#define VIR_FROM_THIS VIR_FROM_NETWORK
+
+VIR_LOG_INIT("util.virmacmap");
+
+/**
+ * VIR_MAC_MAP_FILE_SIZE_MAX:
+ *
+ * Macro providing the upper limit on the size of mac maps file
+ */
+#define VIR_MAC_MAP_FILE_SIZE_MAX (32 * 1024 * 1024)
+
+struct virMACMapMgr {
+    virObjectLockable parent;
+
+    virHashTablePtr macs;
+};
+
+
+static virClassPtr virMACMapMgrClass;
+
+
+static void
+virMACMapMgrDispose(void *obj)
+{
+    virMACMapMgrPtr mgr = obj;
+    virHashFree(mgr->macs);
+}
+
+
+static void
+virMACMapMgrHashFree(void *payload, const void *name ATTRIBUTE_UNUSED)
+{
+    virStringListFree(payload);
+}
+
+
+static int virMACMapMgrOnceInit(void)
+{
+    if (!(virMACMapMgrClass = virClassNew(virClassForObjectLockable(),
+                                          "virMACMapMgrClass",
+                                          sizeof(virMACMapMgr),
+                                          virMACMapMgrDispose)))
+        return -1;
+
+    return 0;
+}
+
+VIR_ONCE_GLOBAL_INIT(virMACMapMgr);
+
+
+static int
+virMACMapMgrAddLocked(virMACMapMgrPtr mgr,
+                      const char *domain,
+                      const char *mac)
+{
+    int ret = -1;
+    const char **macsList = NULL;
+    char **newMacsList = NULL;
+
+    if ((macsList = virHashLookup(mgr->macs, domain)) &&
+        virStringListHasString(macsList, mac)) {
+        ret = 0;
+        goto cleanup;
+    }
+
+    if (!(newMacsList = virStringListAdd(macsList, mac)) ||
+        virHashUpdateEntry(mgr->macs, domain, newMacsList) < 0)
+        goto cleanup;
+    newMacsList = NULL;
+
+    ret = 0;
+ cleanup:
+    virStringListFree(newMacsList);
+    return ret;
+}
+
+
+static int
+virMACMapMgrRemoveLocked(virMACMapMgrPtr mgr,
+                         const char *domain,
+                         const char *mac)
+{
+    const char **macsList = NULL;
+    char **newMacsList = NULL;
+    int ret = -1;
+    int rv;
+
+    if (!(macsList = virHashLookup(mgr->macs, domain)))
+        return 0;
+
+    if (!virStringListHasString(macsList, mac)) {
+        ret = 0;
+        goto cleanup;
+    }
+
+    rv = virStringListRemove(macsList, &newMacsList, mac);
+    if (rv < 0) {
+        goto cleanup;
+    } else if (rv == 0) {
+        virHashRemoveEntry(mgr->macs, domain);
+    } else {
+        if (virHashUpdateEntry(mgr->macs, domain, newMacsList) < 0)
+            goto cleanup;
+    }
+    newMacsList = NULL;
+
+    ret = 0;
+ cleanup:
+    virStringListFree(newMacsList);
+    return ret;
+}
+
+
+static int
+virMACMapMgrLoadFile(virMACMapMgrPtr mgr,
+                     const char *file)
+{
+    char *map_str = NULL;
+    virJSONValuePtr map = NULL;
+    int map_str_len = 0;
+    size_t i;
+    int ret = -1;
+
+    if (virFileExists(file) &&
+        (map_str_len = virFileReadAll(file,
+                                      VIR_MAC_MAP_FILE_SIZE_MAX,
+                                      &map_str)) < 0)
+        goto cleanup;
+
+    if (map_str_len == 0) {
+        ret = 0;
+        goto cleanup;
+    }
+
+    if (!(map = virJSONValueFromString(map_str))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("invalid json in file: %s"),
+                       file);
+        goto cleanup;
+    }
+
+    if (!virJSONValueIsArray(map)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Malformed file structure: %s"),
+                       file);
+        goto cleanup;
+    }
+
+    for (i = 0; i < virJSONValueArraySize(map); i++) {
+        virJSONValuePtr tmp = virJSONValueArrayGet(map, i);
+        virJSONValuePtr macs;
+        const char *domain;
+        size_t j;
+
+        if (!(domain = virJSONValueObjectGetString(tmp, "domain"))) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Missing domain"));
+            goto cleanup;
+        }
+
+        if (!(macs = virJSONValueObjectGetArray(tmp, "macs"))) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Missing macs"));
+            goto cleanup;
+        }
+
+        for (j = 0; j < virJSONValueArraySize(macs); j++) {
+            virJSONValuePtr macJSON = virJSONValueArrayGet(macs, j);
+            const char *mac = virJSONValueGetString(macJSON);
+
+            if (virMACMapMgrAddLocked(mgr, domain, mac) < 0)
+                goto cleanup;
+        }
+    }
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(map_str);
+    virJSONValueFree(map);
+    return ret;
+}
+
+
+static int
+virMACMapHashDumper(void *payload,
+                    const void *name,
+                    void *data)
+{
+    virJSONValuePtr obj = NULL;
+    virJSONValuePtr arr = NULL;
+    const char **macs = payload;
+    size_t i;
+    int ret = -1;
+
+    if (!(obj = virJSONValueNewObject()) ||
+        !(arr = virJSONValueNewArray()))
+        goto cleanup;
+
+    for (i = 0; macs[i]; i++) {
+        virJSONValuePtr m = virJSONValueNewString(macs[i]);
+
+        if (!m ||
+            virJSONValueArrayAppend(arr, m) < 0) {
+            virJSONValueFree(m);
+            goto cleanup;
+        }
+    }
+
+    if (virJSONValueObjectAppendString(obj, "domain", name) < 0 ||
+        virJSONValueObjectAppend(obj, "macs", arr) < 0)
+        goto cleanup;
+    arr = NULL;
+
+    if (virJSONValueArrayAppend(data, obj) < 0)
+        goto cleanup;
+    obj = NULL;
+
+    ret = 0;
+ cleanup:
+    virJSONValueFree(obj);
+    virJSONValueFree(arr);
+    return ret;
+}
+
+
+static int
+virMACMapMgrDumpStr(virMACMapMgrPtr mgr,
+                    char **str)
+{
+    virJSONValuePtr arr;
+    int ret = -1;
+
+    if (!(arr = virJSONValueNewArray()))
+        goto cleanup;
+
+    if (virHashForEach(mgr->macs, virMACMapHashDumper, arr) < 0)
+        goto cleanup;
+
+    if (!(*str = virJSONValueToString(arr, true)))
+        goto cleanup;
+
+    ret = 0;
+ cleanup:
+    virJSONValueFree(arr);
+    return ret;
+}
+
+
+static int
+virMACMapMgrWriteFile(virMACMapMgrPtr mgr,
+                      const char *file)
+{
+    char *str;
+    int ret = -1;
+
+    if (virMACMapMgrDumpStr(mgr, &str) < 0)
+        goto cleanup;
+
+    if (virFileRewriteStr(file, 0644, str) < 0)
+        goto cleanup;
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(str);
+    return ret;
+}
+
+
+#define VIR_MAC_HASH_TABLE_SIZE 10
+
+virMACMapMgrPtr
+virMACMapMgrNew(const char *file)
+{
+    virMACMapMgrPtr mgr;
+
+    if (virMACMapMgrInitialize() < 0)
+        return NULL;
+
+    if (!(mgr = virObjectLockableNew(virMACMapMgrClass)))
+        return NULL;
+
+    virObjectLock(mgr);
+    if (!(mgr->macs = virHashCreate(VIR_MAC_HASH_TABLE_SIZE,
+                                    virMACMapMgrHashFree)))
+        goto error;
+
+    if (file &&
+        virMACMapMgrLoadFile(mgr, file) < 0)
+        goto error;
+
+    virObjectUnlock(mgr);
+    return mgr;
+
+ error:
+    virObjectUnlock(mgr);
+    virObjectUnref(mgr);
+    return NULL;
+}
+
+
+int
+virMACMapMgrAdd(virMACMapMgrPtr mgr,
+                const char *domain,
+                const char *mac)
+{
+    int ret;
+
+    virObjectLock(mgr);
+    ret = virMACMapMgrAddLocked(mgr, domain, mac);
+    virObjectUnlock(mgr);
+    return ret;
+}
+
+
+int
+virMACMapMgrRemove(virMACMapMgrPtr mgr,
+                   const char *domain,
+                   const char *mac)
+{
+    int ret;
+
+    virObjectLock(mgr);
+    ret = virMACMapMgrRemoveLocked(mgr, domain, mac);
+    virObjectUnlock(mgr);
+    return ret;
+}
+
+
+const char *const *
+virMACMapMgrLookup(virMACMapMgrPtr mgr,
+                   const char *domain)
+{
+    const char *const *ret;
+
+    virObjectLock(mgr);
+    ret = virHashLookup(mgr->macs, domain);
+    virObjectUnlock(mgr);
+    return ret;
+}
+
+
+int
+virMACMapMgrFlush(virMACMapMgrPtr mgr,
+                  const char *filename)
+{
+    int ret;
+
+    virObjectLock(mgr);
+    ret = virMACMapMgrWriteFile(mgr, filename);
+    virObjectUnlock(mgr);
+    return ret;
+}
+
+
+int
+virMACMapMgrFlushStr(virMACMapMgrPtr mgr,
+                     char **str)
+{
+    int ret;
+
+    virObjectLock(mgr);
+    ret = virMACMapMgrDumpStr(mgr, str);
+    virObjectUnlock(mgr);
+    return ret;
+}
diff --git a/src/util/virmacmap.h b/src/util/virmacmap.h
new file mode 100644
index 0000000..6ebba7c
--- /dev/null
+++ b/src/util/virmacmap.h
@@ -0,0 +1,48 @@
+/*
+ * virmacmap.h: MAC address <-> Domain name mapping
+ *
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *     Michal Privoznik <mprivozn at redhat.com>
+ */
+
+#ifndef __VIR_MACMAP_H__
+# define __VIR_MACMAP_H__
+
+typedef struct virMACMapMgr virMACMapMgr;
+typedef virMACMapMgr *virMACMapMgrPtr;
+
+virMACMapMgrPtr virMACMapMgrNew(const char *file);
+
+int virMACMapMgrAdd(virMACMapMgrPtr mgr,
+                    const char *domain,
+                    const char *mac);
+
+int virMACMapMgrRemove(virMACMapMgrPtr mgr,
+                       const char *domain,
+                       const char *mac);
+
+const char *const *virMACMapMgrLookup(virMACMapMgrPtr mgr,
+                                      const char *domain);
+
+int virMACMapMgrFlush(virMACMapMgrPtr mgr,
+                      const char *filename);
+
+int virMACMapMgrFlushStr(virMACMapMgrPtr mgr,
+                         char **str);
+#endif /* __VIR_MACMAPPING_H__ */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6a24861..9d5583d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -144,6 +144,7 @@ EXTRA_DIST =		\
 	vircgroupdata \
 	virconfdata \
 	virfiledata \
+	virmacmaptestdata \
 	virmock.h \
 	virnetdaemondata \
 	virnetdevtestdata \
@@ -191,6 +192,7 @@ test_programs = virshtest sockettest \
 	domainconftest \
 	virhostdevtest \
 	vircaps2xmltest \
+	virmacmaptest \
 	virnetdevtest \
 	virtypedparamtest \
 	$(NULL)
@@ -406,6 +408,7 @@ test_libraries = libshunload.la \
 		virhostcpumock.la \
 		nssmock.la \
 		domaincapsmock.la \
+		virmacmapmock.la \
 		$(NULL)
 if WITH_QEMU
 test_libraries += libqemumonitortestutils.la \
@@ -1137,6 +1140,17 @@ nsslinktest_CFLAGS = 	\
 nsslinktest_LDADD = ../tools/nss/libnss_libvirt_impl.la
 nsslinktest_LDFLAGS = $(NULL)
 
+virmacmapmock_la_SOURCES = \
+	virmacmapmock.c
+virmacmapmock_la_CFLAGS = $(AM_CFLAGS)
+virmacmapmock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS)
+virmacmapmock_la_LIBADD = $(MOCKLIBS_LIBS)
+
+virmacmaptest_SOURCES = \
+	virmacmaptest.c testutils.h testutils.c
+virmacmaptest_CLFAGS = $(AM_CFLAGS);
+virmacmaptest_LDADD = $(LDADDS)
+
 virnetdevtest_SOURCES = \
 	virnetdevtest.c testutils.h testutils.c
 virnetdevtest_CFLAGS = $(AM_CFLAGS) $(LIBNL_CFLAGS)
diff --git a/tests/virmacmapmock.c b/tests/virmacmapmock.c
new file mode 100644
index 0000000..d01f1c9
--- /dev/null
+++ b/tests/virmacmapmock.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Michal Privoznik <mprivozn at redhat.com>
+ */
+
+#include <config.h>
+
+#include "virrandom.h"
+
+uint64_t virRandomBits(int nbits ATTRIBUTE_UNUSED)
+{
+    return 4; /* chosen by fair dice roll.
+                 guaranteed to be random. */
+}
diff --git a/tests/virmacmaptest.c b/tests/virmacmaptest.c
new file mode 100644
index 0000000..a983b54
--- /dev/null
+++ b/tests/virmacmaptest.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Michal Privoznik <mprivozn at redhat.com>
+ */
+
+#include <config.h>
+
+#include "testutils.h"
+#include "virmacmap.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+struct testData {
+    const char *file;
+    const char *domain;
+    const char * const * macs;
+    virMACMapMgrPtr mgr;
+};
+
+
+static int
+testMACLookup(const void *opaque)
+{
+    const struct testData *data = opaque;
+    virMACMapMgrPtr mgr = NULL;
+    const char * const * macs;
+    size_t i, j;
+    char *file = NULL;
+    int ret = -1;
+
+    if (virAsprintf(&file, "%s/virmacmaptestdata/%s.json",
+                    abs_srcdir, data->file) < 0)
+        goto cleanup;
+
+    if (!(mgr = virMACMapMgrNew(file)))
+        goto cleanup;
+
+    macs = virMACMapMgrLookup(mgr, data->domain);
+
+    for (i = 0; macs && macs[i]; i++) {
+        for (j = 0; data->macs && data->macs[j]; j++) {
+            if (STREQ(macs[i], data->macs[j]))
+                break;
+        }
+
+        if (!data->macs || !data->macs[j]) {
+            fprintf(stderr,
+                    "Unexpected %s in the returned list of MACs\n", macs[i]);
+            goto cleanup;
+        }
+    }
+
+    for (i = 0; data->macs && data->macs[i]; i++) {
+        for (j = 0; macs && macs[j]; j++) {
+            if (STREQ(data->macs[i], macs[j]))
+                break;
+        }
+
+        if (!macs || !macs[j]) {
+            fprintf(stderr,
+                    "Expected %s in the returned list of MACs\n", data->macs[i]);
+            goto cleanup;
+        }
+    }
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(file);
+    virObjectUnref(mgr);
+    return ret;
+}
+
+
+static int
+testMACRemove(const void *opaque)
+{
+    const struct testData *data = opaque;
+    virMACMapMgrPtr mgr = NULL;
+    const char * const * macs;
+    size_t i;
+    char *file = NULL;
+    int ret = -1;
+
+    if (virAsprintf(&file, "%s/virmacmaptestdata/%s.json",
+                    abs_srcdir, data->file) < 0)
+        goto cleanup;
+
+    if (!(mgr = virMACMapMgrNew(file)))
+        goto cleanup;
+
+    for (i = 0; data->macs && data->macs[i]; i++) {
+        if (virMACMapMgrRemove(mgr, data->domain, data->macs[i]) < 0) {
+            fprintf(stderr,
+                    "Error when removing %s from the list of MACs\n", data->macs[i]);
+            goto cleanup;
+        }
+    }
+
+    if ((macs = virMACMapMgrLookup(mgr, data->domain))) {
+        fprintf(stderr,
+                "Not removed all MACs for domain %s: %s\n", data->domain, macs[0]);
+        goto cleanup;
+    }
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(file);
+    virObjectUnref(mgr);
+    return ret;
+}
+
+
+static int
+testMACFlush(const void *opaque)
+{
+    const struct testData *data = opaque;
+    char *file = NULL;
+    char *str = NULL;
+    int ret = -1;
+
+    if (virAsprintf(&file, "%s/virmacmaptestdata/%s.json",
+                    abs_srcdir, data->file) < 0)
+        goto cleanup;
+
+    if (virMACMapMgrFlushStr(data->mgr, &str) < 0)
+        goto cleanup;
+
+    if (virTestCompareToFile(str, file) < 0)
+        goto cleanup;
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(file);
+    VIR_FREE(str);
+    return ret;
+}
+
+
+static int
+mymain(void)
+{
+    int ret = 0;
+    virMACMapMgrPtr mgr = NULL;
+
+#define DO_TEST_BASIC(f, d, ...)                                    \
+    do {                                                            \
+        const char * const m[] = {__VA_ARGS__, NULL };              \
+        struct testData data = {.file = f, .domain = d, .macs = m}; \
+        if (virTestRun("Lookup " #d " in " #f,                      \
+                       testMACLookup, &data) < 0)                   \
+            ret = -1;                                               \
+        if (virTestRun("Remove " #d " in " #f,                      \
+                       testMACRemove, &data) < 0)                   \
+            ret = -1;                                               \
+    } while (0)
+
+#define DO_TEST_FLUSH_PROLOGUE                                      \
+    if (!(mgr = virMACMapMgrNew(NULL)))                             \
+        ret = -1;
+
+#define DO_TEST_FLUSH(d, ...)                                       \
+    do {                                                            \
+        const char * const m[] = {__VA_ARGS__, NULL };              \
+        size_t i;                                                   \
+        for (i = 0; m[i]; i++)  {                                   \
+            if (virMACMapMgrAdd(mgr, d, m[i]) < 0) {                \
+                virObjectUnref(mgr);                                \
+                mgr = NULL;                                         \
+                ret = -1;                                           \
+            }                                                       \
+        }                                                           \
+    } while (0)
+
+
+#define DO_TEST_FLUSH_EPILOGUE(f)                                   \
+    do {                                                            \
+        struct testData data = {.file = f, .mgr = mgr};             \
+        if (virTestRun("Flush " #f, testMACFlush, &data) < 0)       \
+            ret = -1;                                               \
+        virObjectUnref(mgr);                                        \
+        mgr = NULL;                                                 \
+    } while (0)
+
+    DO_TEST_BASIC("empty", "none", NULL);
+    DO_TEST_BASIC("simple", "f24", "aa:bb:cc:dd:ee:ff");
+    DO_TEST_BASIC("simple2", "f24", "aa:bb:cc:dd:ee:ff", "a1:b2:c3:d4:e5:f6");
+    DO_TEST_BASIC("simple2", "f25", "00:11:22:33:44:55", "aa:bb:cc:00:11:22");
+
+    DO_TEST_FLUSH_PROLOGUE;
+    DO_TEST_FLUSH_EPILOGUE("empty");
+
+    DO_TEST_FLUSH_PROLOGUE;
+    DO_TEST_FLUSH("f24", "aa:bb:cc:dd:ee:ff");
+    DO_TEST_FLUSH_EPILOGUE("simple");
+
+    DO_TEST_FLUSH_PROLOGUE;
+    DO_TEST_FLUSH("f24", "aa:bb:cc:dd:ee:ff", "a1:b2:c3:d4:e5:f6");
+    DO_TEST_FLUSH("f25", "00:11:22:33:44:55", "aa:bb:cc:00:11:22");
+    DO_TEST_FLUSH_EPILOGUE("simple2");
+
+    DO_TEST_FLUSH_PROLOGUE;
+    DO_TEST_FLUSH("dom0", "e1:81:5d:f3:41:57", "76:0a:2a:a0:51:86", "01:c7:fc:01:c7:fc");
+    DO_TEST_FLUSH("dom0", "8e:82:53:60:32:4a", "14:7a:25:dc:7d:a0", "f8:d7:75:f8:d7:75");
+    DO_TEST_FLUSH("dom0", "73:d2:50:fb:0f:b1", "82:ee:a7:9b:e3:69", "a8:b4:cb:a8:b4:cb");
+    DO_TEST_FLUSH("dom0", "7e:81:86:0f:0b:fb", "94:e2:00:d9:4c:70", "dc:7b:83:dc:7b:83");
+    DO_TEST_FLUSH("dom0", "d1:19:a5:a1:52:a8", "22:03:a0:bf:cb:4a", "e3:c7:f8:e3:c7:f8");
+    DO_TEST_FLUSH("dom0", "aa:bf:3f:4f:21:8d", "28:67:45:72:8f:47", "eb:08:cd:eb:08:cd");
+    DO_TEST_FLUSH("dom0", "bd:f8:a7:e5:e2:bd", "c7:80:e3:b9:18:4d", "ce:da:c0:ce:da:c0");
+    DO_TEST_FLUSH("dom1", "8b:51:1d:9f:2f:29", "7c:ae:4c:3e:e1:11", "c6:68:4e:98:ff:6a");
+    DO_TEST_FLUSH("dom1", "43:0e:33:a1:3f:0f", "7a:3e:ed:bb:15:27", "b1:17:fd:95:d2:1b");
+    DO_TEST_FLUSH("dom1", "9e:89:49:99:51:0e", "89:b4:3f:08:88:2c", "54:0b:4c:e2:0a:39");
+    DO_TEST_FLUSH("dom1", "bb:88:07:19:51:9d", "b7:f1:1a:40:a2:95", "88:94:39:a3:90:b4");
+    DO_TEST_FLUSH_EPILOGUE("complex");
+    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+VIRT_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/virmacmapmock.so")
diff --git a/tests/virmacmaptestdata/complex.json b/tests/virmacmaptestdata/complex.json
new file mode 100644
index 0000000..192347c
--- /dev/null
+++ b/tests/virmacmaptestdata/complex.json
@@ -0,0 +1,45 @@
+[
+  {
+    "domain": "dom0",
+    "macs": [
+      "e1:81:5d:f3:41:57",
+      "76:0a:2a:a0:51:86",
+      "01:c7:fc:01:c7:fc",
+      "8e:82:53:60:32:4a",
+      "14:7a:25:dc:7d:a0",
+      "f8:d7:75:f8:d7:75",
+      "73:d2:50:fb:0f:b1",
+      "82:ee:a7:9b:e3:69",
+      "a8:b4:cb:a8:b4:cb",
+      "7e:81:86:0f:0b:fb",
+      "94:e2:00:d9:4c:70",
+      "dc:7b:83:dc:7b:83",
+      "d1:19:a5:a1:52:a8",
+      "22:03:a0:bf:cb:4a",
+      "e3:c7:f8:e3:c7:f8",
+      "aa:bf:3f:4f:21:8d",
+      "28:67:45:72:8f:47",
+      "eb:08:cd:eb:08:cd",
+      "bd:f8:a7:e5:e2:bd",
+      "c7:80:e3:b9:18:4d",
+      "ce:da:c0:ce:da:c0"
+    ]
+  },
+  {
+    "domain": "dom1",
+    "macs": [
+      "8b:51:1d:9f:2f:29",
+      "7c:ae:4c:3e:e1:11",
+      "c6:68:4e:98:ff:6a",
+      "43:0e:33:a1:3f:0f",
+      "7a:3e:ed:bb:15:27",
+      "b1:17:fd:95:d2:1b",
+      "9e:89:49:99:51:0e",
+      "89:b4:3f:08:88:2c",
+      "54:0b:4c:e2:0a:39",
+      "bb:88:07:19:51:9d",
+      "b7:f1:1a:40:a2:95",
+      "88:94:39:a3:90:b4"
+    ]
+  }
+]
diff --git a/tests/virmacmaptestdata/empty.json b/tests/virmacmaptestdata/empty.json
new file mode 100644
index 0000000..41b42e6
--- /dev/null
+++ b/tests/virmacmaptestdata/empty.json
@@ -0,0 +1,3 @@
+[
+
+]
diff --git a/tests/virmacmaptestdata/simple.json b/tests/virmacmaptestdata/simple.json
new file mode 100644
index 0000000..ea0fb08
--- /dev/null
+++ b/tests/virmacmaptestdata/simple.json
@@ -0,0 +1,8 @@
+[
+  {
+    "domain": "f24",
+    "macs": [
+      "aa:bb:cc:dd:ee:ff"
+    ]
+  }
+]
diff --git a/tests/virmacmaptestdata/simple2.json b/tests/virmacmaptestdata/simple2.json
new file mode 100644
index 0000000..91b2cde
--- /dev/null
+++ b/tests/virmacmaptestdata/simple2.json
@@ -0,0 +1,16 @@
+[
+  {
+    "domain": "f25",
+    "macs": [
+      "00:11:22:33:44:55",
+      "aa:bb:cc:00:11:22"
+    ]
+  },
+  {
+    "domain": "f24",
+    "macs": [
+      "aa:bb:cc:dd:ee:ff",
+      "a1:b2:c3:d4:e5:f6"
+    ]
+  }
+]
-- 
2.8.4




More information about the libvir-list mailing list