[Ovirt-devel] [PATCH] Refactored ovirt-identify, and added NIC info during the identify phase.

Darryl L. Pierce dpierce at redhat.com
Mon Jul 21 20:14:48 UTC 2008


The identify phase now gathers the details for each physical NIC on the
managed node and submits that back to the server along with the CPU
details.

The code is now broken out into several source modules to make the code
easier to maintain. The source files include:
 * comm.c        - code for establishing a connection with the server
 * debug.c       - code for displaying debug information
 * gather.c      - code for collecting the various hardware details
 * hal_support.c - code for working with HAL
 * main.c        - main entry point and variable declarations.
 * protocol.c    - code to handle data exchange with the server

Signed-off-by: Darryl L. Pierce <dpierce at redhat.com>
---
 ovirt-managed-node/ovirt-managed-node.spec         |    2 +
 ovirt-managed-node/src/Makefile                    |    6 +-
 ovirt-managed-node/src/comm.c                      |   85 +++
 ovirt-managed-node/src/debug.c                     |   50 ++
 ovirt-managed-node/src/gather.c                    |  284 +++++++++
 ovirt-managed-node/src/hal_support.c               |   61 ++
 ovirt-managed-node/src/main.c                      |  242 ++++++++
 ovirt-managed-node/src/ovirt-identify-node.c       |  653 --------------------
 ovirt-managed-node/src/ovirt-identify-node.h       |  123 +++-
 ovirt-managed-node/src/protocol.c                  |  272 ++++++++
 ovirt-managed-node/src/scripts/ovirt-post          |    8 +-
 wui/src/host-browser/host-browser.rb               |   84 +++-
 wui/src/host-browser/test-host-browser-identify.rb |   42 ++-
 13 files changed, 1222 insertions(+), 690 deletions(-)
 create mode 100644 ovirt-managed-node/src/comm.c
 create mode 100644 ovirt-managed-node/src/debug.c
 create mode 100644 ovirt-managed-node/src/gather.c
 create mode 100644 ovirt-managed-node/src/hal_support.c
 create mode 100644 ovirt-managed-node/src/main.c
 delete mode 100644 ovirt-managed-node/src/ovirt-identify-node.c
 create mode 100644 ovirt-managed-node/src/protocol.c

diff --git a/ovirt-managed-node/ovirt-managed-node.spec b/ovirt-managed-node/ovirt-managed-node.spec
index 4e14b08..0cd3aa8 100644
--- a/ovirt-managed-node/ovirt-managed-node.spec
+++ b/ovirt-managed-node/ovirt-managed-node.spec
@@ -12,7 +12,9 @@ URL:            http://www.ovirt.org/
 Requires(post):  /sbin/chkconfig
 Requires(preun): /sbin/chkconfig
 BuildRequires:  libvirt-devel
+BuildRequires:  dbus-devel hal-devel
 Requires:       libvirt
+Requires:       hal
 ExclusiveArch:  %{ix86} x86_64
 
 %define app_root %{_datadir}/%{name}
diff --git a/ovirt-managed-node/src/Makefile b/ovirt-managed-node/src/Makefile
index 1991e46..d5e4093 100644
--- a/ovirt-managed-node/src/Makefile
+++ b/ovirt-managed-node/src/Makefile
@@ -17,9 +17,9 @@
 # also available at http://www.gnu.org/copyleft/gpl.html.
 
 CC=gcc
-CFLAGS=-Wall -c -g
-LFLAGS=-lvirt
-OBJECTS=ovirt-identify-node.o
+CFLAGS=-Wall -c -g $(shell pkg-config --cflags dbus-1)
+LFLAGS=-lhal -lvirt
+OBJECTS=comm.o gather.o hal_support.o main.o protocol.o
 TARGET=ovirt-identify-node
 SOURCES=\
 	ovirt-identify-node.c
diff --git a/ovirt-managed-node/src/comm.c b/ovirt-managed-node/src/comm.c
new file mode 100644
index 0000000..16dc3b8
--- /dev/null
+++ b/ovirt-managed-node/src/comm.c
@@ -0,0 +1,85 @@
+
+/* comm.c -- Contains communications routines.
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.  A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "ovirt-identify-node.h"
+
+ssize_t
+saferead(int fd, char *buf, size_t count)
+{
+    ssize_t bytes, offset;
+
+    int len_left;
+
+    int done = 0;
+
+    offset = 0;
+
+    len_left = count;
+
+    DEBUG("Begin saferead(%d, %p, %d)\n", fd, buf, count);
+
+    while (!done) {
+        DEBUG("Before read(%d,%p,%d)\n", fd, buf + offset, len_left);
+
+        bytes = read(fd, buf + offset, len_left);
+
+        DEBUG("After read: bytes=%d\n", bytes);
+
+        if (bytes == 0) {
+            done = 1;
+        } else if (bytes > 0) {
+            offset += bytes;
+            len_left -= bytes;
+            done = 1;
+        } else if (errno == EINTR) {
+            continue;
+        } else {
+            done = 1;
+        }
+
+        DEBUG("End of decision loop: offset=%d, len_left=%dl, done=%d\n",
+              offset, len_left, done);
+    }
+
+    return offset;
+}
+
+ssize_t
+safewrite(int fd, const void *buf, size_t count)
+{
+    size_t nwritten = 0;
+
+    while (count > 0) {
+        ssize_t r = write(fd, buf, count);
+
+        if (r < 0 && errno == EINTR)
+            continue;
+        if (r < 0)
+            return r;
+        if (r == 0)
+            return nwritten;
+        buf = (const char *) buf + r;
+        count -= r;
+        nwritten += r;
+    }
+    return nwritten;
+}
diff --git a/ovirt-managed-node/src/debug.c b/ovirt-managed-node/src/debug.c
new file mode 100644
index 0000000..36a7f59
--- /dev/null
+++ b/ovirt-managed-node/src/debug.c
@@ -0,0 +1,50 @@
+
+/* debug.c -- Debugging methods.
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.  A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "ovirt-identify-node.h"
+
+void
+debug_cpu_info(void)
+{
+    fprintf(stdout, "Node Info:\n");
+    fprintf(stdout, "     UUID: %s\n", uuid);
+    fprintf(stdout, "     Arch: %s\n", arch);
+    fprintf(stdout, "   Memory: %s\n", memsize);
+
+    cpu_info_ptr current = cpu_info;
+
+    while (current != NULL) {
+        fprintf(stdout, "\n");
+        fprintf(stdout, "     CPU Number: %s\n", current->cpu_num);
+        fprintf(stdout, "    Core Number: %s\n", current->core_num);
+        fprintf(stdout, "Number of Cores: %s\n", current->number_of_cores);
+        fprintf(stdout, "         Vendor: %s\n", current->vendor);
+        fprintf(stdout, "          Model: %s\n", current->model);
+        fprintf(stdout, "         Family: %s\n", current->family);
+        fprintf(stdout, "    CPUID Level: %s\n", current->cpuid_level);
+        fprintf(stdout, "      CPU Speed: %s\n", current->speed);
+        fprintf(stdout, "     Cache Size: %s\n", current->cache);
+        fprintf(stdout, "      CPU Flags: %s\n", current->flags);
+
+        current = current->next;
+    }
+}
diff --git a/ovirt-managed-node/src/gather.c b/ovirt-managed-node/src/gather.c
new file mode 100644
index 0000000..39be6fd
--- /dev/null
+++ b/ovirt-managed-node/src/gather.c
@@ -0,0 +1,284 @@
+
+/* gather.c -- Contains methods for collecting data about the system.
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.  A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "ovirt-identify-node.h"
+
+int
+init_gather(void)
+{
+    int result = 1;
+
+    hal_ctx = get_hal_ctx();
+
+    if (hal_ctx != NULL) {
+        result = 0;
+    }
+
+    return result;
+}
+
+int
+get_uuid(void)
+{
+    const char *udi = "/org/freedesktop/Hal/devices/computer";
+
+    const char *key = "system.hardware.uuid";
+
+    VERBOSE("Getting system UUID.\n");
+
+    int result = 1;
+
+    int type;
+
+    type = libhal_device_get_property_type(hal_ctx, udi, key, &dbus_error);
+
+    if (type == LIBHAL_PROPERTY_TYPE_STRING) {
+        char *value;
+
+        DEBUG("%s/%s=%d\n", udi, key, type);
+
+        value =
+            libhal_device_get_property_string(hal_ctx, udi, key,
+                                              &dbus_error);
+        snprintf(uuid, BUFFER_LENGTH, "%s", value);
+
+        DEBUG("UUID=%s\n", uuid);
+
+        result = 0;
+    }
+
+    return result;
+}
+
+/* Creates a new instance of type t_cpu_info and places it into the
+ * linked list of CPUs.
+ */
+cpu_info_ptr
+create_cpu_info(void)
+{
+    cpu_info_ptr result = calloc(1, sizeof(t_cpu_info));
+
+    bzero(result, sizeof(t_cpu_info));
+
+    strcpy(result->core_num, "0");
+    strcpy(result->number_of_cores, "1");
+
+    return result;
+}
+
+int
+get_cpu_info(void)
+{
+    int result = 1;
+
+    FILE *inputfd;
+
+    cpu_info_ptr current = NULL;
+
+    /* in order to support Xen, this data will need to be gathered
+     * from libvirt rather than directly from cpuinfo
+     */
+    if ((inputfd = fopen("/proc/cpuinfo", "rb")) != NULL) {
+        VERBOSE("Parsing CPU information\n");
+        do {
+            char buffer[255];
+
+            char label[BUFFER_LENGTH];
+
+            char value[BUFFER_LENGTH];
+
+            fgets(buffer, 255, inputfd);
+            if (strlen(buffer) > 0)
+                buffer[strlen(buffer) - 1] = '\0';
+
+            get_label_and_value(buffer,
+                                label, BUFFER_LENGTH,
+                                value, BUFFER_LENGTH);
+
+            DEBUG("label=\"%s\", value=\"%s\"\n", label, value);
+
+            if (strlen(label)) {
+                if (!strcmp(label, "processor")) {
+                    VERBOSE("Starting new CPU\n");
+
+                    cpu_info_ptr last = current;
+
+                    current = create_cpu_info();
+                    if (last != NULL) {
+                        last->next = current;
+                    } else {
+                        cpu_info = current;
+                    }
+
+                    COPY_VALUE_TO_BUFFER(value, current->cpu_num,
+                                         BUFFER_LENGTH);
+                } else
+                    /* core id and number of cores is not correct on
+                     * Xen machines
+                     */
+                if (!strcmp(label, "core id")) {
+                    COPY_VALUE_TO_BUFFER(value, current->core_num,
+                                         BUFFER_LENGTH);
+                } else if (!strcmp(label, "cpu cores")) {
+                    COPY_VALUE_TO_BUFFER(value, current->number_of_cores,
+                                         BUFFER_LENGTH);
+                } else if (!strcmp(label, "vendor_id")) {
+                    COPY_VALUE_TO_BUFFER(value, current->vendor,
+                                         BUFFER_LENGTH);
+                } else if (!strcmp(label, "model")) {
+                    COPY_VALUE_TO_BUFFER(value, current->model,
+                                         BUFFER_LENGTH);
+                } else if (!strcmp(label, "cpu family")) {
+                    COPY_VALUE_TO_BUFFER(value, current->family,
+                                         BUFFER_LENGTH);
+                } else if (!strcmp(label, "cpuid level")) {
+                    COPY_VALUE_TO_BUFFER(value, current->cpuid_level,
+                                         BUFFER_LENGTH);
+                } else if (!strcmp(label, "cpu MHz")) {
+                    COPY_VALUE_TO_BUFFER(value, current->speed,
+                                         BUFFER_LENGTH);
+                } else if (!strcmp(label, "cache size")) {
+                    COPY_VALUE_TO_BUFFER(value, current->cache,
+                                         BUFFER_LENGTH);
+                } else if (!strcmp(label, "flags")) {
+                    COPY_VALUE_TO_BUFFER(value, current->flags,
+                                         BUFFER_LENGTH);
+                }
+            }
+
+        } while (!feof(inputfd));
+
+        fclose(inputfd);
+
+        result = 0;
+    } else {
+        VERBOSE("Unable to open /proc/cpuinfo\n");
+    }
+
+    return result;
+}
+
+/* Creates a new instance of type t_nic_info.
+ */
+nic_info_ptr
+create_nic_info(void)
+{
+    nic_info_ptr result = calloc(1, sizeof(t_nic_info));
+
+    bzero(result, sizeof(t_nic_info));
+
+    return result;
+}
+
+/* Determines the speed of the network interface.
+ */
+void
+get_nic_data(char *nic, nic_info_ptr nic_info)
+{
+    char *interface;
+
+    struct ifreq ifr;
+
+    int sockfd;
+
+    struct ethtool_cmd ecmd;
+
+    interface =
+        libhal_device_get_property_string(hal_ctx, nic, "net.interface",
+                                          &dbus_error);
+    bzero(&ifr, sizeof(struct ifreq));
+
+    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (sockfd >= 0) {
+        int bandwidth;
+
+        ifr.ifr_addr.sa_family = AF_INET;
+        strncpy(ifr.ifr_name, interface, IFNAMSIZ - 1);
+
+        ioctl(sockfd, SIOCETHTOOL, &ifr);
+        close(sockfd);
+
+        bandwidth = 10;
+        if (ecmd.supported & SUPPORTED_10000baseT_Full)
+            bandwidth = 10000;
+        else if (ecmd.supported & SUPPORTED_2500baseX_Full)
+            bandwidth = 2500;
+        else if (ecmd.supported & (SUPPORTED_1000baseT_Half |
+                                   SUPPORTED_1000baseT_Full))
+            bandwidth = 1000;
+        else if (ecmd.supported & (SUPPORTED_100baseT_Half |
+                                   SUPPORTED_100baseT_Full))
+            bandwidth = 100;
+        else if (ecmd.supported & (SUPPORTED_10baseT_Half |
+                                   SUPPORTED_10baseT_Full))
+            bandwidth = 10;
+
+        snprintf(nic_info->bandwidth, BUFFER_LENGTH, "%d", bandwidth);
+    }
+}
+
+int
+get_nic_info(void)
+{
+    int result = 0;
+
+    nic_info_ptr current = NULL;
+
+    nic_info_ptr last = NULL;
+
+    char **nics;
+
+    int num_results;
+
+    int index;
+
+    nics = libhal_find_device_by_capability(hal_ctx, "net",
+                                            &num_results, &dbus_error);
+
+    DEBUG("Found %d NICs\n", num_results);
+
+    for (index = 0; index < num_results; index++) {
+        char *nic = nics[index];
+
+        VERBOSE("Starting new NIC.\n");
+
+        if (current != NULL) {
+            last = current;
+            current = create_nic_info();
+            last->next = current;
+        } else {
+            nic_info = current = create_nic_info();
+        }
+
+        snprintf(current->mac_address, BUFFER_LENGTH, "%s",
+                 libhal_device_get_property_string(hal_ctx, nic,
+                                                   "net.address",
+                                                   &dbus_error));
+        get_nic_data(nic, current);
+
+        DEBUG("NIC details: MAC:%s, speed:%s, IP:%s\n",
+              nic_info->mac_address, nic_info->bandwidth,
+              nic_info->ip_address);
+    }
+
+    return result;
+}
diff --git a/ovirt-managed-node/src/hal_support.c b/ovirt-managed-node/src/hal_support.c
new file mode 100644
index 0000000..1b1d0ca
--- /dev/null
+++ b/ovirt-managed-node/src/hal_support.c
@@ -0,0 +1,61 @@
+
+/* hal_support.c -- Interfaces with the HAL libraries.
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.  A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "ovirt-identify-node.h"
+
+DBusConnection *dbus_connection;
+
+DBusError dbus_error;
+
+LibHalContext *
+get_hal_ctx(void)
+{
+    LibHalContext *result = NULL;
+
+    LibHalContext *ctx;
+
+    ctx = libhal_ctx_new();
+    if (ctx != NULL) {
+        dbus_error_init(&dbus_error);
+        dbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error);
+
+        if (!dbus_error_is_set(&dbus_error)) {
+            libhal_ctx_set_dbus_connection(ctx, dbus_connection);
+
+            if (libhal_ctx_init(ctx, &dbus_error)) {
+                result = ctx;
+            } else {
+                fprintf(stderr,
+                        "Failed to initial libhal context: %s : %s\n",
+                        dbus_error.name, dbus_error.message);
+            }
+        } else {
+            fprintf(stderr, "Unable to connect to system bus: %s : %s\n",
+                    dbus_error.name, dbus_error.message);
+            dbus_error_free(&dbus_error);
+        }
+    } else {
+        fprintf(stderr, "Unable to initialize HAL context.\n");
+    }
+
+    return result;
+}
diff --git a/ovirt-managed-node/src/main.c b/ovirt-managed-node/src/main.c
new file mode 100644
index 0000000..696571b
--- /dev/null
+++ b/ovirt-managed-node/src/main.c
@@ -0,0 +1,242 @@
+
+/* identify-node -- Main entry point for the identify-node utility.
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.  A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "ovirt-identify-node.h"
+
+int debug = 0;
+
+int verbose = 0;
+
+int testing = 0;
+
+char arch[BUFFER_LENGTH];
+
+char uuid[BUFFER_LENGTH];
+
+char memsize[BUFFER_LENGTH];
+
+char numcpus[BUFFER_LENGTH];
+
+char cpuspeed[BUFFER_LENGTH];
+
+char *hostname;
+
+int hostport = -1;
+
+int socketfd;
+
+cpu_info_ptr cpu_info;
+
+nic_info_ptr nic_info;
+
+LibHalContext *hal_ctx;
+
+int
+main(int argc, char **argv)
+{
+    int result = 1;
+
+    virConnectPtr connection;
+
+    virNodeInfo info;
+
+    fprintf(stdout, "Sending managed node details to server.\n");
+
+    if (!config(argc, argv)) {
+        VERBOSE("Connecting to libvirt.\n");
+
+        connection =
+            virConnectOpenReadOnly(testing ? "test:///default" : NULL);
+
+        DEBUG("connection=%p\n", connection);
+
+        if (connection) {
+            VERBOSE("Retrieving node information.\n");
+            if (!virNodeGetInfo(connection, &info)) {
+                snprintf(arch, BUFFER_LENGTH, "%s", info.model);
+                snprintf(memsize, BUFFER_LENGTH, "%ld", info.memory);
+
+                cpu_info = NULL;
+                nic_info = NULL;
+
+                if (!init_gather() && !get_uuid() && !get_cpu_info()
+                    && !get_nic_info()) {
+                    if (!start_conversation() && !send_details()
+                        && !end_conversation()) {
+                        fprintf(stdout, "Finished!\n");
+                        result = 0;
+                    }
+                } else {
+                    VERBOSE("Failed to get CPU info.\n");
+                }
+            } else {
+                VERBOSE("Failed to get node info.\n");
+            }
+        } else {
+            VERBOSE("Could not connect to libvirt.\n");
+        }
+    } else {
+        usage();
+    }
+
+    return result;
+}
+
+int
+config(int argc, char **argv)
+{
+    int result = 0;
+
+    int option;
+
+    while ((option = getopt(argc, argv, "s:p:dvth")) != -1) {
+        DEBUG("Processing argument: %c (optarg:%s)\n", option, optarg);
+
+        switch (option) {
+            case 's':
+                hostname = optarg;
+                break;
+            case 'p':
+                hostport = atoi(optarg);
+                break;
+            case 't':
+                testing = 1;
+                break;
+            case 'd':
+                debug = 1;
+                break;
+            case 'v':
+                verbose = 1;
+                break;
+            case 'h':
+                // fall thru
+            default:
+                result = 1;
+                break;
+        }
+    }
+
+    // verify that required options are provided
+    if (hostname == NULL || strlen(hostname) == 0) {
+        fprintf(stderr,
+                "ERROR: The server name is required. (-s [hostname])\n");
+        result = 1;
+    }
+
+    if (hostport <= 0) {
+        fprintf(stderr,
+                "ERROR: The server port is required. (-p [port])\n");
+        result = 1;
+    }
+
+    return result;
+}
+
+void
+usage()
+{
+    fprintf(stdout, "\n");
+    fprintf(stdout, "Usage: ovirt-identify [OPTION]\n");
+    fprintf(stdout, "\n");
+    fprintf(stdout, "\t-s [server]\t\tThe remote server's hostname.\n");
+    fprintf(stdout, "\t-p [port]\t\tThe remote server's port.\n");
+    fprintf(stdout,
+            "\t-d\t\tDisplays debug information during execution.\n");
+    fprintf(stdout,
+            "\t-v\t\tDisplays verbose information during execution.\n");
+    fprintf(stdout,
+            "\t-h\t\tDisplays this help information and then exits.\n");
+    fprintf(stdout, "\n");
+}
+
+void
+get_label_and_value(char *text,
+                    char *label, size_t label_length,
+                    char *value, size_t value_length)
+{
+    int offset = 0;
+
+    int which = 0;              /* 0 = label, 1 = value */
+
+    char *current = text;
+
+    /* iterate through the text supplied and find where the
+     * label ends with a colon, then copy that into the supplied
+     * label buffer and trim any trailing spaces
+     */
+
+    while (current != NULL && *current != '\0') {
+        /* if we're on the separator, then switch modes and reset
+         * the offset indicator, otherwise just process the character
+         */
+        if (which == 0 && *current == ':') {
+            which = 1;
+            offset = 0;
+        } else {
+            char *buffer = (which == 0 ? label : value);
+
+            int length = (which == 0 ? label_length : value_length);
+
+            /* only copy if we're past the first character and it's not
+             * a space
+             */
+            if ((offset > 0 || (*current != 9 && *current != ' '))
+                && offset < (length - 1)) {
+                buffer[offset++] = *current;
+                buffer[offset] = 0;
+            }
+        }
+
+        current++;
+    }
+
+    /* now trim all trailing spaces from the values */
+    while (label[strlen(label) - 1] == 9)
+        label[strlen(label) - 1] = 0;
+    while (value[strlen(value) - 1] == 9)
+        value[strlen(value) - 1] = 0;
+}
+
+int
+get_text(const char *const expected)
+{
+    int result = 1;
+
+    int received;
+
+    char buffer[BUFFER_LENGTH];
+
+    bzero(buffer, BUFFER_LENGTH);
+
+    VERBOSE("Looking to receive %s\n", expected);
+
+    received = saferead(socketfd, buffer, BUFFER_LENGTH);
+
+    buffer[received - 1] = 0;
+
+    VERBOSE("Received \"%s\": size=%d (trimmed ending carriage return)\n",
+            buffer, received);
+
+    result = strcmp(expected, buffer);
+
+    return result;
+}
diff --git a/ovirt-managed-node/src/ovirt-identify-node.c b/ovirt-managed-node/src/ovirt-identify-node.c
deleted file mode 100644
index f114d81..0000000
--- a/ovirt-managed-node/src/ovirt-identify-node.c
+++ /dev/null
@@ -1,653 +0,0 @@
-/* identify-node -- Main entry point for the identify-node utility.
- *
- * Copyright (C) 2008 Red Hat, Inc.
- * Written by Darryl L. Pierce <dpierce at redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA  02110-1301, USA.  A copy of the GNU General Public License is
- * also available at http://www.gnu.org/copyleft/gpl.html.
- */
-
-#include <errno.h>
-#include <getopt.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <libvirt/libvirt.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include "ovirt-identify-node.h"
-
-int main(int argc,char** argv)
-{
-    int result = 1;
-    virConnectPtr connection;
-    virNodeInfo info;
-
-    fprintf(stdout,"Sending managed node details to server.\n");
-
-    if(!config(argc,argv))
-    {
-        if(verbose)  fprintf(stdout,"Connecting to libvirt.\n");
-
-        connection = virConnectOpenReadOnly(testing ? "test:///default" : NULL);
-
-        if(debug) fprintf(stderr,"connection=%p\n",connection);
-
-        if(connection)
-        {
-            if(verbose) fprintf(stdout,"Getting hostname: %s\n", uuid);
-            if(!strlen(uuid)) gethostname(uuid,sizeof uuid);
-
-            if(verbose) fprintf(stdout,"Retrieving node information.\n");
-            if(!virNodeGetInfo(connection,&info))
-            {
-                snprintf(arch, BUFFER_LENGTH, "%s", info.model);
-                snprintf(memsize, BUFFER_LENGTH, "%ld", info.memory);
-
-                cpu_info = NULL;
-
-                if(!get_cpu_info())
-                {
-                    if(verbose) fprintf(stdout, "Getting CPU info.\n");
-
-                    if(debug)
-                    {
-                        fprintf(stdout,"Node Info:\n");
-                        fprintf(stdout,"     UUID: %s\n", uuid);
-                        fprintf(stdout,"     Arch: %s\n", arch);
-                        fprintf(stdout,"   Memory: %s\n", memsize);
-
-                        t_cpu_info* current = cpu_info;
-                        while(current != NULL)
-                        {
-                            fprintf(stdout,"\n");
-                            fprintf(stdout,"     CPU Number: %s\n", current->cpu_num);
-                            fprintf(stdout,"    Core Number: %s\n", current->core_num);
-                            fprintf(stdout,"Number of Cores: %s\n", current->number_of_cores);
-                            fprintf(stdout,"         Vendor: %s\n", current->vendor);
-                            fprintf(stdout,"          Model: %s\n", current->model);
-                            fprintf(stdout,"         Family: %s\n", current->family);
-                            fprintf(stdout,"    CPUID Level: %s\n", current->cpuid_level);
-                            fprintf(stdout,"      CPU Speed: %s\n", current->speed);
-                            fprintf(stdout,"     Cache Size: %s\n", current->cache);
-                            fprintf(stdout,"      CPU Flags: %s\n", current->flags);
-
-                            current = current->next;
-                        }
-                    }
-
-                    if(verbose) fprintf(stdout, "Retrieved node information.\n");
-
-                    if(!start_conversation() && !send_details() && !end_conversation())
-                    {
-                        fprintf(stdout,"Finished!\n");
-                        result = 0;
-                    }
-                }
-                else
-                {
-                    if(verbose) fprintf(stderr,"Failed to get CPU info.\n");
-                }
-            }
-            else
-            {
-                if(verbose) fprintf(stderr,"Failed to get node info.\n");
-            }
-        }
-        else
-        {
-            if(verbose) fprintf(stderr,"Could not connect to libvirt.\n");
-        }
-    }
-    else
-    {
-        usage();
-    }
-
-    return result;
-}
-
-int config(int argc,char** argv)
-{
-    int result = 0;
-    int option;
-
-    while((option = getopt(argc,argv,"s:p:u:dvth")) != -1)
-    {
-        if(debug) fprintf(stdout,"Processing argument: %c (optarg:%s)\n",option,optarg);
-
-        switch(option)
-        {
-            case 's': hostname = optarg; break;
-            case 'p': hostport = atoi(optarg); break;
-            case 'u': snprintf(uuid,VIR_UUID_BUFLEN,"%s",optarg); break;
-            case 't': testing  = 1; break;
-            case 'd': debug    = 1; break;
-            case 'v': verbose  = 1; break;
-            case 'h':
-            // fall thru
-            default : result   = 1; break;
-        }
-    }
-
-    // verify that required options are provided
-    if(hostname == NULL || strlen(hostname) == 0)
-    {
-        fprintf(stderr,"ERROR: The server name is required. (-s [hostname])\n");
-        result = 1;
-    }
-
-    if(hostport <= 0)
-    {
-        fprintf(stderr,"ERROR: The server port is required. (-p [port])\n");
-        result = 1;
-    }
-
-    return result;
-}
-
-void usage()
-{
-    fprintf(stdout,"\n");
-    fprintf(stdout,"Usage: ovirt-identify [OPTION]\n");
-    fprintf(stdout,"\n");
-    fprintf(stdout,"\t-s [server]\t\tThe remote server's hostname.\n");
-    fprintf(stdout,"\t-p [port]\t\tThe remote server's port.\n");
-    fprintf(stdout,"\t-d\t\tDisplays debug information during execution.\n");
-    fprintf(stdout,"\t-v\t\tDisplays verbose information during execution.\n");
-    fprintf(stdout,"\t-h\t\tDisplays this help information and then exits.\n");
-    fprintf(stdout,"\n");
-}
-
-int start_conversation(void)
-{
-    int result = 1;
-
-    if(verbose || debug) fprintf(stdout,"Starting conversation with %s:%d.\n",hostname,hostport);
-
-    if(!create_connection())
-    {
-        if(debug || verbose) fprintf(stdout,"Connected.\n");
-
-        if (!get_text("HELLO?"))
-        {
-            if(verbose) fprintf(stdout,"Checking for handshake.\n");
-
-            if(!send_text("HELLO!"))
-            {
-                if(verbose) fprintf(stdout,"Handshake received. Starting conversation.\n");
-
-                if(!get_text("MODE?"))
-                {
-                    if(verbose) fprintf(stdout,"Shifting to IDENTIFY mode.\n");
-
-                    if(!send_text("IDENTIFY")) result = 0;
-                }
-                else
-                {
-                    if(verbose) fprintf(stderr,"Was not asked for a mode.\n");
-                }
-            }
-        }
-        else
-        {
-            if(verbose) fprintf(stderr,"Did not receive a proper handshake.\n");
-        }
-    }
-
-    else
-    {
-        if(verbose) fprintf(stderr,"Did not get a connection.\n");
-    }
-
-    if(debug) fprintf(stdout,"start_conversation: result=%d\n", result);
-
-    return result;
-}
-
-int send_value(char* label,char* value)
-{
-    char buffer[BUFFER_LENGTH];
-    int result = 1;
-    char expected[BUFFER_LENGTH];
-
-    snprintf(buffer,BUFFER_LENGTH,"%s=%s", label, value);
-
-    if(!send_text(buffer))
-    {
-        snprintf(expected, BUFFER_LENGTH, "ACK %s", label);
-
-        if(verbose) fprintf(stdout,"Expecting \"%s\"\n", expected);
-
-        result = get_text(expected);
-    }
-
-    return result;
-}
-
-int send_details(void)
-{
-    int result = 1;
-
-    if(verbose) fprintf(stdout,"Sending node details.\n");
-
-    if (!get_text("INFO?"))
-    {
-        if((!send_value("ARCH",     arch))     &&
-           (!send_value("UUID",     uuid))     &&
-           (!send_value("MEMSIZE",  memsize))  &&
-           (!send_cpu_details()))
-        {
-            if(!send_text("ENDINFO")) result = 0;
-        }
-    }
-    else
-    {
-        if(verbose) fprintf(stdout,"Was not interrogated for hardware info.\n");
-    }
-
-    return result;
-}
-
-int send_cpu_details(void)
-{
-    int result = 1;
-    t_cpu_info* current = cpu_info;
-
-    while(current != NULL)
-    {
-        send_text("CPU");
-
-        if(!(get_text("CPUINFO?"))                              &&
-           (!send_value("CPUNUM",current->cpu_num))             &&
-           (!send_value("CORENUM",current->core_num))           &&
-           (!send_value("NUMCORES",current->number_of_cores))   &&
-           (!send_value("VENDOR",current->vendor))              &&
-           (!send_value("MODEL",current->model))                &&
-           (!send_value("FAMILY",current->family))              &&
-           (!send_value("CPUIDLVL",current->cpuid_level))       &&
-           (!send_value("SPEED",current->speed))                &&
-           (!send_value("CACHE", current->cache))               &&
-           (!send_value("FLAGS", current->flags)))
-            {
-                send_text("ENDCPU");
-                result = get_text("ACK CPU");
-            }
-
-        current = current->next;
-    }
-
-
-    return result;
-}
-
-int end_conversation(void)
-{
-    int result = 0;
-
-    if(debug || verbose) fprintf(stdout,"Ending conversation.\n");
-
-    send_text("ENDINFO");
-
-    close(socketfd);
-
-    return result;
-}
-
-void get_label_and_value(char* text,
-                         char* label, size_t label_length,
-                         char* value, size_t value_length)
-{
-    int   offset  = 0;
-    int   which   = 0; /* 0 = label, 1 = value */
-    char* current = text;
-
-    /* iterate through the text supplied and find where the
-     * label ends with a colon, then copy that into the supplied
-     * label buffer and trim any trailing spaces
-     */
-
-    while(current != NULL && *current != '\0')
-    {
-        /* if we're on the separator, then switch modes and reset
-         * the offset indicator, otherwise just process the character
-         */
-        if(which == 0 && *current == ':')
-        {
-            which  = 1;
-            offset = 0;
-        }
-        else
-        {
-            char* buffer = (which == 0 ? label : value);
-            int   length = (which == 0 ? label_length : value_length);
-
-            /* only copy if we're past the first character and it's not
-             * a space
-             */
-            if((offset > 0 || (*current != 9 && *current != ' ')) && offset < (length - 1))
-            {
-                buffer[offset++] = *current;
-                buffer[offset]   = 0;
-            }
-        }
-
-        current++;
-    }
-
-    /* now trim all trailing spaces from the values */
-    while(label[strlen(label) - 1 ] == 9)
-        label[strlen(label) - 1] = 0;
-    while(value[strlen(value) - 1] == 9)
-        value[strlen(value) - 1] = 0;
-}
-
-int get_cpu_info(void)
-{
-    int result = 1;
-    FILE* inputfd;
-    t_cpu_info* current = NULL;
-
-    if(( inputfd = fopen("/proc/cpuinfo","rb")) != NULL)
-    {
-        if(verbose) fprintf(stdout,"Parsing CPU information\n");
-        do
-        {
-            char buffer[255];
-            char label[BUFFER_LENGTH];
-            char value[BUFFER_LENGTH];
-
-            fgets(buffer, 255, inputfd);
-            if(strlen(buffer) > 0) buffer[strlen(buffer) - 1] = '\0';
-
-            get_label_and_value(buffer,
-                                label,BUFFER_LENGTH,
-                                value,BUFFER_LENGTH);
-
-            if(debug)
-                fprintf(stdout,"label=\"%s\", value=\"%s\"\n", label, value);
-
-            if(strlen(label))
-            {
-                if(!strcmp(label,"processor"))
-                {
-                    if(debug || verbose)
-                        fprintf(stdout,"Starting new CPU\n");
-
-                    t_cpu_info* last = current;
-
-                    current = create_cpu_info();
-                    if(last != NULL)
-                    {
-                        last->next = current;
-                    }
-                    else
-                    {
-                        cpu_info = current;
-                    }
-
-                    COPY_VALUE_TO_BUFFER(value,current->cpu_num,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"core id"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->core_num,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"cpu cores"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->number_of_cores,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"vendor_id"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->vendor,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"model"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->model,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"cpu family"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->family,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"cpuid level"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->cpuid_level,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"cpu MHz"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->speed,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"cache size"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->cache,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"flags"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->flags,BUFFER_LENGTH);
-                }
-            }
-
-        } while(!feof(inputfd));
-
-        fclose(inputfd);
-
-        result = 0;
-    }
-    else
-    {
-        if(verbose) fprintf(stderr,"Unable to open /proc/cpuinfo\n");
-    }
-
-    return result;
-}
-
-t_cpu_info* create_cpu_info(void)
-{
-    t_cpu_info* result = calloc(1,sizeof(t_cpu_info));
-    bzero(result,sizeof(t_cpu_info));
-
-    strcpy(result->core_num,"0");
-    strcpy(result->number_of_cores,"1");
-
-
-    return result;
-}
-
-ssize_t safewrite(int fd, const void *buf, size_t count)
-{
-        size_t nwritten = 0;
-        while (count > 0) {
-                ssize_t r = write(fd, buf, count);
-
-                if (r < 0 && errno == EINTR)
-                        continue;
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        return nwritten;
-                buf = (const char *)buf + r;
-                count -= r;
-                nwritten += r;
-        }
-        return nwritten;
-}
-
-int send_text(char* text)
-{
-    int result = 1;
-    int sent;
-
-    if(verbose) fprintf(stdout,"Sending: \"%s\"\n", text);
-
-    sent = safewrite(socketfd, text, strlen(text));
-    sent += safewrite(socketfd, "\n", 1);
-
-    if(sent >= 0)
-    {
-        if(debug) fprintf(stdout,"Sent %d bytes total.\n", sent);
-
-        result = 0;
-    }
-
-    return result;
-}
-
-int saferead(int fd, char *buf, size_t count)
-{
-    ssize_t bytes,offset;
-    int len_left;
-    int done = 0;
-
-    if(debug) fprintf(stdout,"Begin saferead(%d, %p, %ld)\n", fd, buf, count);
-
-    offset = 0;
-    len_left = count;
-
-
-    while(!done)
-    {
-        if(debug) fprintf(stdout,"Before read(%ld,%p,%ld)\n",fd,buf+offset,len_left);
-
-        bytes = read(fd, buf+offset, len_left);
-
-        if(debug) fprintf(stdout,"After read: bytes=%ld\n", bytes);
-
-        if(bytes == 0)
-        {
-            done = 1;
-        }
-        else if(bytes > 0)
-        {
-            offset += bytes;
-            len_left -= bytes;
-            done = 1;
-        }
-        else if(errno == EINTR)
-        {
-            continue;
-        }
-        else
-        {
-            done = 1;
-        }
-
-        if(debug) fprintf(stdout,"End of decision loop: offset=%ld, len_left=%dl, done=%d\n",offset, len_left, done);
-    }
-
-    return offset;
-}
-
-int get_text(const char *const expected)
-{
-    int result = 1;
-    int received;
-    char buffer[BUFFER_LENGTH];
-    bzero(buffer,BUFFER_LENGTH);
-
-    if(verbose) fprintf(stdout, "Looking to receive %s\n", expected);
-
-    received = saferead(socketfd, buffer, BUFFER_LENGTH);
-
-    buffer[received - 1] = 0;
-
-    if(verbose) fprintf(stdout,"Received \"%s\": size=%d (trimmed ending carriage return)\n", buffer, received);
-
-    result = strcmp(expected,buffer);
-
-    return result;
-}
-
-int create_connection(void)
-{
-    int result = 1;
-    struct addrinfo hints;
-    struct addrinfo* results;
-    char port[6];
-    struct addrinfo* rptr;
-
-    if(verbose) fprintf(stdout,"Creating the socket connection.\n");
-
-    memset(&hints, 0, sizeof(struct addrinfo));
-    hints.ai_family = AF_UNSPEC;
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_flags = 0;
-    hints.ai_protocol = 0;
-
-    if(verbose) fprintf(stdout,"Searching for host candidates.\n");
-
-    snprintf(port, 6, "%d", hostport);
-
-    if(!getaddrinfo(hostname, port, &hints, &results))
-    {
-        if(verbose) fprintf(stdout,"Got address information. Searching for a proper entry.\n");
-
-        for(rptr = results; rptr != NULL; rptr = rptr->ai_next)
-        {
-            if(debug)
-            {
-                fprintf(stdout,"Attempting connection: family=%d, socket type=%d, protocol=%d\n",
-                rptr->ai_family, rptr->ai_socktype, rptr->ai_protocol);
-            }
-
-            socketfd = socket(rptr->ai_family, rptr->ai_socktype, rptr->ai_protocol);
-
-            if(socketfd == -1)
-            {
-                continue;
-            }
-
-            if(connect(socketfd, rptr->ai_addr, rptr->ai_addrlen) != -1)
-            {
-                break;
-            }
-
-            //  invalid connection, so close it
-            if(verbose) fprintf(stdout, "Invalid connection.\n");
-            close(socketfd);
-        }
-
-        if(rptr == NULL)
-        {
-            if(verbose) fprintf(stdout,"Unable to connect to server %s:%d\n", hostname, hostport);
-        }
-        else
-        {
-            // success
-            result = 0;
-        }
-
-        freeaddrinfo(results);
-    }
-    else
-    {
-        if(verbose) fprintf(stderr,"No hosts found. Exiting...\n");
-    }
-
-    if(debug) fprintf(stdout, "create_connection: result=%d\n", result);
-
-    return result;
-}
diff --git a/ovirt-managed-node/src/ovirt-identify-node.h b/ovirt-managed-node/src/ovirt-identify-node.h
index 1cb1526..c595891 100644
--- a/ovirt-managed-node/src/ovirt-identify-node.h
+++ b/ovirt-managed-node/src/ovirt-identify-node.h
@@ -1,6 +1,49 @@
+/* Copyright (C) 2008 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.  A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
 #ifndef __OVIRT_IDENTIFY_NODE_H
 #define __OVIRT_IDENTIFY_NODE_H
 
+#include <errno.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+
+#include <hal/libhal.h>
+
+#include <libvirt/libvirt.h>
+
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+#include <linux/if.h>
+
+#include <netinet/in.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
 #define BUFFER_LENGTH 128
 #define CPU_FLAGS_BUFFER_LENGTH 256
 
@@ -18,39 +61,75 @@ typedef struct _cpu_info {
     struct _cpu_info* next;
 } t_cpu_info;
 
-#define COPY_VALUE_TO_BUFFER(value,buffer,length) \
-    snprintf(buffer,length,"%s",value)
+typedef t_cpu_info* cpu_info_ptr;
+
+typedef struct _nic_info {
+    char mac_address[BUFFER_LENGTH];
+    char bandwidth[BUFFER_LENGTH];
+    char ip_address[BUFFER_LENGTH];
+    struct _nic_info* next;
+} t_nic_info;
+
+typedef t_nic_info* nic_info_ptr;
 
 int  config(int argc,char** argv);
 void usage(void);
 
-int start_conversation(void);
-int send_details(void);
-int send_cpu_details(void);
-int end_conversation(void);
-
 void get_label_and_value(char* text,
                          char* label,size_t label_length,
                          char* value,size_t value_length);
-t_cpu_info* create_cpu_info(void);
-int get_cpu_info(void);
 
 int send_text(char* text);
 int get_text(const char *const expected);
+
+/* comm.c */
+ssize_t saferead(int fd, char *buf, size_t count);
+ssize_t safewrite(int fd, const void *buf, size_t count);
+
+/* debug.c */
+void debug_cpu_info(void);
+
+/* gather.c */
+int init_gather(void);
+int get_uuid(void);
+int get_cpu_info(void);
+int get_nic_info(void);
+
+/* hal_support.c */
+LibHalContext* get_hal_ctx(void);
+
+/* protocol.c */
 int create_connection(void);
+int start_conversation(void);
+int send_details(void);
+int end_conversation(void);
+int send_value(char* label,char* value);
+int send_text(char* text);
+
+/* variables */
+extern int  debug;
+extern int  verbose;
+extern int  testing;
 
-int debug   = 0;
-int verbose = 0;
-int testing = 0;
-
-char arch[BUFFER_LENGTH];
-char uuid[VIR_UUID_BUFLEN];
-char memsize[BUFFER_LENGTH];
-char numcpus[BUFFER_LENGTH];
-char cpuspeed[BUFFER_LENGTH];
-char *hostname;
-int  hostport = -1;
-int  socketfd;
-t_cpu_info* cpu_info;
+extern char arch[BUFFER_LENGTH];
+extern char uuid[BUFFER_LENGTH];
+extern char memsize[BUFFER_LENGTH];
+extern char numcpus[BUFFER_LENGTH];
+extern char cpuspeed[BUFFER_LENGTH];
+extern char *hostname;
+extern int  hostport;
+extern int  socketfd;
+extern cpu_info_ptr cpu_info;
+extern nic_info_ptr nic_info;
+
+extern DBusConnection* dbus_connection;
+extern DBusError       dbus_error;
+extern LibHalContext*  hal_ctx;
+
+/* macros */
+#define DEBUG(arg...)   if(debug)   fprintf(stderr, ##arg)
+#define VERBOSE(arg...) if(verbose) fprintf(stdout, ##arg)
+#define COPY_VALUE_TO_BUFFER(value,buffer,length) \
+    snprintf(buffer,length,"%s",value)
 
 #endif
diff --git a/ovirt-managed-node/src/protocol.c b/ovirt-managed-node/src/protocol.c
new file mode 100644
index 0000000..131bb38
--- /dev/null
+++ b/ovirt-managed-node/src/protocol.c
@@ -0,0 +1,272 @@
+
+/* protocol.c -- Manages the communication between the managed node and
+ *               the oVirt server.
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.  A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "ovirt-identify-node.h"
+
+int
+create_connection(void)
+{
+    int result = 1;
+
+    struct addrinfo hints;
+
+    struct addrinfo *results;
+
+    char port[6];
+
+    struct addrinfo *rptr;
+
+    VERBOSE("Creating the socket connection.\n");
+
+    memset(&hints, 0, sizeof(struct addrinfo));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = 0;
+    hints.ai_protocol = 0;
+
+    VERBOSE("Searching for host candidates.\n");
+
+    snprintf(port, 6, "%d", hostport);
+
+    if (!getaddrinfo(hostname, port, &hints, &results)) {
+        VERBOSE
+            ("Got address information. Searching for a proper entry.\n");
+
+        for (rptr = results; rptr != NULL; rptr = rptr->ai_next) {
+            if (debug) {
+                fprintf(stdout,
+                        "Attempting connection: family=%d, socket type=%d, protocol=%d\n",
+                        rptr->ai_family, rptr->ai_socktype,
+                        rptr->ai_protocol);
+            }
+
+            socketfd =
+                socket(rptr->ai_family, rptr->ai_socktype,
+                       rptr->ai_protocol);
+
+            if (socketfd == -1) {
+                continue;
+            }
+
+            if (connect(socketfd, rptr->ai_addr, rptr->ai_addrlen) != -1) {
+                break;
+            }
+            //  invalid connection, so close it
+            VERBOSE("Invalid connection.\n");
+            close(socketfd);
+        }
+
+        if (rptr == NULL) {
+            VERBOSE("Unable to connect to server %s:%d\n", hostname,
+                    hostport);
+        } else {
+            // success
+            result = 0;
+        }
+
+        freeaddrinfo(results);
+    } else {
+        VERBOSE("No hosts found. Exiting...\n");
+    }
+
+    DEBUG("create_connection: result=%d\n", result);
+
+    return result;
+}
+
+int
+start_conversation(void)
+{
+    int result = 1;
+
+    VERBOSE("Starting conversation with %s:%d.\n", hostname, hostport);
+
+    if (!create_connection()) {
+        VERBOSE("Connected.\n");
+
+        if (!get_text("HELLO?")) {
+            VERBOSE("Checking for handshake.\n");
+
+            if (!send_text("HELLO!")) {
+                VERBOSE("Handshake received. Starting conversation.\n");
+
+                if (!get_text("MODE?")) {
+                    VERBOSE("Shifting to IDENTIFY mode.\n");
+
+                    if (!send_text("IDENTIFY"))
+                        result = 0;
+                } else {
+                    VERBOSE("Was not asked for a mode.\n");
+                }
+            }
+        } else {
+            VERBOSE("Did not receive a proper handshake.\n");
+        }
+    }
+
+    else {
+        VERBOSE("Did not get a connection.\n");
+    }
+
+    DEBUG("start_conversation: result=%d\n", result);
+
+    return result;
+}
+
+/* Transmits the CPU details to the server.
+ */
+int
+send_cpu_details(void)
+{
+    int result = 1;
+
+    cpu_info_ptr current = cpu_info;
+
+    while (current != NULL) {
+        send_text("CPU");
+
+        if (!(get_text("CPUINFO?")) &&
+            (!send_value("CPUNUM", current->cpu_num)) &&
+            (!send_value("CORENUM", current->core_num)) &&
+            (!send_value("NUMCORES", current->number_of_cores)) &&
+            (!send_value("VENDOR", current->vendor)) &&
+            (!send_value("MODEL", current->model)) &&
+            (!send_value("FAMILY", current->family)) &&
+            (!send_value("CPUIDLVL", current->cpuid_level)) &&
+            (!send_value("SPEED", current->speed)) &&
+            (!send_value("CACHE", current->cache)) &&
+            (!send_value("FLAGS", current->flags))) {
+            send_text("ENDCPU");
+            result = get_text("ACK CPU");
+        }
+
+        current = current->next;
+    }
+
+
+    return result;
+}
+
+/* Transmits the NIC details to the server.
+ */
+int
+send_nic_details(void)
+{
+    int result = 1;
+
+    nic_info_ptr current = nic_info;
+
+    while (current != NULL) {
+        send_text("NIC");
+
+        if (!(get_text("NICINFO?")) &&
+            (!send_value("MAC", current->mac_address)) &&
+            (!send_value("BANDWIDTH", current->bandwidth))) {
+            send_text("ENDNIC");
+            result = get_text("ACK NIC");
+        }
+
+        current = current->next;
+    }
+
+    return result;
+}
+
+int
+send_details(void)
+{
+    int result = 1;
+
+    VERBOSE("Sending node details.\n");
+
+    if (!get_text("INFO?")) {
+        if ((!send_value("ARCH", arch)) &&
+            (!send_value("UUID", uuid)) &&
+            (!send_value("MEMSIZE", memsize)) &&
+            (!send_cpu_details() && !send_nic_details())) {
+            if (!send_text("ENDINFO"))
+                result = 0;
+        }
+    } else {
+        VERBOSE("Was not interrogated for hardware info.\n");
+    }
+
+    return result;
+}
+
+int
+end_conversation(void)
+{
+    int result = 0;
+
+    VERBOSE("Ending conversation.\n");
+
+    send_text("ENDINFO");
+
+    close(socketfd);
+
+    return result;
+}
+
+int
+send_value(char *label, char *value)
+{
+    char buffer[BUFFER_LENGTH];
+
+    int result = 1;
+
+    char expected[BUFFER_LENGTH];
+
+    snprintf(buffer, BUFFER_LENGTH, "%s=%s", label, value);
+
+    if (!send_text(buffer)) {
+        snprintf(expected, BUFFER_LENGTH, "ACK %s", label);
+
+        VERBOSE("Expecting \"%s\"\n", expected);
+
+        result = get_text(expected);
+    }
+
+    return result;
+}
+
+int
+send_text(char *text)
+{
+    int result = 1;
+
+    int sent;
+
+    VERBOSE("Sending: \"%s\"\n", text);
+
+    sent = safewrite(socketfd, text, strlen(text));
+    sent += safewrite(socketfd, "\n", 1);
+
+    if (sent >= 0) {
+        DEBUG("Sent %d bytes total.\n", sent);
+
+        result = 0;
+    }
+
+    return result;
+}
diff --git a/ovirt-managed-node/src/scripts/ovirt-post b/ovirt-managed-node/src/scripts/ovirt-post
index f113b28..310a41c 100755
--- a/ovirt-managed-node/src/scripts/ovirt-post
+++ b/ovirt-managed-node/src/scripts/ovirt-post
@@ -12,14 +12,8 @@
 
 start() {
     find_srv identify tcp
-    UUID=`hal-get-property --udi \
-        /org/freedesktop/Hal/devices/computer --key system.hardware.uuid`
 
-    if [ -z $UUID ]; then
-        ovirt-identify-node -s $SRV_HOST -p $SRV_PORT
-    else
-        ovirt-identify-node -s $SRV_HOST -p $SRV_PORT -u $UUID
-    fi
+    ovirt-identify-node -s $SRV_HOST -p $SRV_PORT
 }
 
 case "$1" in
diff --git a/wui/src/host-browser/host-browser.rb b/wui/src/host-browser/host-browser.rb
index 624661d..d209bdb 100755
--- a/wui/src/host-browser/host-browser.rb
+++ b/wui/src/host-browser/host-browser.rb
@@ -87,8 +87,8 @@ class HostBrowser
 
             break if info == "ENDINFO"
 
-            # if we got the start of a CPU details marker, then process it
-            if info == "CPU"
+            case info
+            when "CPU"
                 cpu = get_cpu_info
                 cpu_info = result['CPUINFO']
 
@@ -98,7 +98,16 @@ class HostBrowser
                 end
 
                 cpu_info << cpu
+            when "NIC"
+                nic = get_nic_info
+                nic_info = result['NICINFO']
 
+                if(nic_info == nil)
+                    nic_info = Array.new
+                    result['NICINFO'] = nic_info
+                end
+
+                nic_info << nic
             else
 
                 raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/
@@ -144,6 +153,35 @@ class HostBrowser
         return result
     end
 
+    # Extracts NIC details from the managed node.
+    #
+    def get_nic_info
+        puts "Begin receiving NIC details"
+
+        result = Hash.new
+
+        @session.write("NICINFO?\n")
+
+        loop do
+            info = @session.readline.chomp
+
+            break if info == "ENDNIC"
+
+            raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/
+
+            key, value = info.split("=")
+
+            puts "#{@log_prefix} ::Received - #{key}:#{value}" unless defined?(TESTING)
+            result[key] = value
+
+            @session.write("ACK #{key}\n")
+        end
+
+        @session.write("ACK NIC\n");
+
+        return result
+    end
+
     # Writes the supplied host information to the database.
     #
     def write_host_info(host_info)
@@ -151,8 +189,10 @@ class HostBrowser
         ensure_present(host_info,'ARCH')
         ensure_present(host_info,'MEMSIZE')
         ensure_present(host_info,'CPUINFO')
+        ensure_present(host_info,'NICINFO')
 
         cpu_info = host_info['CPUINFO']
+        nic_info = host_info['NICINFO']
 
         cpu_info.each do |cpu|
             ensure_present(cpu,'CPUNUM')
@@ -216,7 +256,45 @@ class HostBrowser
             host.cpus << detail
          end
 
-         host.save!
+        # Update the NIC details for this host:
+        # -if the NIC exists, then update the IP address
+        # -if the NIC does not exist, create it
+        # -any nic not in this list is deleted
+
+        puts "Updating NIC records for the node"
+        nics = Array.new
+
+        host.nics.collect do |nic|
+            found = false
+
+            nic_info.collect do |detail|
+                # if we have a match, then update the database and remove
+                # the received data to avoid creating a dupe later
+                if detail['MAC'] == nic.mac
+                    nic_info.delete(detail)
+                end
+            end
+
+            # if the record wasn't found, then remove it from the database
+            unless found
+                host.nics.delete(nic)
+                nic.destroy
+            end
+        end
+
+        # iterate over any nics left and create new records for them.
+
+        nic_info.collect do |nic|
+            puts "Creating a new nic..."
+            detail = Nic.new(
+                'mac'        => nic['MAC'],
+                'bandwidth'  => nic['BANDWIDTH'],
+                'usage_type' => 1)
+
+            host.nics << detail
+        end
+
+        host.save!
 
         return host
     end
diff --git a/wui/src/host-browser/test-host-browser-identify.rb b/wui/src/host-browser/test-host-browser-identify.rb
index 4197e19..7e672ce 100755
--- a/wui/src/host-browser/test-host-browser-identify.rb
+++ b/wui/src/host-browser/test-host-browser-identify.rb
@@ -38,7 +38,7 @@ class TestHostBrowser < Test::Unit::TestCase
         @host_info = {}
         @host_info['UUID']     = 'node1'
         @host_info['IPADDR']   = '192.168.2.2'
-        @host_info['HOSTNAME'] = 'node1.ovirt.redhat.com'
+        @host_info['HOSTNAME'] = 'prod.corp.com'
         @host_info['ARCH']     = 'x86_64'
         @host_info['MEMSIZE']  = '16384'
         @host_info['DISABLED'] = '0'
@@ -75,6 +75,15 @@ class TestHostBrowser < Test::Unit::TestCase
             mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx \
             fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs \
             bts pni monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr lahf_lm'
+
+        @host_info['NICINFO'] = Array.new
+        @host_info['NICINFO'][0] = {}
+        @host_info['NICINFO'][0]['MAC']       = '00:11:22:33:44:55'
+        @host_info['NICINFO'][0]['BANDWIDTH'] = '100'
+
+        @host_info['NICINFO'][1] = {}
+        @host_info['NICINFO'][1]['MAC']       = '00:77:11:77:19:65'
+        @host_info['NICINFO'][1]['BANDWIDTH'] = '100'
     end
 
     # Ensures that the server is satisfied if the remote system is
@@ -184,6 +193,15 @@ class TestHostBrowser < Test::Unit::TestCase
         assert_raise(Exception) { @browser.write_host_info(@host_info) }
     end
 
+    # Ensures that, if no NIC info was available, the server raises an
+    # exception.
+    #
+    def test_write_host_info_with_missing_nicinfo
+        @host_info['NICINFO'] = nil
+
+        assert_raise(Exception) { @browser.write_host_info(@host_info) }
+    end
+
     # Ensures the browser can properly parse the CPU details.
     #
     def test_parse_cpu_info
@@ -206,7 +224,7 @@ class TestHostBrowser < Test::Unit::TestCase
 
     # Ensures the browser can properly parse the CPU details of two CPUs.
     #
-    def test_parse_cpu_info
+    def test_parse_cpu_info_with_two_entries
         @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
 
         # CPU 0
@@ -242,4 +260,24 @@ class TestHostBrowser < Test::Unit::TestCase
         assert_not_nil info['CPUINFO'][1]['key4']
     end
 
+    # Ensures the browser can properly parse the details for a NIC.
+    #
+    def test_parse_nic_info
+        @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
+        @session.should_receive(:readline).once().returns { "NIC\n" }
+        @session.should_receive(:write).with("NICINFO?\n").once().returns { |request| request.length }
+        @session.should_receive(:readline).once().returns { "key1=value1\n" }
+        @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length }
+        @session.should_receive(:readline).once().returns { "key2=value2\n" }
+        @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length }
+        @session.should_receive(:readline).once().returns { "ENDNIC\n" }
+        @session.should_receive(:write).with("ACK NIC\n").once().returns { |request| request.length }
+        @session.should_receive(:readline).once().returns { "ENDINFO\n" }
+
+        info = @browser.get_remote_info
+
+        assert_equal 3,info.keys.size, "Should contain four keys"
+        assert info.include?("NICINFO")
+    end
+
 end
-- 
1.5.5.1




More information about the ovirt-devel mailing list