[Ovirt-devel] [PATCH] Adding NIC details to ovirt identify stage.

Darryl L. Pierce dpierce at redhat.com
Fri Jul 11 19:28:50 UTC 2008


This patch includes submitting to the server the MAC address and bandwidth, as
determined via HAL, for each physical NIC in the machine. 

The source code for the ovirt-identify-node was split up as well to make it 
easier to review and manage.


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                      |   87 +++
 ovirt-managed-node/src/debug.c                     |   48 ++
 ovirt-managed-node/src/gather.c                    |  278 +++++++++
 ovirt-managed-node/src/hal_support.c               |   65 ++
 ovirt-managed-node/src/main.c                      |  216 +++++++
 ovirt-managed-node/src/ovirt-identify-node.c       |  653 --------------------
 ovirt-managed-node/src/ovirt-identify-node.h       |  119 +++-
 ovirt-managed-node/src/protocol.c                  |  276 +++++++++
 ovirt-managed-node/src/scripts/ovirt-post          |    9 +-
 wui/src/host-browser/host-browser.rb               |   84 +++-
 wui/src/host-browser/test-host-browser-identify.rb |   42 ++-
 13 files changed, 1195 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..a63a58d
--- /dev/null
+++ b/ovirt-managed-node/src/comm.c
@@ -0,0 +1,87 @@
+/* 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;
+
+    DEBUG("Begin saferead(%d, %p, %d)\n", fd, buf, count);
+
+    offset = 0;
+    len_left = 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..807d88b
--- /dev/null
+++ b/ovirt-managed-node/src/debug.c
@@ -0,0 +1,48 @@
+/* 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);
+
+    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;
+    }
+}
diff --git a/ovirt-managed-node/src/gather.c b/ovirt-managed-node/src/gather.c
new file mode 100644
index 0000000..d18eb86
--- /dev/null
+++ b/ovirt-managed-node/src/gather.c
@@ -0,0 +1,278 @@
+/* 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.
+ */
+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;
+}
+
+int get_cpu_info(void)
+{
+    int result = 1;
+    FILE* inputfd;
+    t_cpu_info* current = NULL;
+
+    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");
+
+                    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
+    {
+        VERBOSE("Unable to open /proc/cpuinfo\n");
+    }
+
+    return result;
+}
+
+/* Creates a new instance of type t_nic_info.
+ */
+t_nic_info* create_nic_info(void)
+{
+    t_nic_info* 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,t_nic_info* 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;
+    t_nic_info* current = NULL;
+    t_nic_info* 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..58ee29b
--- /dev/null
+++ b/ovirt-managed-node/src/hal_support.c
@@ -0,0 +1,65 @@
+/* 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..29e08a5
--- /dev/null
+++ b/ovirt-managed-node/src/main.c
@@ -0,0 +1,216 @@
+/* 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;
+t_cpu_info* cpu_info;
+t_nic_info* 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..fd1bc0a 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,71 @@ 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 struct _nic_info {
+    char mac_address[BUFFER_LENGTH];
+    char bandwidth[BUFFER_LENGTH];
+    char ip_address[BUFFER_LENGTH];
+    struct _nic_info* next;
+} t_nic_info;
 
 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;
+
+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 t_cpu_info* cpu_info;
+extern t_nic_info* nic_info;
 
-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 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..111a1c1
--- /dev/null
+++ b/ovirt-managed-node/src/protocol.c
@@ -0,0 +1,276 @@
+/* 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;
+    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;
+}
+
+/* Transmits the NIC details to the server.
+ */
+int send_nic_details(void)
+{
+    int         result  = 1;
+    t_nic_info* 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 3bb0f6d..2624e01 100755
--- a/ovirt-managed-node/src/scripts/ovirt-post
+++ b/ovirt-managed-node/src/scripts/ovirt-post
@@ -14,16 +14,11 @@ start() {
     echo -n $"Starting ovirt-post: "
 
     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
 
     success
+
     echo
 }
 
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