[libvirt] PATCH: 0/3: Run QEMU guests within a CGroup
by Daniel P. Berrange
Recent Linux kernels have a new concept of 'CGroups' which is a way to
group tasks on the system and apply policy to them as a whole. We already
use this in the LXC container driver, to control total memory usage of
things runing within a container.
This patch series is a proof of concept to make use of CGroups in the
QEMU driver. The idea is that we have a 3 level cgroup hierarchy
- Top level; contains the libvirtd daemon itself
- 2nd level: one per libvirt driver, but dos not contain any
processes.
- 3rd level: one per guest VM. Contains the QEMU process
The host admin can do control on the top level and 2nd level to set an
overall system policy. libvirt will then provide APIs / capabilities to
control individual VMs policy.
Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
15 years, 4 months
[libvirt] [PATCH 1/2] (Updated & fixed) OpenNebula driver, libvirt-0.6.2
by "Abel Míguez Rodríguez"
Hi all,
Here is the One driver & patches for the current git's master commit "9e9527 - Remove stale QEMU pidfiles".
[PATCH 1/2] Patch to be applied to libvirt-0.6.2 sources and building files.
[PATCH 2/2] Driver source code.
Thanks for all the comments about the patches.
We waited for the libvirt's release to update the driver's structure to 0.6.2 and apply the improvements.
Here is a short list of the main changes applied:
- Included driver's files in a different directory "src/opennebula"
- Added Capabilities "virCapabilitiesAddGuest" for "x86_64" and "i686" guests and used "one" as hypervisor at "virCapabilitiesAddGuestDomain".
- Instead creating a temporal file to send the VM definition we have updated the API we were using to being able to do everything in memory, so making use of "virBuffer" to create the VM definition Template.
- Added previously unsupported features to the ONE Template, other types of disks and graphics (vnc,sdl) settings.
- Fixed up warnings at compilation and make 'syntax-check' test passed.
thanks,
Abel Miguez.
[PATCH 1/2]
diff --git a/configure.in b/configure.in
index dcacc7f..ab14303 100644
--- a/configure.in
+++ b/configure.in
@@ -186,6 +186,8 @@ AC_ARG_WITH([vbox],
[ --with-vbox add VirtualBox support (on)],[],[with_vbox=yes])
AC_ARG_WITH([lxc],
[ --with-lxc add Linux Container support (on)],[],[with_lxc=yes])
+AC_ARG_WITH([one],
+[ --with-one add ONE support (on)],[],[with_one=no])
AC_ARG_WITH([test],
[ --with-test add test driver support (on)],[],[with_test=yes])
AC_ARG_WITH([remote],
@@ -305,6 +307,11 @@ if test "$with_uml" = "yes" ; then
fi
AM_CONDITIONAL([WITH_UML], [test "$with_uml" = "yes"])
+if test "$with_one" = "yes" ; then
+ AC_DEFINE_UNQUOTED([WITH_ONE],1,[whether ONE driver is enabled])
+fi
+AM_CONDITIONAL([WITH_ONE],[test "$with_one" = "yes"])
+
if test "$with_test" = "yes" ; then
AC_DEFINE_UNQUOTED([WITH_TEST], 1, [whether Test driver is enabled])
fi
@@ -406,6 +413,15 @@ dnl check for kvm headers
dnl
AC_CHECK_HEADERS([linux/kvm.h])
+dnl OpenNebula driver Compilation setting
+dnl
+
+if test "$with_one" = "yes" ; then
+ CFLAGS="$CFLAGS -I$ONE_LOCATION/include"
+ ONE_LIBS="-L/usr/local/lib -lxmlrpc_client++ -lxmlrpc -lxmlrpc_util -lxmlrpc_xmlparse -lxmlrpc_xmltok -lxmlrpc++ -lxmlrpc_client -L$ONE_LOCATION/lib -loneapi"
+ AC_SUBST([ONE_LIBS])
+fi
+
dnl Need to test if pkg-config exists
PKG_PROG_PKG_CONFIG
@@ -1372,6 +1388,7 @@ AC_MSG_NOTICE([ UML: $with_uml])
AC_MSG_NOTICE([ OpenVZ: $with_openvz])
AC_MSG_NOTICE([ VBox: $with_vbox])
AC_MSG_NOTICE([ LXC: $with_lxc])
+AC_MSG_NOTICE([ ONE: $with_one])
AC_MSG_NOTICE([ Test: $with_test])
AC_MSG_NOTICE([ Remote: $with_remote])
AC_MSG_NOTICE([ Network: $with_network])
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index faf3f61..abe54b2 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -63,6 +63,7 @@ typedef enum {
VIR_FROM_XEN_INOTIFY, /* Error from xen inotify layer */
VIR_FROM_SECURITY, /* Error from security framework */
VIR_FROM_VBOX, /* Error from VirtualBox driver */
+ VIR_FROM_ONE, /* Error from ONE driver */
} virErrorDomain;
diff --git a/qemud/Makefile.am b/qemud/Makefile.am
index 924e8ad..9d7f61f 100644
--- a/qemud/Makefile.am
+++ b/qemud/Makefile.am
@@ -120,6 +120,10 @@ if WITH_UML
libvirtd_LDADD += ../src/libvirt_driver_uml.la
endif
+if WITH_ONE
+ libvirtd_LDADD += ../src/libvirt_driver_one.la
+endif
+
if WITH_STORAGE_DIR
libvirtd_LDADD += ../src/libvirt_driver_storage.la
endif
diff --git a/qemud/qemud.c b/qemud/qemud.c
index 829a4bc..a069f38 100644
--- a/qemud/qemud.c
+++ b/qemud/qemud.c
@@ -75,6 +75,9 @@
#ifdef WITH_UML
#include "uml_driver.h"
#endif
+#ifdef WITH_ONE
+#include "opennebula/one_driver.h"
+#endif
#ifdef WITH_NETWORK
#include "network_driver.h"
#endif
@@ -841,6 +844,7 @@ static struct qemud_server *qemudInitialize(int sigread) {
virDriverLoadModule("qemu");
virDriverLoadModule("lxc");
virDriverLoadModule("uml");
+ virDriverLoadModule("one");
#else
#ifdef WITH_NETWORK
networkRegister();
@@ -861,6 +865,9 @@ static struct qemud_server *qemudInitialize(int sigread) {
#ifdef WITH_UML
umlRegister();
#endif
+#ifdef WITH_ONE
+ oneRegister();
+#endif
#endif
virEventRegisterImpl(virEventAddHandleImpl,
diff --git a/src/Makefile.am b/src/Makefile.am
index fd692b4..17ae0e7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -144,6 +144,12 @@ UML_DRIVER_SOURCES = \
uml_conf.c uml_conf.h \
uml_driver.c uml_driver.h
+ONE_DRIVER_SOURCES = \
+ ./opennebula/one_conf.c \
+ ./opennebula/one_conf.h \
+ ./opennebula/one_driver.c \
+ ./opennebula/one_driver.h
+
NETWORK_DRIVER_SOURCES = \
network_driver.h network_driver.c
@@ -337,6 +342,25 @@ endif
libvirt_driver_uml_la_SOURCES = $(UML_DRIVER_SOURCES)
endif
+if WITH_ONE
+if WITH_DRIVER_MODULES
+mod_LTLIBRARIES += libvirt_driver_one.la
+else
+noinst_LTLIBRARIES += libvirt_driver_one.la
+# Stateful, so linked to daemon instead
+#libvirt_la_LIBADD += libvirt_driver_one.la
+endif
+libvirt_driver_one_la_LDFLAGS = $(ONE_LIBS)
+
+if WITH_DRIVER_MODULES
+libvirt_driver_one_la_LDFLAGS += -module -avoid-version
+endif
+libvirt_driver_one_la_SOURCES = $(ONE_DRIVER_SOURCES)
+endif
+
+
+
+
if WITH_NETWORK
if WITH_DRIVER_MODULES
mod_LTLIBRARIES += libvirt_driver_network.la
@@ -429,6 +453,7 @@ EXTRA_DIST += \
$(QEMU_DRIVER_SOURCES) \
$(LXC_DRIVER_SOURCES) \
$(UML_DRIVER_SOURCES) \
+ $(ONE_DRIVER_SOURCES) \
$(OPENVZ_DRIVER_SOURCES) \
$(VBOX_DRIVER_SOURCES) \
$(NETWORK_DRIVER_SOURCES) \
diff --git a/src/domain_conf.c b/src/domain_conf.c
index 648d9e9..06b9713 100644
--- a/src/domain_conf.c
+++ b/src/domain_conf.c
@@ -55,7 +55,8 @@ VIR_ENUM_IMPL(virDomainVirt, VIR_DOMAIN_VIRT_LAST,
"test",
"vmware",
"hyperv",
- "vbox")
+ "vbox",
+ "one")
VIR_ENUM_IMPL(virDomainBoot, VIR_DOMAIN_BOOT_LAST,
"fd",
diff --git a/src/domain_conf.h b/src/domain_conf.h
index f4eea6b..c91a245 100644
--- a/src/domain_conf.h
+++ b/src/domain_conf.h
@@ -49,6 +49,7 @@ enum virDomainVirtType {
VIR_DOMAIN_VIRT_VMWARE,
VIR_DOMAIN_VIRT_HYPERV,
VIR_DOMAIN_VIRT_VBOX,
+ VIR_DOMAIN_VIRT_ONE,
VIR_DOMAIN_VIRT_LAST,
};
diff --git a/src/driver.h b/src/driver.h
index 39dc413..5685783 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -21,6 +21,7 @@ typedef enum {
VIR_DRV_LXC = 6,
VIR_DRV_UML = 7,
VIR_DRV_VBOX = 8,
+ VIR_DRV_ONE = 9,
} virDrvNo;
diff --git a/src/libvirt.c b/src/libvirt.c
index 95a861e..4b1610a 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -845,6 +845,10 @@ virGetVersion(unsigned long *libVer, const char *type,
if (STRCASEEQ(type, "UML"))
*typeVer = LIBVIR_VERSION_NUMBER;
#endif
+#if WITH_ONE
+ if (STRCASEEQ(type, "ONE"))
+ *typeVer = LIBVIR_VERSION_NUMBER;
+#endif
#if WITH_REMOTE
if (STRCASEEQ(type, "Remote"))
*typeVer = remoteVersion();
diff --git a/src/virterror.c b/src/virterror.c
index 2d34ed7..d4b429c 100644
--- a/src/virterror.c
+++ b/src/virterror.c
@@ -156,6 +156,8 @@ static const char *virErrorDomainName(virErrorDomain domain) {
break;
case VIR_FROM_VBOX:
dom = "VBOX ";
+ case VIR_FROM_ONE:
+ dom = "ONE ";
break;
}
return(dom);
----
Distributed System Architecture Group
(http://dsa-research.org)
GridWay, http://www.gridway.org
OpenNEbula, http://www.opennebula.org
15 years, 6 months
[libvirt] PATCH: Enable migration with QEMU >= 0.10.0
by Daniel P. Berrange
The KVM migration code was added to QEMU for the 0.10.0 release, so we
should enable this in libvirt now.
Daniel
diff -r be7993675e07 src/qemu_conf.c
--- a/src/qemu_conf.c Thu Apr 30 14:49:27 2009 +0100
+++ b/src/qemu_conf.c Thu Apr 30 15:08:45 2009 +0100
@@ -473,16 +473,13 @@ int qemudExtractVersionInfo(const char *
/*
* Handling of -incoming arg with varying features
- * -incoming tcp (kvm >= 79)
- * -incoming exec (kvm >= 80)
+ * -incoming tcp (kvm >= 79, qemu >= 0.10.0)
+ * -incoming exec (kvm >= 80, qemu >= 0.10.0)
* -incoming stdio (all earlier kvm)
*
* NB, there was a pre-kvm-79 'tcp' support, but it
* was broken, because it blocked the monitor console
* while waiting for data, so pretend it doesn't exist
- *
- * XXX when next QEMU release after 0.9.1 arrives,
- * we'll need to add MIGRATE_QEMU_TCP/EXEC here too
*/
if (kvm_version >= 79) {
flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP;
@@ -490,6 +487,9 @@ int qemudExtractVersionInfo(const char *
flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC;
} else if (kvm_version > 0) {
flags |= QEMUD_CMD_FLAG_MIGRATE_KVM_STDIO;
+ } else if (version >= 10000) {
+ flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP;
+ flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC;
}
if (retversion)
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
15 years, 6 months
[libvirt] (no subject)
by Eduardo Otubo
Hello all,
I've been working on a libvirt extension to manage IBM's Power VMs
(LPARs). The Power systems are managed through management console
referred to as the HMC or using a management partition (IVM). Both HMC
and IVM runs an SSH, then you can reach it via command line, and an HTTP
server, then you can reach it via web browser.
The protocol between the console and the partition (LPAR) is not
disclosed, therefore I propose the driver to execute commands remoetly
over an SSH connection to the consoles to manage IBM LPARs.
The patch attached is the first scratch of the driver that will interact
with HMC over a SSH connection. The URI model that is
used in virsh command line is:
virsh --conect phyp://$user@$server
Some known issues are:
* Next step is to make the URI like this: phyp://$user@
$HMC/@managed_system. Almost finished. What it takes now is
$server = $HMC = $managed_system.
* Next features in my TODO list are "resume", "stop" and "reboot" the
LPAR.
Any comments are welcome.
Thanks,
--
Eduardo Otubo
Software Engineer
Linux Technology Center
IBM Systems & Technology Group
Mobile: +55 19 8135 0885
otubo(a)linux.vnet.ibm.com
15 years, 6 months
[libvirt] [PATCH] also enable bridges without IP address
by Ludwig Nussel
Bridges that are not up won't forward packets
Signed-off-by: Ludwig Nussel <ludwig.nussel(a)suse.de>
cu
Ludwig
---
src/network_driver.c | 9 +++------
1 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/src/network_driver.c b/src/network_driver.c
index a17a769..a163b15 100644
--- a/src/network_driver.c
+++ b/src/network_driver.c
@@ -836,8 +836,7 @@ static int networkStartNetworkDaemon(virConnectPtr conn,
goto err_delbr;
}
- if (network->def->ipAddress &&
- (err = brSetInterfaceUp(driver->brctl, network->def->bridge, 1))) {
+ if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 1))) {
virReportSystemError(conn, err,
_("failed to bring the bridge '%s' up"),
network->def->bridge);
@@ -878,8 +877,7 @@ static int networkStartNetworkDaemon(virConnectPtr conn,
networkRemoveIptablesRules(driver, network);
err_delbr1:
- if (network->def->ipAddress &&
- (err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) {
+ if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) {
char ebuf[1024];
networkLog(NETWORK_WARN, _("Failed to bring down bridge '%s' : %s\n"),
network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
@@ -920,8 +918,7 @@ static int networkShutdownNetworkDaemon(virConnectPtr conn,
networkRemoveIptablesRules(driver, network);
char ebuf[1024];
- if (network->def->ipAddress &&
- (err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) {
+ if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) {
networkLog(NETWORK_WARN, _("Failed to bring down bridge '%s' : %s\n"),
network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
}
--
1.6.2.1
15 years, 6 months
[libvirt] [PATCH 1/6] Allow multiple monitor devices (v2)
by Anthony Liguori
Right now only one monitor device can be enabled at a time. In order to support
asynchronous notification of events, I would like to introduce a 'wait' command
that waits for an event to occur. This implies that we need an additional
monitor session to allow commands to still be executed while waiting for an
asynchronous notification.
Signed-off-by: Anthony Liguori <aliguori(a)us.ibm.com>
diff --git a/vl.c b/vl.c
index 4bd173f..f78cabb 100644
--- a/vl.c
+++ b/vl.c
@@ -184,6 +184,9 @@ int main(int argc, char **argv)
/* Max number of bluetooth switches on the commandline. */
#define MAX_BT_CMDLINE 10
+/* Maximum number of monitor devices */
+#define MAX_MONITOR_DEVICES 10
+
/* XXX: use a two level table to limit memory usage */
#define MAX_IOPORTS 65536
@@ -4252,8 +4255,9 @@ int main(int argc, char **argv, char **envp)
int hda_index;
int optind;
const char *r, *optarg;
- CharDriverState *monitor_hd = NULL;
- const char *monitor_device;
+ CharDriverState *monitor_hds[MAX_MONITOR_DEVICES];
+ const char *monitor_devices[MAX_MONITOR_DEVICES];
+ int monitor_device_index;
const char *serial_devices[MAX_SERIAL_PORTS];
int serial_device_index;
const char *parallel_devices[MAX_PARALLEL_PORTS];
@@ -4324,7 +4328,6 @@ int main(int argc, char **argv, char **envp)
kernel_cmdline = "";
cyls = heads = secs = 0;
translation = BIOS_ATA_TRANSLATION_AUTO;
- monitor_device = "vc:80Cx24C";
serial_devices[0] = "vc:80Cx24C";
for(i = 1; i < MAX_SERIAL_PORTS; i++)
@@ -4340,6 +4343,11 @@ int main(int argc, char **argv, char **envp)
virtio_consoles[i] = NULL;
virtio_console_index = 0;
+ monitor_devices[0] = "vc:80Cx24C";
+ for (i = 1; i < MAX_MONITOR_DEVICES; i++)
+ monitor_devices[i] = NULL;
+ monitor_device_index = 0;
+
usb_devices_index = 0;
nb_net_clients = 0;
@@ -4723,7 +4731,12 @@ int main(int argc, char **argv, char **envp)
break;
}
case QEMU_OPTION_monitor:
- monitor_device = optarg;
+ if (monitor_device_index >= MAX_MONITOR_DEVICES) {
+ fprintf(stderr, "qemu: too many monitor devices\n");
+ exit(1);
+ }
+ monitor_devices[monitor_device_index] = optarg;
+ monitor_device_index++;
break;
case QEMU_OPTION_serial:
if (serial_device_index >= MAX_SERIAL_PORTS) {
@@ -4974,8 +4987,8 @@ int main(int argc, char **argv, char **envp)
serial_devices[0] = "stdio";
if (parallel_device_index == 0)
parallel_devices[0] = "null";
- if (strncmp(monitor_device, "vc", 2) == 0)
- monitor_device = "stdio";
+ if (strncmp(monitor_devices[0], "vc", 2) == 0)
+ monitor_devices[0] = "stdio";
}
#ifndef _WIN32
@@ -5184,14 +5197,14 @@ int main(int argc, char **argv, char **envp)
#endif
/* Maintain compatibility with multiple stdio monitors */
- if (!strcmp(monitor_device,"stdio")) {
+ if (!strcmp(monitor_devices[0],"stdio")) {
for (i = 0; i < MAX_SERIAL_PORTS; i++) {
const char *devname = serial_devices[i];
if (devname && !strcmp(devname,"mon:stdio")) {
- monitor_device = NULL;
+ monitor_devices[0] = NULL;
break;
} else if (devname && !strcmp(devname,"stdio")) {
- monitor_device = NULL;
+ monitor_devices[0] = NULL;
serial_devices[i] = "mon:stdio";
break;
}
@@ -5208,11 +5221,20 @@ int main(int argc, char **argv, char **envp)
}
}
- if (monitor_device) {
- monitor_hd = qemu_chr_open("monitor", monitor_device, NULL);
- if (!monitor_hd) {
- fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device);
- exit(1);
+ for (i = 0; i < MAX_MONITOR_DEVICES; i++) {
+ const char *devname = monitor_devices[i];
+ if (devname && strcmp(devname, "none")) {
+ char label[32];
+ if (i == 0)
+ snprintf(label, sizeof(label), "monitor");
+ else
+ snprintf(label, sizeof(label), "monitor%d", i);
+ monitor_hds[i] = qemu_chr_open(label, devname, NULL);
+ if (!monitor_hds[i]) {
+ fprintf(stderr, "qemu: could not open monitor device '%s'\n",
+ devname);
+ exit(1);
+ }
}
}
@@ -5335,8 +5357,13 @@ int main(int argc, char **argv, char **envp)
text_consoles_set_display(display_state);
qemu_chr_initial_reset();
- if (monitor_device && monitor_hd)
- monitor_init(monitor_hd, MONITOR_USE_READLINE | MONITOR_IS_DEFAULT);
+ for (i = 0; i < MAX_MONITOR_DEVICES; i++) {
+ if (monitor_devices[i] && monitor_hds[i]) {
+ monitor_init(monitor_hds[i],
+ MONITOR_USE_READLINE |
+ ((i == 0) ? MONITOR_IS_DEFAULT : 0));
+ }
+ }
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
const char *devname = serial_devices[i];
15 years, 6 months
[libvirt] [PATCH 2/2] support for multiple graphics devices
by Pritesh Kothari
Hi All,
I have added support for multiple graphics devices, the patches are as below.
I have checked them against current cvs head and works fine
PATCH 1/2: contains changes in libvirt for multiple graphics devices
PATCH 2/2: contains corresponding changes in qemu driver.
Regards,
Pritesh
15 years, 6 months
[libvirt] PATCH: Raise log level for dlopen() problems
by Daniel P. Berrange
Some of the problems when dlopen'ing a module really should be reported to
the user/admin more readily. So this raises the logging level for the
important failure messages, so they're visible by default
Daniel
diff -r 15c4668d403b src/driver.c
--- a/src/driver.c Wed Apr 29 15:29:17 2009 +0100
+++ b/src/driver.c Thu Apr 30 14:49:27 2009 +0100
@@ -54,13 +54,13 @@ virDriverLoadModule(const char *name)
return NULL;
if (access(modfile, R_OK) < 0) {
- DEBUG("Moodule %s not accessible", modfile);
+ VIR_WARN("Module %s not accessible", modfile);
goto cleanup;
}
handle = dlopen(modfile, RTLD_NOW | RTLD_LOCAL);
if (!handle) {
- DEBUG("failed to load module %s %s", modfile, dlerror());
+ VIR_ERROR("failed to load module %s %s", modfile, dlerror());
goto cleanup;
}
@@ -70,12 +70,12 @@ virDriverLoadModule(const char *name)
regsym = dlsym(handle, regfunc);
if (!regsym) {
- DEBUG("Missing module registration symbol %s", regfunc);
+ VIR_ERROR("Missing module registration symbol %s", regfunc);
goto cleanup;
}
if ((*regsym)() < 0) {
- DEBUG("Failed module registration %s", regfunc);
+ VIR_ERROR("Failed module registration %s", regfunc);
goto cleanup;
}
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
15 years, 6 months