[libvirt] [hyperv]: Connection failure
by Ata Bohra
Hi Everyone, I installed a HyperV server and trying to connect to it using libvirt. As suggested by libvirt driver wiki (http://libvirt.org/drvhyperv.html), I've enabled Basic authentication on the server (and also enabled HTTP connection request for debugging purpose). Even after all this configuration, on connection I get error as: ---------------Enter Administrator's password for 10.y.y.y: xxxxxx
2013-02-14 00:02:25.122+0000: 6825: info : libvirt version: 1.0.2
2013-02-14 00:02:25.122+0000: 6825: error : hypervDebugHandler:1444 : openwsman error: NULL response
libvir: Hyper-V Driver error : internal error Transport error during enumeration: Could not connect (7)
Failed to open connection
libvir: error : invalid connection pointer in virConnectGetHostname
Host name: (null)
libvir: error : invalid connection pointer in virConnectClose ------------------------------ Hyper-V server configuration looks like:xxx> winrm get winrm/config/serviceServiceROOTSDDL = <long string>MaxConnectionOperations = 4294967295MaxConnectionOperationsPerUser = 1500MaxConnectionTimeoutms = 240000MaxConnections = 300MaxPacketRetrievalTimeSeconds = 120AllowUnencrypted = trueAuth Basic = true ........AllowRemoteAccess = true ------------------------------ I'm have libvirt on ubuntu (3.2.0-37-generic) and openwsman is 2.2.3-oubuntu4 version. Also, I'm using "Administrator" credentials to connect to HyperV server. Please suggest what is missing from my setup. Thanks!Ata
11 years, 9 months
[libvirt] [PATCH v4 0/2] net: support set source address(es) and ports for NAT
by Natanael Copa
Changes v4:
- barf if 'end' attribute is missing in <address>
- update doc to tell how to properly set single address
Natanael Copa (2):
net: support set public ip range for forward mode nat
net: add support for specifying port range for forward mode nat
docs/formatnetwork.html.in | 33 ++++++++
src/conf/network_conf.c | 195 ++++++++++++++++++++++++++++++++++++++++++--
src/conf/network_conf.h | 4 +
src/network/bridge_driver.c | 32 ++++++++
src/util/viriptables.c | 77 +++++++++++++++--
src/util/viriptables.h | 8 ++
6 files changed, 335 insertions(+), 14 deletions(-)
--
1.8.1.2
11 years, 9 months
[libvirt] [PATCH] build: more mingw fixes
by Eric Blake
More mingw build failures:
CCLD libvirt-lxc.la
/usr/lib64/gcc/i686-w64-mingw32/4.7.2/../../../../i686-w64-mingw32/bin/ld: cannot find libvirt_lxc.def: No such file or directory
CC virportallocatortest-virportallocatortest.o
../../tests/virportallocatortest.c: In function 'main':
../../tests/virportallocatortest.c:195:1: error: implicit declaration of function 'setenv' [-Werror=implicit-function-declaration]
* src/Makefile.am (GENERATED_SYM_FILES): Also generate
libvirt_lxc.def.
* bootstrap.conf (gnulib_modules): Import setenv.
---
Pushing under the build-breaker rule.
bootstrap.conf | 1 +
src/Makefile.am | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/bootstrap.conf b/bootstrap.conf
index 4b45a4f..6e03757 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -92,6 +92,7 @@ regex
random_r
sched
send
+setenv
setsockopt
sigaction
sigpipe
diff --git a/src/Makefile.am b/src/Makefile.am
index 0d2f2f8..780cd52 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1462,7 +1462,8 @@ EXTRA_DIST += \
libvirt_xenxs.syms \
libvirt_libssh2.syms
-GENERATED_SYM_FILES = libvirt.syms libvirt.def libvirt_qemu.def
+GENERATED_SYM_FILES = \
+ libvirt.syms libvirt.def libvirt_qemu.def libvirt_lxc.def
BUILT_SOURCES += $(GENERATED_SYM_FILES)
--
1.8.1.2
11 years, 9 months
[libvirt] [PATCH] build: fix mingw build
by Eric Blake
Commits 2025356 and ba72cb12 introduced typos.
* src/util/virpci.c (virPCIIsVirtualFunction) [!__linux__]: Fix
function name.
* src/util/virutil.c (virGetDeviceID): Fix attribute spelling.
---
Another push under the build-breaker rule.
src/util/virpci.c | 4 ++--
src/util/virutil.c | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/util/virpci.c b/src/util/virpci.c
index d1881e5..4bb82aa 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -1,7 +1,7 @@
/*
* virpci.c: helper APIs for managing host PCI devices
*
- * Copyright (C) 2009-2012 Red Hat, Inc.
+ * Copyright (C) 2009-2013 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
@@ -2239,7 +2239,7 @@ virPCIGetVirtualFunctions(const char *sysfs_path ATTRIBUTE_UNUSED,
}
int
-virPCIDeviceIsVirtualFunction(const char *vf_sysfs_device_link ATTRIBUTE_UNUSED)
+virPCIIsVirtualFunction(const char *vf_sysfs_device_link ATTRIBUTE_UNUSED)
{
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));
return -1;
diff --git a/src/util/virutil.c b/src/util/virutil.c
index 55e1b52..7acda77 100644
--- a/src/util/virutil.c
+++ b/src/util/virutil.c
@@ -3270,9 +3270,9 @@ virGetDeviceID(const char *path, int *maj, int *min)
}
#else
int
-virGetDeviceID(const char *path ATRRIBUTE_UNUSED,
- int *maj ATRRIBUTE_UNUSED,
- int *min ATRRIBUTE_UNUSED)
+virGetDeviceID(const char *path ATTRIBUTE_UNUSED,
+ int *maj ATTRIBUTE_UNUSED,
+ int *min ATTRIBUTE_UNUSED)
{
return -ENOSYS;
--
1.8.1.2
11 years, 9 months
[libvirt] [PATCH] regex: gnulib guarantees that we have regex support
by Eric Blake
No need to use HAVE_REGEX_H - our use of gnulib guarantees that
the header exists and works, regardless of platform. Similarly,
we can unconditionally assume a compiling <sys/wait.h> (although
the mingw version of this header is not full-featured).
* src/storage/storage_backend.c: Drop useless conditional.
* tests/testutils.c: Likewise.
---
I noticed this while trying to clean up a VPATH test failure.
src/storage/storage_backend.c | 6 ++----
tests/testutils.c | 18 +++---------------
2 files changed, 5 insertions(+), 19 deletions(-)
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index cab72c6..bdddddf 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -1,7 +1,7 @@
/*
* storage_backend.c: internal storage driver backend contract
*
- * Copyright (C) 2007-2012 Red Hat, Inc.
+ * Copyright (C) 2007-2013 Red Hat, Inc.
* Copyright (C) 2007-2008 Daniel P. Berrange
*
* This library is free software; you can redistribute it and/or
@@ -25,9 +25,7 @@
#include <string.h>
#include <stdio.h>
-#if HAVE_REGEX_H
-# include <regex.h>
-#endif
+#include <regex.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
diff --git a/tests/testutils.c b/tests/testutils.c
index 9c8f365..7b2ea51 100644
--- a/tests/testutils.c
+++ b/tests/testutils.c
@@ -1,7 +1,7 @@
/*
* testutils.c: basic test utils
*
- * Copyright (C) 2005-2012 Red Hat, Inc.
+ * Copyright (C) 2005-2013 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
@@ -27,12 +27,8 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
-#ifndef WIN32
-# include <sys/wait.h>
-#endif
-#ifdef HAVE_REGEX_H
-# include <regex.h>
-#endif
+#include <sys/wait.h>
+#include <regex.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
@@ -735,7 +731,6 @@ cleanup:
}
-#ifdef HAVE_REGEX_H
int virtTestClearLineRegex(const char *pattern,
char *str)
{
@@ -779,10 +774,3 @@ int virtTestClearLineRegex(const char *pattern,
return 0;
}
-#else
-int virtTestClearLineRegex(const char *pattern ATTRIBUTE_UNUSED,
- char *str ATTRIBUTE_UNUSED)
-{
- return 0;
-}
-#endif
--
1.8.1.2
11 years, 9 months
[libvirt] [PATCH] Configure native vlan modes on Open vSwitch ports
by james robson
This patch adds functionality to allow libvirt to configure the
'native-tagged' and 'native-untagged' modes on openvswitch networks.
---
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index ffcc33e..a5054cc 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -3209,6 +3209,12 @@ qemu-kvm -net nic,model=? /dev/null
<parameters
interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'/>
</virtualport>
</interface>
+ <interface type='bridge'>
+ <b><vlan trunk='yes' native_mode='tagged'
native_tag='123'></b>
+ <b><tag id='42'/></b>
+ <b></vlan></b>
+ ...
+ </interface>
<devices>
...</pre>
@@ -3234,7 +3240,17 @@ qemu-kvm -net nic,model=? /dev/null
attribute <code>trunk='yes'</code> can be added to the toplevel
vlan element.
</p>
-
+ <p>
+ For network connections using openvswitch it is possible to
+ configure the 'native-tagged' and 'native-untagged' vlan modes
+ <span class="since">(Since 1.0.2).</span> This uses the optional
+ <code>native_mode</code> and <code>native_tag</code> attributes
+ on the <code><vlan></code> element:
<code>native_mode</code>
+ may be set to 'tagged' or 'untagged', <code>native_tag</code>
+ sets the id of the native vlan. Setting a native vlan
implies
+ this is a trunk port, so <code>trunk='yes'</code> will be added
if not
+ explicitly set.
+ </p>
<h5><a name="elementLink">Modifying virtual link state</a></h5>
<pre>
...
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index 7b42529..68c562b 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -396,6 +396,12 @@
<parameters
interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'/>
</virtualport>
</interface>
+ <interface type='bridge'>
+ <b><vlan trunk='yes' native_mode='tagged'
native_tag='123'></b>
+ <b><tag id='42'/></b>
+ <b></vlan></b>
+ ...
+ </interface>
<devices>
...</pre>
diff --git a/docs/schemas/networkcommon.rng
b/docs/schemas/networkcommon.rng
index 51ff759..4696f43 100644
--- a/docs/schemas/networkcommon.rng
+++ b/docs/schemas/networkcommon.rng
@@ -197,6 +197,21 @@
<value>yes</value>
</attribute>
</optional>
+ <optional>
+ <attribute name="native_mode">
+ <choice>
+ <value>tagged</value>
+ <value>untagged</value>
+ </choice>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="native_tag">
+ <data type="unsignedInt">
+ <param name="maxInclusive">4095</param>
+ </data>
+ </attribute>
+ </optional>
<oneOrMore>
<element name="tag">
<attribute name="id">
diff --git a/src/conf/netdev_vlan_conf.c b/src/conf/netdev_vlan_conf.c
index 13ba8c6..618eb4c 100644
--- a/src/conf/netdev_vlan_conf.c
+++ b/src/conf/netdev_vlan_conf.c
@@ -17,6 +17,7 @@
*
* Authors:
* Laine Stump <laine(a)redhat.com>
+ * James Robson <jrobson(a)websense.com>
*/
#include <config.h>
@@ -33,6 +34,8 @@ virNetDevVlanParse(xmlNodePtr node, xmlXPathContextPtr
ctxt, virNetDevVlanPtr de
int ret = -1;
xmlNodePtr save = ctxt->node;
const char *trunk = NULL;
+ const char *nativeMode;
+ unsigned int nativeTag;
xmlNodePtr *tagNodes = NULL;
int nTags, ii;
@@ -73,16 +76,44 @@ virNetDevVlanParse(xmlNodePtr node,
xmlXPathContextPtr ctxt, virNetDevVlanPtr de
def->nTags = nTags;
- /* now that we know how many tags there are, look for an explicit
- * trunk setting.
- */
- if (nTags > 1)
- def->trunk = true;
+ def->nativeMode = 0;
+ def->nativeTag = 0;
ctxt->node = node;
+ if ((nativeMode = virXPathString("string(./@native_mode)", ctxt)) !
= NULL) {
+ if (STRCASENEQ(nativeMode, "tagged") && STRCASENEQ(nativeMode,
"untagged")) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid \"native_mode='%s'\" in <vlan> -
"
+ "native_mode must be 'tagged' or
'untagged'"), nativeMode);
+ goto error;
+ }
+ if (virXPathUInt("string(./@native_tag)", ctxt, &nativeTag) <
0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing or invalid native_tag
attribute"));
+ goto error;
+ }
+ if (nativeTag > 4095) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("native_tag %u too large (maximum 4095)"),
nativeTag);
+ goto error;
+ }
+ def->nativeMode = STRCASEEQ(nativeMode, "tagged") ? 1 : 2;
+ def->nativeTag = nativeTag;
+ }
+
+ /* def->trunk will be set to true if:
+ * "trunk='yes'" is set in xml
+ * a native-* vlan mode has been set
+ * >1 tag has been set */
if ((trunk = virXPathString("string(./@trunk)", ctxt)) != NULL) {
def->trunk = STRCASEEQ(trunk, "yes");
if (!def->trunk) {
+ if (def->nativeMode > 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid configuration in <vlan> -
\"trunk='no'\" is "
+ "not allowed with native_mode"));
+ goto error;
+ }
if (nTags > 1) {
virReportError(VIR_ERR_XML_ERROR,
_("invalid \"trunk='%s'\" in <vlan> -
trunk='yes' "
@@ -97,6 +128,8 @@ virNetDevVlanParse(xmlNodePtr node,
xmlXPathContextPtr ctxt, virNetDevVlanPtr de
goto error;
}
}
+ } else if (nTags > 1 || def->nativeMode > 0) {
+ def->trunk = true;
}
ret = 0;
@@ -122,8 +155,11 @@ virNetDevVlanFormat(virNetDevVlanPtr def,
virBufferPtr buf)
_("missing vlan tag data"));
return -1;
}
-
- virBufferAsprintf(buf, "<vlan%s>\n", def->trunk ? " trunk='yes'" :
"");
+ if (def->nativeMode == 0) {
+ virBufferAsprintf(buf, "<vlan%s>\n", def->trunk ? "
trunk='yes'" : "");
+ } else {
+ virBufferAsprintf(buf, "<vlan trunk='yes' native_mode='%s'
native_tag='%u'>\n", def->nativeMode == 1 ? "tagged" : "untagged",
def->nativeTag);
+ }
for (ii = 0; ii < def->nTags; ii++) {
virBufferAsprintf(buf, " <tag id='%u'/>\n", def->tag[ii]);
}
diff --git a/src/util/virnetdevopenvswitch.c
b/src/util/virnetdevopenvswitch.c
index 4fe077a..87122b0 100644
--- a/src/util/virnetdevopenvswitch.c
+++ b/src/util/virnetdevopenvswitch.c
@@ -19,6 +19,7 @@
* Dan Wendlandt <dan(a)nicira.com>
* Kyle Mestery <kmestery(a)cisco.com>
* Ansis Atteka <aatteka(a)nicira.com>
+ * James Robson <jrobson(a)websense.com>
*/
#include <config.h>
@@ -108,9 +109,13 @@ int virNetDevOpenvswitchAddPort(const char *brname,
const char *ifname,
virCommandAddArgList(cmd, "--timeout=5", "--", "--may-exist",
"add-port",
brname, ifname, NULL);
- if (virBufferUse(&buf) != 0)
+ if (virBufferUse(&buf) != 0) {
+ if (virtVlan->nativeMode > 0) {
+ virCommandAddArgFormat(cmd, "vlan_mode=%s",
virtVlan->nativeMode == 1 ? "native-tagged" : "native-untagged");
+ virCommandAddArgFormat(cmd, "tag=%d", virtVlan->nativeTag);
+ }
virCommandAddArgList(cmd, virBufferCurrentContent(&buf), NULL);
-
+ }
if (ovsport->profileID[0] == '\0') {
virCommandAddArgList(cmd,
"--", "set", "Interface", ifname,
attachedmac_ex_id,
diff --git a/src/util/virnetdevvlan.c b/src/util/virnetdevvlan.c
index 2fe2017..298673d 100644
--- a/src/util/virnetdevvlan.c
+++ b/src/util/virnetdevvlan.c
@@ -17,6 +17,7 @@
*
* Authors:
* Laine Stump <laine(a)redhat.com>
+ * James Robson <jrobson(a)websense.com>
*/
#include <config.h>
@@ -33,6 +34,8 @@ virNetDevVlanClear(virNetDevVlanPtr vlan)
{
VIR_FREE(vlan->tag);
vlan->nTags = 0;
+ vlan->nativeMode = 0;
+ vlan->nativeTag = -1;
}
void
@@ -54,7 +57,9 @@ virNetDevVlanEqual(const virNetDevVlanPtr a, const
virNetDevVlanPtr b)
return false;
if (a->trunk != b->trunk ||
- a->nTags != b->nTags) {
+ a->nTags != b->nTags ||
+ a->nativeMode != b->nativeMode ||
+ a->nativeTag != b->nativeTag) {
return false;
}
@@ -89,6 +94,8 @@ virNetDevVlanCopy(virNetDevVlanPtr dst, const
virNetDevVlanPtr src)
dst->trunk = src->trunk;
dst->nTags = src->nTags;
+ dst->nativeMode = src->nativeMode;
+ dst->nativeTag = src->nativeTag;
memcpy(dst->tag, src->tag, src->nTags * sizeof(*src->tag));
return 0;
}
diff --git a/src/util/virnetdevvlan.h b/src/util/virnetdevvlan.h
index c6b16ef..f0f78f0 100644
--- a/src/util/virnetdevvlan.h
+++ b/src/util/virnetdevvlan.h
@@ -17,6 +17,7 @@
*
* Authors:
* Laine Stump <laine(a)redhat.com>
+ * James Robson <jrobson(a)websense.com>
*/
#ifndef __VIR_NETDEV_VLAN_H__
@@ -25,6 +26,8 @@
typedef struct _virNetDevVlan virNetDevVlan;
typedef virNetDevVlan *virNetDevVlanPtr;
struct _virNetDevVlan {
+ short int nativeMode; /* 0=off, 1=tagged, 2=untagged */
+ unsigned int nativeTag;
bool trunk; /* true if this is a trunk */
int nTags; /* number of tags in array */
unsigned int *tag; /* pointer to array of tags */
diff --git a/tests/networkxml2xmlin/openvswitch-net.xml
b/tests/networkxml2xmlin/openvswitch-net.xml
index a3d82b1..93c49d5 100644
--- a/tests/networkxml2xmlin/openvswitch-net.xml
+++ b/tests/networkxml2xmlin/openvswitch-net.xml
@@ -21,4 +21,13 @@
<parameters profileid='alice-profile'/>
</virtualport>
</portgroup>
+ <portgroup name='tagged'>
+ <vlan native_mode='tagged' native_tag='123'>
+ <tag id='555'/>
+ <tag id='444'/>
+ </vlan>
+ <virtualport>
+ <parameters profileid='tagged-profile'/>
+ </virtualport>
+ </portgroup>
</network>
diff --git a/tests/networkxml2xmlout/openvswitch-net.xml
b/tests/networkxml2xmlout/openvswitch-net.xml
index a3d82b1..ab3d797 100644
--- a/tests/networkxml2xmlout/openvswitch-net.xml
+++ b/tests/networkxml2xmlout/openvswitch-net.xml
@@ -21,4 +21,13 @@
<parameters profileid='alice-profile'/>
</virtualport>
</portgroup>
+ <portgroup name='tagged'>
+ <vlan trunk='yes' native_mode='tagged' native_tag='123'>
+ <tag id='555'/>
+ <tag id='444'/>
+ </vlan>
+ <virtualport>
+ <parameters profileid='tagged-profile'/>
+ </virtualport>
+ </portgroup>
</network>
Protected by Websense Hosted Email Security -- www.websense.com
11 years, 9 months
[libvirt] [PATCH] qemu: handle not supported writable devices
by Philipp Hahn
If the running VM contains a writable raw image, creating snapshot fails
internally in QEMU, but the error is not detected by libvirt. Success is
still reported to the user, who will see the snapshot in libvirt, even
they are NOT created by qemu.
virsh # qemu-monitor-command --hmp winxp-1 savevm \"test\"
Device 'drive-fdc0-0-0' is writable but does not support snapshots.
virsh # snapshot-create-as winxp-1 test
Domain snapshot test created
Since there is no QMP command in QEMU, libvirtd sends a HMP command to the
running QEMU and parses the returned text. There only the following 4 strings
are detected as errors:
src/qemu/qemu_monitor_text.c:2822 # qemuMonitorTextCreateSnapshot()
> "Error while creating snapshot"
> "No block device can accept snapshots"
> "Could not open VM state file"
> "Error" + "while writing VM"
Since none of them match the above message, libvirt thinks the command
succeeded.
Add "does not support snapshots" as an additional error condition.
Signed-off-by: Philipp Hahn <hahn(a)univention.de>
---
src/qemu/qemu_monitor_text.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index bc0a11d..5880ab9 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -2854,6 +2854,10 @@ int qemuMonitorTextCreateSnapshot(qemuMonitorPtr mon, const char *name)
virReportError(VIR_ERR_OPERATION_FAILED, "%s", reply);
goto cleanup;
}
+ else if (strstr(reply, "does not support snapshots") != NULL) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s", reply);
+ goto cleanup;
+ }
ret = 0;
--
1.7.10.4
11 years, 9 months
[libvirt] Out of Memory Error
by varun bhatnagar
Hi,
I am trying to attach a usb device to my virtualbox node using libvirt. My
node is already running, I stop my node and then I am trying to add this
usb device.
I have a separate xml file defined for usb. It looks like this:
*<device>
<hostdev mode='subsystem' type='usb'>
<source>
<vendor id='0x4321'/>
<product id='0xfeeb'/>
</source>
</hostdev>
</device> *
*
*
I am trying to attach it using code:
*conn = libvirt.open("vbox:///session")
if conn ==None:
print 'Failed to open connection to the hypervisor'
sys.exit(1)
print 'connected to vbox hypervisor driver'
domainInstance = conn.lookupByName('SampleNode')
filed = open('/root/testFolder/usbSharedFolder.xml', 'r')
config_str = filed.read()
libvirt.virDomain.attachDevice(domainInstance, config_str)*
When it is executed I am getting an error message saying:
*libvir: VirtualBox Driver error : out of memory *
*
*
Even with virsh it is giving the same error. I am using the below command:
*attach-device SampleNode /root/testFolder/usbSharedFolder.xml*
Can anyone tell me what is going wrong. It is really very important. Please
do reply.
Thanks in advance.
11 years, 9 months