[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v11 2/3] tools/tests: introduce unit tests for domain ID allocator



From: Denis Mukhin <dmukhin@xxxxxxxx> 

Introduce some basic infrastructure for doing domain ID allocation unit tests,
and add a few tests that ensure correctness of the domain ID allocator in
dom0less and non-dom0less scenarios.

Signed-off-by: Denis Mukhin <dmukhin@xxxxxxxx>
---
Changes since v10:
- new patch
---
 tools/tests/Makefile                   |   2 +-
 tools/tests/domid/.gitignore           |   2 +
 tools/tests/domid/Makefile             |  69 ++++++++++++++
 tools/tests/domid/include/xen/domain.h | 124 +++++++++++++++++++++++++
 tools/tests/domid/test-domid.c         |  88 ++++++++++++++++++
 5 files changed, 284 insertions(+), 1 deletion(-)
 create mode 100644 tools/tests/domid/.gitignore
 create mode 100644 tools/tests/domid/Makefile
 create mode 100644 tools/tests/domid/include/xen/domain.h
 create mode 100644 tools/tests/domid/test-domid.c

diff --git a/tools/tests/Makefile b/tools/tests/Makefile
index 36928676a666..ff1666425436 100644
--- a/tools/tests/Makefile
+++ b/tools/tests/Makefile
@@ -1,7 +1,7 @@
 XEN_ROOT = $(CURDIR)/../..
 include $(XEN_ROOT)/tools/Rules.mk
 
-SUBDIRS-y :=
+SUBDIRS-y := domid
 SUBDIRS-y += resource
 SUBDIRS-$(CONFIG_X86) += cpu-policy
 SUBDIRS-$(CONFIG_X86) += tsx
diff --git a/tools/tests/domid/.gitignore b/tools/tests/domid/.gitignore
new file mode 100644
index 000000000000..91ac43232518
--- /dev/null
+++ b/tools/tests/domid/.gitignore
@@ -0,0 +1,2 @@
+*.o
+test-domid-*
diff --git a/tools/tests/domid/Makefile b/tools/tests/domid/Makefile
new file mode 100644
index 000000000000..e0b6a0e0a49c
--- /dev/null
+++ b/tools/tests/domid/Makefile
@@ -0,0 +1,69 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Unit tests for domain ID allocator.
+#
+# There are two flavors of the test:
+# - default; domain ID can be reused.
+# - dom0less: each domain ID can be allocated only once.
+#
+# Copyright 2025 Ford Motor Company
+
+XEN_ROOT=$(CURDIR)/../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+TESTS := test-domid-default test-domid-CONFIG_DOM0LESS_BOOT
+
+vpath domid.c $(XEN_ROOT)/xen/common/
+
+.PHONY: all
+all: $(TESTS)
+
+.PHONY: run
+run: $(TESTS)
+       $(foreach t,$(TESTS),./$(t);)
+
+.PHONY: clean
+clean:
+       $(RM) -- *.o $(TESTS) $(DEPS_RM)
+
+.PHONY: distclean
+distclean: clean
+       $(RM) -- *~
+
+.PHONY: install
+install: all
+       $(INSTALL_DIR) $(DESTDIR)$(LIBEXEC)/tests
+       $(INSTALL_PROG) test-domid-* $(DESTDIR)$(LIBEXEC)/tests
+
+.PHONY: uninstall
+uninstall:
+       $(RM) -- $(DESTDIR)$(LIBEXEC)/tests/test-domid-*
+
+CFLAGS += -D__XEN_TOOLS__
+CFLAGS += $(APPEND_CFLAGS)
+CFLAGS += $(CFLAGS_xeninclude)
+CFLAGS += -I./include/
+
+LDFLAGS += $(APPEND_LDFLAGS)
+
+# default (no dom0less) scenario
+domid-default.o: domid.c
+       $(CC) $(CFLAGS) -c $^ -o $@ $(LDFLAGS)
+
+test-domid-default.o: test-domid.c
+       $(CC) $(CFLAGS) -c $^ -o $@ $(LDFLAGS)
+
+test-domid-default: domid-default.o test-domid-default.o
+       $(CC) $^ -o $@ $(LDFLAGS)
+
+# dom0less scenario
+domid-CONFIG_DOM0LESS_BOOT.o: domid.c
+       $(CC) $(CFLAGS) -DCONFIG_DOM0LESS_BOOT -c $^ -o $@ $(LDFLAGS)
+
+test-domid-CONFIG_DOM0LESS_BOOT.o: test-domid.c
+       $(CC) $(CFLAGS) -DCONFIG_DOM0LESS_BOOT -c $^ -o $@ $(LDFLAGS)
+
+test-domid-CONFIG_DOM0LESS_BOOT: domid-CONFIG_DOM0LESS_BOOT.o 
test-domid-CONFIG_DOM0LESS_BOOT.o
+       $(CC) -DCONFIG_DOM0LESS_BOOT $^ -o $@ $(LDFLAGS)
+
+-include $(DEPS_INCLUDE)
diff --git a/tools/tests/domid/include/xen/domain.h 
b/tools/tests/domid/include/xen/domain.h
new file mode 100644
index 000000000000..465568c0dd02
--- /dev/null
+++ b/tools/tests/domid/include/xen/domain.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Unit test harness for domain ID allocator.
+ *
+ * Copyright 2025 Ford Motor Company
+ */
+
+#ifndef _TEST_HARNESS_
+#define _TEST_HARNESS_
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <xen-tools/common-macros.h>
+
+#define BUG_ON(x)               assert(!(x))
+#define ASSERT(x)               assert(x)
+
+#define __xen_mk_uint(x)        x ## U
+#define xen_mk_uint(x)          __xen_mk_uint(x)
+
+#define DOMID_FIRST_RESERVED    xen_mk_uint(10)
+#define DOMID_INVALID           xen_mk_uint(11)
+
+#define DEFINE_SPINLOCK(x)      unsigned long *(x)
+#define spin_lock(x)            ((*(x))++)
+#define spin_unlock(x)          ((*(x))--)
+
+#define BITS_PER_LONG           sizeof(unsigned long)
+#define BITS_PER_WORD           (8U * BITS_PER_LONG)
+#define BITS_TO_LONGS(bits) \
+    (((bits) + BITS_PER_LONG - 1) / BITS_PER_LONG)
+#define DECLARE_BITMAP(name, bits) \
+    unsigned long name[BITS_TO_LONGS(bits)]
+
+static inline int __test_and_set_bit(unsigned int nr, unsigned long *addr)
+{
+    unsigned long mask = 1UL << (nr % BITS_PER_WORD);
+    unsigned long *p = addr + (nr / BITS_PER_WORD);
+    int old = (*p & mask) != 0;
+
+    *p |= mask;
+
+    return old;
+}
+
+static inline void __set_bit(unsigned int nr, volatile unsigned long *addr)
+{
+    unsigned long mask = 1UL << (nr % BITS_PER_WORD);
+    unsigned long *p = (unsigned long *)addr + (nr / BITS_PER_WORD);
+
+    *p |= mask;
+}
+
+static inline void __clear_bit(unsigned int nr, volatile unsigned long *addr)
+{
+    unsigned long mask = 1UL << (nr % BITS_PER_WORD);
+    unsigned long *p = (unsigned long *)addr + (nr / BITS_PER_WORD);
+
+    *p &= ~mask;
+}
+
+static inline unsigned long find_next_zero_bit(const unsigned long *addr,
+                                               unsigned long size,
+                                               unsigned long offset)
+{
+    unsigned long idx = offset / BITS_PER_WORD;
+    unsigned long bit = offset % BITS_PER_WORD;
+
+    if (offset >= size)
+        return size;
+
+    while (offset < size)
+    {
+        unsigned long val = addr[idx] | (~0UL >> (BITS_PER_WORD - bit));
+
+        if (~val)
+        {
+            unsigned long pos = __builtin_ffsl(~val);
+
+            if (pos > 0)
+            {
+                unsigned long rc = idx * BITS_PER_WORD + (pos - 1);
+
+                if (rc < size)
+                    return rc;
+            }
+        }
+
+        offset = (idx + 1) * BITS_PER_WORD;
+        idx++;
+        bit = 0;
+    }
+
+    return size;
+}
+
+#define printk printf
+
+#define cf_check
+
+typedef bool spinlock_t;
+typedef uint16_t domid_t;
+
+/* See include/xen/domain.h */
+extern domid_t domid_alloc(domid_t domid);
+extern void domid_free(domid_t domid);
+
+#endif /* _TEST_HARNESS_ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/tests/domid/test-domid.c b/tools/tests/domid/test-domid.c
new file mode 100644
index 000000000000..f077d77be0df
--- /dev/null
+++ b/tools/tests/domid/test-domid.c
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Unit tests for domain ID allocator.
+ *
+ * Copyright 2025 Ford Motor Company
+ */
+
+/* Local test include replicating hypervisor includes. */
+#include <xen/domain.h>
+
+int main(int argc, char **argv)
+{
+    domid_t expected, allocated;
+
+    printk("%s DOMID_FIRST_RESERVED=%u DOMID_INVALID=%u\n",
+            argv[0], DOMID_FIRST_RESERVED, DOMID_INVALID);
+
+    /* Test ID#0 cannot be allocated twice. */
+    allocated = domid_alloc(0);
+    printk("expected %u allocated %u\n", 0, allocated);
+    ASSERT(allocated == 0);
+    allocated = domid_alloc(0);
+    printk("expected %u allocated %u\n", DOMID_INVALID, allocated);
+    ASSERT(allocated == DOMID_INVALID);
+
+    /* Ensure ID is not allocated. */
+    domid_free(0);
+
+    /*
+     * Test that that two consecutive calls of domid_alloc(DOMID_INVALID)
+     * will never return the same ID.
+     * NB: ID#0 is reserved and shall not be allocated by
+     * domid_alloc(DOMID_INVALID).
+     */
+    for ( expected = 0; expected < DOMID_FIRST_RESERVED - 1; expected++ )
+    {
+        allocated = domid_alloc(DOMID_INVALID);
+        printk("expected %u allocated %u\n", expected + 1, allocated);
+        ASSERT(allocated == expected + 1);
+    }
+    for ( expected = 0; expected < DOMID_FIRST_RESERVED; expected++ )
+    {
+        allocated = domid_alloc(DOMID_INVALID);
+        printk("expected %u allocated %u\n", DOMID_INVALID, allocated);
+        ASSERT(allocated == DOMID_INVALID);
+    }
+
+    /* Re-allocate first ID from [1..DOMID_FIRST_RESERVED - 1]. */
+#ifdef CONFIG_DOM0LESS_BOOT
+    /* Each ID is allowed to be allocated only once. */
+    expected = DOMID_INVALID;
+#else
+    expected = 1;
+#endif
+    domid_free(1);
+    allocated = domid_alloc(DOMID_INVALID);
+    printk("expected %u allocated %u\n", expected, allocated);
+    ASSERT(allocated == expected);
+
+    /* Re-allocate last ID from [1..DOMID_FIRST_RESERVED - 1]. */
+#ifdef CONFIG_DOM0LESS_BOOT
+    /* Each ID is allowed to be allocated only once. */
+    expected = DOMID_INVALID;
+#else
+    expected = DOMID_FIRST_RESERVED - 1;
+#endif
+    domid_free(DOMID_FIRST_RESERVED - 1);
+    allocated = domid_alloc(DOMID_INVALID);
+    printk("expected %u allocated %u\n", expected, allocated);
+    ASSERT(allocated == expected);
+
+    /* Allocate an invalid ID. */
+    expected = DOMID_INVALID;
+    allocated = domid_alloc(DOMID_FIRST_RESERVED);
+    printk("expected %u allocated %u\n", expected, allocated);
+    ASSERT(allocated == expected);
+
+    return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.34.1





 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.