domain <disk> <iotune> subelement "group_name"
to allow sharing I/O throttling quota between multiple drives
</li>
+ <li>nss: Introduce <code>libvirt-guest</code><br/>
+ New <code>libvirt-guest</code> nss module that translates libvirt
+ guest names into IP addresses
+ </li>
</ul>
</li>
<li><strong>Improvements</strong>
lookup given host name.
</p>
+ <h2><a name="Sources">Sources of information</a></h2>
+
+ <p>
+ As of <code>v3.0.0</code> release, libvirt offers two NSS modules
+ implementing two different methods of hostname translation. The first and
+ older method is implemented by <code>libvirt</code> plugin and
+ basically looks up the hostname to IP address translation in DHCP server
+ records. Therefore this is dependent on hostname provided by guests. Thing
+ is, not all the guests out there provide one in DHCP transactions, or not
+ every sysadmin out there believes all the guests. Hence libvirt implements
+ second method in <code>libvirt-guest</code> module which does libvirt guest
+ name to IP address translation (regardless of hostname set in the guest).
+ </p>
+
+ <p>
+ To enable either of the modules put their name into the
+ <code>nsswitch.conf</code> file. For instance, to enable
+ <code>libvirt-guest</code> module:
+ </p>
+
+<pre>
+$ cat /etc/nsswitch.conf
+# /etc/nsswitch.conf:
+hosts: files libvirt-guest dns
+# ...
+</pre>
+ <p>Or users can enable both at the same time:</p>
+<pre>
+$ cat /etc/nsswitch.conf
+# /etc/nsswitch.conf:
+hosts: files libvirt libvirt-guest dns
+# ...
+</pre>
+
+ <p>
+ This configuration will mean that if hostname is not found by the
+ <code>libvirt</code> module (e.g. because a guest did not sent hostname
+ during DHCP transaction), the <code>libvirt-guest</code> module is
+ consulted (and if the hostname matches libvirt guest name it will be
+ resolved).
+ </p>
+
<h2><a name="Internals">How does it work?</a></h2>
<p>
<h2><a name="Limitations">Limitations</a></h2>
<ol>
- <li>The libvirt NSS module matches only hostnames provided by guest. If
- the libvirt name and one advertised by guest differs, the latter is
- matched.</li>
+ <li>The <code>libvirt</code> NSS module matches only hostnames provided by guest.
+ If the libvirt name and one advertised by guest differs, the latter is
+ matched. However, as of <code>v3.0.0</code> there are two libvirt NSS modules
+ translating both hostnames provided by guest and libvirt guest names.</li>
<li>The module works only in that cases where IP addresses are assigned by
dnsmasq spawned by libvirt. Libvirt NATed networks are typical
example.</li>
</ol>
<p>
+ <i>The following paragraph describes implementation limitation of the
+ <code>libvirt</code> NSS module.</i>
These limitation are result of libvirt's internal implementation. While
libvirt can report IP addresses regardless of their origin, a public API
must be used to obtain those. However, for the API a connection object is
</pre>
<p>
- If there's no record for either of the aforementioned commands, it's very
- likely that NSS module won't find anything and vice versa.
+ If there's no record for either of the aforementioned commands, it's
+ very likely that NSS module won't find anything and vice versa.
+ As of <code>v3.0.0</code> libvirt provides <code>libvirt-guest</code> NSS
+ module that doesn't have this limitation. However, the statement is still
+ true for the <code>libvirt</code> NSS module.
</p>
</body>
</html>
util/virerror.h \
util/virfile.c \
util/virfile.h \
+ util/virhash.c \
+ util/virhash.h \
+ util/virhashcode.c \
+ util/virhashcode.h \
util/virjson.c \
util/virjson.h \
util/virkmod.c \
util/virlease.h \
util/virlog.c \
util/virlog.h \
+ util/virmacmap.c \
+ util/virmacmap.h \
util/virobject.c \
util/virobject.h \
util/virpidfile.c \
util/virpidfile.h \
util/virprocess.c \
util/virprocess.h \
+ util/virrandom.c \
+ util/virrandom.h \
util/virsocketaddr.c \
util/virsocketaddr.h \
util/virstring.c \
endif WITH_LINUX
if WITH_NSS
-test_helpers += nsslinktest
-test_programs += nsstest
+test_helpers += nsslinktest nssguestlinktest
+test_programs += nsstest nssguesttest
endif WITH_NSS
test_programs += storagevolxml2xmltest storagepoolxml2xmltest
$(LDADDS) \
../tools/nss/libnss_libvirt_impl.la
+nssguesttest_SOURCES = \
+ nsstest.c testutils.h testutils.c
+nssguesttest_CFLAGS = \
+ -DLIBVIRT_NSS_GUEST \
+ $(AM_CFLAGS) \
+ -I$(top_srcdir)/tools/nss
+nssguesttest_LDADD = \
+ $(LDADDS) \
+ ../tools/nss/libnss_libvirt_guest_impl.la
+
nssmock_la_SOURCES = \
nssmock.c
nssmock_la_CFLAGS = $(AM_CFLAGS)
nsslinktest_LDADD = ../tools/nss/libnss_libvirt_impl.la
nsslinktest_LDFLAGS = $(NULL)
+nssguestlinktest_SOURCES = nsslinktest.c
+nssguestlinktest_CFLAGS = \
+ -DLIBVIRT_NSS_GUEST \
+ $(AM_CFLAGS) \
+ -I$(top_srcdir)/tools/nss
+nssguestlinktest_LDADD = ../tools/nss/libnss_libvirt_guest_impl.la
+nssguestlinktest_LDFLAGS = $(NULL)
+
virmacmapmock_la_SOURCES = \
virmacmapmock.c
virmacmapmock_la_CFLAGS = $(AM_CFLAGS)
--- /dev/null
+[
+ {
+ "domain": "fedora",
+ "macs": [
+ "52:54:00:a4:6f:91",
+ "52:54:00:a4:6f:92"
+ ]
+ },
+ {
+ "domain": "gentoo",
+ "macs": [
+ "52:54:00:3a:b5:0c"
+ ]
+ },
+ {
+ "domain": "debian",
+ "macs": [
+ "52:54:00:11:22:33",
+ "52:54:00:a2:37:4c",
+ "52:54:00:f8:5b:1d"
+ ]
+ }
+]
"mac-address": "52:54:00:3a:b5:0c",
"hostname": "gentoo",
"expiry-time": 2000000000
+ },
+ {
+ "ip-address": "192.168.122.2",
+ "mac-address": "52:54:00:11:22:33",
+ "expiry-time": 2000000000
}
]
--- /dev/null
+[
+ {
+ "domain": "fedora",
+ "macs": [
+ "52:54:00:a4:6f:93",
+ "52:54:00:a4:6f:94"
+ ]
+ },
+ {
+ "domain": "gentoo",
+ "macs": [
+ "52:54:00:04:be:64"
+ ]
+ },
+ {
+ "domain": "suse",
+ "macs": [
+ "52:54:00:aa:bb:cc"
+ ]
+ }
+]
"mac-address": "52:54:00:a4:6f:94",
"hostname": "fedora",
"expiry-time": 1
+ },
+ {
+ "ip-address": "192.168.122.3",
+ "mac-address": "52:54:00:aa:bb:cc",
+ "expiry-time": 2000000000
}
]
# include <dirent.h>
# include <sys/stat.h>
# include <fcntl.h>
+# include <unistd.h>
# include "configmake.h"
# include "virstring.h"
static int (*real_open)(const char *path, int flags, ...);
static DIR * (*real_opendir)(const char *name);
+static int (*real_access)(const char *path, int mode);
# define LEASEDIR LOCALSTATEDIR "/lib/libvirt/dnsmasq/"
VIR_MOCK_REAL_INIT(open);
VIR_MOCK_REAL_INIT(opendir);
+ VIR_MOCK_REAL_INIT(access);
}
static int
free(newpath);
return ret;
}
+
+int
+access(const char *path, int mode)
+{
+ int ret;
+ char *newpath = NULL;
+
+ init_syms();
+
+ if (STRPREFIX(path, LEASEDIR) &&
+ getrealpath(&newpath, path) < 0)
+ return -1;
+
+ ret = real_access(newpath ? newpath : path, mode);
+
+ free(newpath);
+ return ret;
+}
#else
/* Nothing to override if NSS plugin is not enabled */
#endif
ret = -1; \
} while (0)
+# if !defined(LIBVIRT_NSS_GUEST)
DO_TEST("fedora", AF_INET, "192.168.122.197", "192.168.122.198", "192.168.122.199");
DO_TEST("gentoo", AF_INET, "192.168.122.254");
DO_TEST("gentoo", AF_INET6, "2001:1234:dead:beef::2");
DO_TEST("gentoo", AF_UNSPEC, "192.168.122.254");
DO_TEST("non-existent", AF_UNSPEC, NULL);
+# else /* defined(LIBVIRT_NSS_GUEST) */
+ DO_TEST("debian", AF_INET, "192.168.122.2");
+ DO_TEST("suse", AF_INET, "192.168.122.3");
+# endif /* defined(LIBVIRT_NSS_GUEST) */
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
if WITH_BSD_NSS
LIBVIRT_NSS_SYMBOL_FILE = \
$(srcdir)/nss/libvirt_nss_bsd.syms
+LIBVIRT_GUEST_NSS_SYMBOL_FILE = \
+ $(LIBVIRT_NSS_SYMBOL_FILE)
NSS_SO_VER = 1
install-nss:
( cd $(DESTDIR)$(libdir) && \
rm -f nss_libvirt.so.$(NSS_SO_VER) && \
- $(LN_S) libnss_libvirt.so.$(NSS_SO_VER) nss_libvirt.so.$(NSS_SO_VER) )
+ $(LN_S) libnss_libvirt.so.$(NSS_SO_VER) nss_libvirt.so.$(NSS_SO_VER) && \
+ rm -f nss_libvirt_guest.so.$(NSS_SO_VER) && \
+ $(LN_S) libnss_libvirt_guest.so.$(NSS_SO_VER) \
+ nss_libvirt_guest.so.$(NSS_SO_VER))
uninstall-nss:
-rm -f $(DESTDIR)$(libdir)/nss_libvirt.so.$(NSS_SO_VER)
+ -rm -f $(DESTDIR)$(libdir)/nss_libvirt_guest.so.$(NSS_SO_VER)
else ! WITH_BSD_NSS
LIBVIRT_NSS_SYMBOL_FILE = \
$(srcdir)/nss/libvirt_nss.syms
+LIBVIRT_GUEST_NSS_SYMBOL_FILE = \
+ $(srcdir)/nss/libvirt_guest_nss.syms
NSS_SO_VER = 2
install-nss:
nss_libnss_libvirt_la_LIBADD = \
nss/libnss_libvirt_impl.la
+noinst_LTLIBRARIES += nss/libnss_libvirt_guest_impl.la
+nss_libnss_libvirt_guest_impl_la_SOURCES = \
+ $(LIBVIRT_NSS_SOURCES)
+
+nss_libnss_libvirt_guest_impl_la_CFLAGS = \
+ -DLIBVIRT_NSS \
+ -DLIBVIRT_NSS_GUEST \
+ $(AM_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(PIE_CFLAGS) \
+ $(COVERAGE_CFLAGS) \
+ $(LIBXML_CFLAGS)
+
+nss_libnss_libvirt_guest_impl_la_LIBADD = \
+ ../gnulib/lib/libgnu.la \
+ ../src/libvirt-nss.la
+
+nss_libnss_libvirt_guest_la_SOURCES =
+nss_libnss_libvirt_guest_la_LDFLAGS = \
+ $(VERSION_SCRIPT_FLAGS)$(LIBVIRT_GUEST_NSS_SYMBOL_FILE) \
+ $(AM_LDFLAGS) \
+ -module \
+ -export-dynamic \
+ -avoid-version \
+ -shared \
+ -shrext .so.$(NSS_SO_VER)
+
+nss_libnss_libvirt_guest_la_LIBADD = \
+ nss/libnss_libvirt_guest_impl.la
+
lib_LTLIBRARIES = \
- nss/libnss_libvirt.la
+ nss/libnss_libvirt.la \
+ nss/libnss_libvirt_guest.la
endif WITH_NSS
EXTRA_DIST += $(LIBVIRT_NSS_SOURCES) \
$(srcdir)/nss/libvirt_nss.syms \
- $(srcdir)/nss/libvirt_nss_bsd.syms
+ $(srcdir)/nss/libvirt_nss_bsd.syms \
+ $(srcdir)/nss/libvirt_guest_nss.syms
clean-local:
-rm -rf wireshark/src/libvirt
--- /dev/null
+#
+# Officially exported symbols.
+#
+
+{
+global:
+ _nss_libvirt_guest_gethostbyname_r;
+ _nss_libvirt_guest_gethostbyname2_r;
+ _nss_libvirt_guest_gethostbyname3_r;
+ _nss_libvirt_guest_gethostbyname4_r;
+local: *;
+};
#include "virstring.h"
#include "virsocketaddr.h"
#include "configmake.h"
+#include "virmacmap.h"
+#include "virobject.h"
#if 0
# define ERROR(...) \
virJSONValuePtr leases_array,
size_t nleases,
const char *name,
+ const char **macs,
int af,
bool *found)
{
for (i = 0; i < nleases; i++) {
virJSONValuePtr lease = virJSONValueArrayGet(leases_array, i);
- const char *lease_name;
if (!lease) {
/* This should never happen (TM) */
goto cleanup;
}
- lease_name = virJSONValueObjectGetString(lease, "hostname");
+ if (macs) {
+ const char *macAddr;
- if (STRNEQ_NULLABLE(name, lease_name))
- continue;
+ macAddr = virJSONValueObjectGetString(lease, "mac-address");
+ if (!macAddr)
+ continue;
+
+ if (!virStringListHasString(macs, macAddr))
+ continue;
+ } else {
+ const char *lease_name;
+
+ lease_name = virJSONValueObjectGetString(lease, "hostname");
+
+ if (STRNEQ_NULLABLE(name, lease_name))
+ continue;
+ }
if (virJSONValueObjectGetNumberLong(lease, "expiry-time", &expirytime) < 0) {
/* A lease cannot be present without expiry-time */
ssize_t nleases;
leaseAddress *tmpAddress = NULL;
size_t ntmpAddress = 0;
+ virMacMapPtr *macmaps = NULL;
+ size_t nMacmaps = 0;
*address = NULL;
*naddress = 0;
goto cleanup;
}
-
if (virDirOpenQuiet(&dir, leaseDir) < 0) {
ERROR("Failed to open dir '%s'", leaseDir);
goto cleanup;
while ((ret = virDirRead(dir, &entry, leaseDir)) > 0) {
char *path;
- if (!virFileHasSuffix(entry->d_name, ".status"))
- continue;
-
- if (!(path = virFileBuildPath(leaseDir, entry->d_name, NULL)))
- goto cleanup;
-
- DEBUG("Processing %s", path);
+ if (virFileHasSuffix(entry->d_name, ".status")) {
+ if (!(path = virFileBuildPath(leaseDir, entry->d_name, NULL)))
+ goto cleanup;
- if (virLeaseReadCustomLeaseFile(leases_array, path, NULL, NULL) < 0) {
- ERROR("Unable to parse %s", path);
+ DEBUG("Processing %s", path);
+ if (virLeaseReadCustomLeaseFile(leases_array, path, NULL, NULL) < 0) {
+ ERROR("Unable to parse %s", path);
+ VIR_FREE(path);
+ goto cleanup;
+ }
+ VIR_FREE(path);
+ } else if (virFileHasSuffix(entry->d_name, ".macs")) {
+ if (!(path = virFileBuildPath(leaseDir, entry->d_name, NULL)))
+ goto cleanup;
+
+ if (VIR_REALLOC_N_QUIET(macmaps, nMacmaps + 1) < 0) {
+ VIR_FREE(path);
+ goto cleanup;
+ }
+
+ DEBUG("Processing %s", path);
+ if (!(macmaps[nMacmaps] = virMacMapNew(path))) {
+ ERROR("Unable to parse %s", path);
+ VIR_FREE(path);
+ goto cleanup;
+ }
+ nMacmaps++;
VIR_FREE(path);
- goto cleanup;
}
-
- VIR_FREE(path);
}
-
VIR_DIR_CLOSE(dir);
nleases = virJSONValueArraySize(leases_array);
DEBUG("Read %zd leases", nleases);
+#if !defined(LIBVIRT_NSS_GUEST)
if (findLeaseInJSON(&tmpAddress, &ntmpAddress,
leases_array, nleases,
- name, af, found) < 0)
+ name, NULL, af, found) < 0)
goto cleanup;
+#else /* defined(LIBVIRT_NSS_GUEST) */
+
+ size_t i;
+ for (i = 0; i < nMacmaps; i++) {
+ const char **macs = (const char **) virMacMapLookup(macmaps[i], name);
+
+ if (!macs)
+ continue;
+
+ if (findLeaseInJSON(&tmpAddress, &ntmpAddress,
+ leases_array, nleases,
+ name, macs, af, found) < 0)
+ goto cleanup;
+ }
+
+#endif /* defined(LIBVIRT_NSS_GUEST) */
+
*address = tmpAddress;
*naddress = ntmpAddress;
tmpAddress = NULL;
VIR_FREE(tmpAddress);
virJSONValueFree(leases_array);
VIR_DIR_CLOSE(dir);
+ while (nMacmaps)
+ virObjectUnref(macmaps[--nMacmaps]);
+ VIR_FREE(macmaps);
return ret;
}
# include <nss.h>
# include <netdb.h>
-# define NSS_NAME(s) _nss_libvirt_##s##_r
+# if !defined(LIBVIRT_NSS_GUEST)
+# define NSS_NAME(s) _nss_libvirt_##s##_r
+# else
+# define NSS_NAME(s) _nss_libvirt_guest_##s##_r
+# endif
enum nss_status
NSS_NAME(gethostbyname)(const char *name, struct hostent *result,