diff --git a/Makefile.am b/Makefile.am
index 07d69b9a728d..5275d2b27a48 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
 include Makefile.am.in
 
 ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
-SUBDIRS = . ndctl
+SUBDIRS = . daxctl ndctl
 if ENABLE_DOCS
 SUBDIRS += Documentation
 endif
diff --git a/Makefile.am.in b/Makefile.am.in
index a27d95e15061..f3dc8b48c890 100644
--- a/Makefile.am.in
+++ b/Makefile.am.in
@@ -39,3 +39,6 @@ LIBNDCTL_CURRENT=7
 LIBNDCTL_REVISION=0
 LIBNDCTL_AGE=1
 
+LIBDAXCTL_CURRENT=1
+LIBDAXCTL_REVISION=0
+LIBDAXCTL_AGE=0
diff --git a/configure.ac b/configure.ac
index e2110cb63640..bb7ffaa1548a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -243,6 +243,7 @@ AC_SUBST([my_CFLAGS])
 AC_CONFIG_HEADERS(config.h)
 AC_CONFIG_FILES([
         Makefile
+        daxctl/Makefile
         ndctl/Makefile
         test/Makefile
         Documentation/Makefile
diff --git a/daxctl/Makefile.am b/daxctl/Makefile.am
new file mode 100644
index 000000000000..a2aea16460a0
--- /dev/null
+++ b/daxctl/Makefile.am
@@ -0,0 +1,26 @@
+include $(top_srcdir)/Makefile.am.in
+
+%.pc: %.pc.in Makefile
+	$(SED_PROCESS)
+
+pkginclude_HEADERS = libdaxctl.h
+lib_LTLIBRARIES = lib/libdaxctl.la
+
+lib_libdaxctl_la_SOURCES =\
+	libdaxctl.h \
+	lib/libdaxctl-private.h \
+	../util/log.c \
+	../util/log.h \
+	lib/libdaxctl.c
+
+EXTRA_DIST += lib/libdaxctl.sym
+
+lib_libdaxctl_la_LDFLAGS = $(AM_LDFLAGS) \
+	-version-info $(LIBDAXCTL_CURRENT):$(LIBDAXCTL_REVISION):$(LIBDAXCTL_AGE) \
+	-Wl,--version-script=$(top_srcdir)/daxctl/lib/libdaxctl.sym
+lib_libdaxctl_la_DEPENDENCIES = lib/libdaxctl.sym
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = lib/libdaxctl.pc
+EXTRA_DIST += lib/libdaxctl.pc.in
+CLEANFILES += lib/libdaxctl.pc
diff --git a/daxctl/lib/libdaxctl-private.h b/daxctl/lib/libdaxctl-private.h
new file mode 100644
index 000000000000..aef95d4aedd4
--- /dev/null
+++ b/daxctl/lib/libdaxctl-private.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2014-2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ */
+#ifndef _LIBDAXCTL_PRIVATE_H_
+#define _LIBDAXCTL_PRIVATE_H_
+
+#define DAXCTL_EXPORT __attribute__ ((visibility("default")))
+
+#endif /* _LIBDAXCTL_PRIVATE_H_ */
diff --git a/daxctl/lib/libdaxctl.c b/daxctl/lib/libdaxctl.c
new file mode 100644
index 000000000000..41c536c14642
--- /dev/null
+++ b/daxctl/lib/libdaxctl.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <util/log.h>
+#include <uuid/uuid.h>
+#include <ccan/list/list.h>
+#include <ccan/array_size/array_size.h>
+
+#include <daxctl/libdaxctl.h>
+#include "libdaxctl-private.h"
+
+/**
+ * struct daxctl_ctx - library user context to find "nd" instances
+ *
+ * Instantiate with daxctl_new(), which takes an initial reference.  Free
+ * the context by dropping the reference count to zero with
+ * daxctl_unref(), or take additional references with daxctl_ref()
+ * @timeout: default library timeout in milliseconds
+ */
+struct daxctl_ctx {
+	/* log_ctx must be first member for daxctl_set_log_fn compat */
+	struct log_ctx ctx;
+	int refcount;
+	void *userdata;
+};
+
+/**
+ * daxctl_get_userdata - retrieve stored data pointer from library context
+ * @ctx: daxctl library context
+ *
+ * This might be useful to access from callbacks like a custom logging
+ * function.
+ */
+DAXCTL_EXPORT void *daxctl_get_userdata(struct daxctl_ctx *ctx)
+{
+	if (ctx == NULL)
+		return NULL;
+	return ctx->userdata;
+}
+
+/**
+ * daxctl_set_userdata - store custom @userdata in the library context
+ * @ctx: daxctl library context
+ * @userdata: data pointer
+ */
+DAXCTL_EXPORT void daxctl_set_userdata(struct daxctl_ctx *ctx, void *userdata)
+{
+	if (ctx == NULL)
+		return;
+	ctx->userdata = userdata;
+}
+
+/**
+ * daxctl_new - instantiate a new library context
+ * @ctx: context to establish
+ *
+ * Returns zero on success and stores an opaque pointer in ctx.  The
+ * context is freed by daxctl_unref(), i.e. daxctl_new() implies an
+ * internal daxctl_ref().
+ */
+DAXCTL_EXPORT int daxctl_new(struct daxctl_ctx **ctx)
+{
+	struct daxctl_ctx *c;
+
+	c = calloc(1, sizeof(struct daxctl_ctx));
+	if (!c)
+		return -ENOMEM;
+
+	c->refcount = 1;
+	log_init(&c->ctx, "libdaxctl", "DAXCTL_LOG");
+	info(c, "ctx %p created\n", c);
+	dbg(c, "log_priority=%d\n", c->ctx.log_priority);
+	*ctx = c;
+
+	return 0;
+}
+
+/**
+ * daxctl_ref - take an additional reference on the context
+ * @ctx: context established by daxctl_new()
+ */
+DAXCTL_EXPORT struct daxctl_ctx *daxctl_ref(struct daxctl_ctx *ctx)
+{
+	if (ctx == NULL)
+		return NULL;
+	ctx->refcount++;
+	return ctx;
+}
+
+/**
+ * daxctl_unref - drop a context reference count
+ * @ctx: context established by daxctl_new()
+ *
+ * Drop a reference and if the resulting reference count is 0 destroy
+ * the context.
+ */
+DAXCTL_EXPORT void daxctl_unref(struct daxctl_ctx *ctx)
+{
+	if (ctx == NULL)
+		return;
+	ctx->refcount--;
+	if (ctx->refcount > 0)
+		return;
+	info(ctx, "context %p released\n", ctx);
+	free(ctx);
+}
+
+/**
+ * daxctl_set_log_fn - override default log routine
+ * @ctx: daxctl library context
+ * @log_fn: function to be called for logging messages
+ *
+ * The built-in logging writes to stderr. It can be overridden by a
+ * custom function, to plug log messages into the user's logging
+ * functionality.
+ */
+DAXCTL_EXPORT void daxctl_set_log_fn(struct daxctl_ctx *ctx,
+		void (*daxctl_log_fn)(struct daxctl_ctx *ctx, int priority,
+			const char *file, int line, const char *fn,
+			const char *format, va_list args))
+{
+	ctx->ctx.log_fn = (log_fn) daxctl_log_fn;
+	info(ctx, "custom logging function %p registered\n", daxctl_log_fn);
+}
+
+/**
+ * daxctl_get_log_priority - retrieve current library loglevel (syslog)
+ * @ctx: daxctl library context
+ */
+DAXCTL_EXPORT int daxctl_get_log_priority(struct daxctl_ctx *ctx)
+{
+	return ctx->ctx.log_priority;
+}
+
+/**
+ * daxctl_set_log_priority - set log verbosity
+ * @priority: from syslog.h, LOG_ERR, LOG_INFO, LOG_DEBUG
+ *
+ * Note: LOG_DEBUG requires library be built with "configure --enable-debug"
+ */
+DAXCTL_EXPORT void daxctl_set_log_priority(struct daxctl_ctx *ctx, int priority)
+{
+	ctx->ctx.log_priority = priority;
+}
diff --git a/daxctl/lib/libdaxctl.pc.in b/daxctl/lib/libdaxctl.pc.in
new file mode 100644
index 000000000000..1aced1a55bc1
--- /dev/null
+++ b/daxctl/lib/libdaxctl.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libdaxctl
+Description: Manage "Device DAX" devices
+Version: @VERSION@
+Libs: -L${libdir} -ldaxctl
+Libs.private:
+Cflags: -I${includedir}
diff --git a/daxctl/lib/libdaxctl.sym b/daxctl/lib/libdaxctl.sym
new file mode 100644
index 000000000000..7583ed2876a1
--- /dev/null
+++ b/daxctl/lib/libdaxctl.sym
@@ -0,0 +1,13 @@
+LIBNDCTL_1 {
+global:
+	daxctl_get_userdata;
+	daxctl_set_userdata;
+	daxctl_ref;
+	daxctl_get_log_priority;
+	daxctl_set_log_fn;
+	daxctl_unref;
+	daxctl_set_log_priority;
+	daxctl_new;
+local:
+        *;
+};
diff --git a/daxctl/libdaxctl.h b/daxctl/libdaxctl.h
new file mode 100644
index 000000000000..5b9325314108
--- /dev/null
+++ b/daxctl/libdaxctl.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ */
+#ifndef _LIBDAXCTL_H_
+#define _LIBDAXCTL_H_
+
+#include <stdarg.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct daxctl_ctx;
+struct daxctl_ctx *daxctl_ref(struct daxctl_ctx *ctx);
+void daxctl_unref(struct daxctl_ctx *ctx);
+int daxctl_new(struct daxctl_ctx **ctx);
+void daxctl_set_log_fn(struct daxctl_ctx *ctx,
+		void (*log_fn)(struct daxctl_ctx *ctx, int priority,
+			const char *file, int line, const char *fn,
+			const char *format, va_list args));
+int daxctl_get_log_priority(struct daxctl_ctx *ctx);
+void daxctl_set_log_priority(struct daxctl_ctx *ctx, int priority);
+void daxctl_set_userdata(struct daxctl_ctx *ctx, void *userdata);
+void *daxctl_get_userdata(struct daxctl_ctx *ctx);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
