Skip to content

Commit

Permalink
[vmware] Allow settings to be specified in the VMware .vmx file
Browse files Browse the repository at this point in the history
Allow iPXE settings to be specified in the .vmx file via the VMware
GuestInfo mechanism.  For example:

    guestinfo.ipxe.filename = "http://boot.ipxe.org/demo/boot.php"
    guestinfo.ipxe.dns = "192.168.0.1"
    guestinfo.ipxe.net0.ip = "192.168.0.15"
    guestinfo.ipxe.net0.netmask = "255.255.255.0"
    guestinfo.ipxe.net0.gateway = "192.168.0.1"

Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Apr 17, 2012
1 parent 52e5ddc commit a9cf527
Show file tree
Hide file tree
Showing 4 changed files with 287 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/arch/i386/include/bits/errfile.h
Expand Up @@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_runtime ( ERRFILE_ARCH | ERRFILE_CORE | 0x00070000 )
#define ERRFILE_vmware ( ERRFILE_ARCH | ERRFILE_CORE | 0x00080000 )
#define ERRFILE_guestrpc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00090000 )
#define ERRFILE_guestinfo ( ERRFILE_ARCH | ERRFILE_CORE | 0x000a0000 )

#define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
#define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
Expand Down
281 changes: 281 additions & 0 deletions src/arch/i386/interface/vmware/guestinfo.c
@@ -0,0 +1,281 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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; either version 2 of the
* License, or any later version.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

FILE_LICENCE ( GPL2_OR_LATER );

/** @file
*
* VMware GuestInfo settings
*
*/

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ipxe/init.h>
#include <ipxe/settings.h>
#include <ipxe/netdevice.h>
#include <ipxe/guestrpc.h>

/** GuestInfo GuestRPC channel */
static int guestinfo_channel;

/**
* Fetch value of typed GuestInfo setting
*
* @v settings Settings block
* @v setting Setting to fetch
* @v type Setting type to attempt (or NULL for default)
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret found Setting found in GuestInfo
* @ret len Length of setting data, or negative error
*/
static int guestinfo_fetch_type ( struct settings *settings,
struct setting *setting,
struct setting_type *type,
void *data, size_t len, int *found ) {
const char *parent_name = settings->parent->name;
char command[ 24 /* "info-get guestinfo.ipxe." */ +
strlen ( parent_name ) + 1 /* "." */ +
strlen ( setting->name ) + 1 /* "." */ +
( type ? strlen ( type->name ) : 0 ) + 1 /* NUL */ ];
struct setting *named_setting;
char *info;
int info_len;
int check_len;
int ret;

/* Construct info-get command */
snprintf ( command, sizeof ( command ),
"info-get guestinfo.ipxe.%s%s%s%s%s",
parent_name, ( parent_name[0] ? "." : "" ), setting->name,
( type ? "." : "" ), ( type ? type->name : "" ) );

/* Check for existence and obtain length of GuestInfo value */
info_len = guestrpc_command ( guestinfo_channel, command, NULL, 0 );
if ( info_len < 0 ) {
ret = info_len;
goto err_get_info_len;
}

/* Mark as found */
*found = 1;

/* Determine default type if necessary */
if ( ! type ) {
named_setting = find_setting ( setting->name );
type = ( named_setting ?
named_setting->type : &setting_type_string );
}
assert ( type != NULL );

/* Allocate temporary block to hold GuestInfo value */
info = zalloc ( info_len + 1 /* NUL */ );
if ( ! info ) {
DBGC ( settings, "GuestInfo %p could not allocate %zd bytes\n",
settings, info_len );
ret = -ENOMEM;
goto err_alloc;
}
info[info_len] = '\0';

/* Fetch GuestInfo value */
check_len = guestrpc_command ( guestinfo_channel, command,
info, info_len );
if ( check_len < 0 ) {
ret = check_len;
goto err_get_info;
}
if ( check_len != info_len ) {
DBGC ( settings, "GuestInfo %p length mismatch (expected %d, "
"got %d)\n", settings, info_len, check_len );
ret = -EIO;
goto err_get_info;
}
DBGC2 ( settings, "GuestInfo %p found %s = \"%s\"\n",
settings, &command[9] /* Skip "info-get " */, info );

/* Parse GuestInfo value according to type */
ret = type->parse ( info, data, len );
if ( ret < 0 ) {
DBGC ( settings, "GuestInfo %p could not parse \"%s\" as %s: "
"%s\n", settings, info, type->name, strerror ( ret ) );
goto err_parse;
}

err_parse:
err_get_info:
free ( info );
err_alloc:
err_get_info_len:
return ret;
}

/**
* Fetch value of GuestInfo setting
*
* @v settings Settings block
* @v setting Setting to fetch
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
static int guestinfo_fetch ( struct settings *settings,
struct setting *setting,
void *data, size_t len ) {
struct setting_type *type;
int found = 0;
int ret;

/* Try default type first */
ret = guestinfo_fetch_type ( settings, setting, NULL,
data, len, &found );
if ( found )
return ret;

/* Otherwise, try all possible types */
for_each_table_entry ( type, SETTING_TYPES ) {
ret = guestinfo_fetch_type ( settings, setting, type,
data, len, &found );
if ( found )
return ret;
}

/* Not found */
return -ENOENT;
}

/** GuestInfo settings operations */
static struct settings_operations guestinfo_settings_operations = {
.fetch = guestinfo_fetch,
};

/** GuestInfo settings */
static struct settings guestinfo_settings = {
.refcnt = NULL,
.siblings = LIST_HEAD_INIT ( guestinfo_settings.siblings ),
.children = LIST_HEAD_INIT ( guestinfo_settings.children ),
.op = &guestinfo_settings_operations,
};

/** Initialise GuestInfo settings */
static void guestinfo_init ( void ) {
int rc;

/* Open GuestRPC channel */
guestinfo_channel = guestrpc_open();
if ( guestinfo_channel < 0 ) {
rc = guestinfo_channel;
DBG ( "GuestInfo could not open channel: %s\n",
strerror ( rc ) );
return;
}

/* Register root GuestInfo settings */
if ( ( rc = register_settings ( &guestinfo_settings, NULL,
"vmware" ) ) != 0 ) {
DBG ( "GuestInfo could not register settings: %s\n",
strerror ( rc ) );
return;
}
}

/** GuestInfo settings initialiser */
struct init_fn guestinfo_init_fn __init_fn ( INIT_NORMAL ) = {
.initialise = guestinfo_init,
};

/**
* Create per-netdevice GuestInfo settings
*
* @v netdev Network device
* @ret rc Return status code
*/
static int guestinfo_net_probe ( struct net_device *netdev ) {
struct settings *settings;
int rc;

/* Do nothing unless we have a GuestInfo channel available */
if ( guestinfo_channel < 0 )
return 0;

/* Allocate and initialise settings block */
settings = zalloc ( sizeof ( *settings ) );
if ( ! settings ) {
rc = -ENOMEM;
goto err_alloc;
}
settings_init ( settings, &guestinfo_settings_operations, NULL, 0 );

/* Register settings */
if ( ( rc = register_settings ( settings, netdev_settings ( netdev ),
"vmware" ) ) != 0 ) {
DBGC ( settings, "GuestInfo %p could not register for %s: %s\n",
settings, netdev->name, strerror ( rc ) );
goto err_register;
}
DBGC ( settings, "GuestInfo %p registered for %s\n",
settings, netdev->name );

return 0;

err_register:
free ( settings );
err_alloc:
return rc;
}

/**
* Handle network device or link state change
*
* @v netdev Network device
*/
static void guestinfo_net_notify ( struct net_device *netdev __unused ) {
/* Nothing to do */
}

/**
* Remove per-netdevice GuestInfo settings
*
* @v netdev Network device
*/
static void guestinfo_net_remove ( struct net_device *netdev ) {
struct settings *parent = netdev_settings ( netdev );
struct settings *settings;

list_for_each_entry ( settings, &parent->children, siblings ) {
if ( settings->op == &guestinfo_settings_operations ) {
DBGC ( settings, "GuestInfo %p unregistered for %s\n",
settings, netdev->name );
unregister_settings ( settings );
free ( settings );
return;
}
}
}

/** GuestInfo per-netdevice driver */
struct net_driver guestinfo_net_driver __net_driver = {
.name = "GuestInfo",
.probe = guestinfo_net_probe,
.notify = guestinfo_net_notify,
.remove = guestinfo_net_remove,
};
5 changes: 4 additions & 1 deletion src/config/config.c
Expand Up @@ -280,13 +280,16 @@ REQUIRE_OBJECT ( tap );
#endif

/*
* Drag in relevant BOFM entry points
* Drag in relevant sideband entry points
*/
#ifdef CONFIG_BOFM
#ifdef BOFM_EFI
REQUIRE_OBJECT ( efi_bofm );
#endif /* BOFM_EFI */
#endif /* CONFIG_BOFM */
#ifdef VMWARE_SETTINGS
REQUIRE_OBJECT ( guestinfo );
#endif /* VMWARE_SETTINGS */

/*
* Drag in selected keyboard map
Expand Down
1 change: 1 addition & 0 deletions src/config/sideband.h
Expand Up @@ -10,5 +10,6 @@
FILE_LICENCE ( GPL2_OR_LATER );

//#define CONFIG_BOFM /* IBM's BladeCenter Open Fabric Manager */
//#define VMWARE_SETTINGS /* VMware GuestInfo settings */

#endif /* CONFIG_SIDEBAND_H */

0 comments on commit a9cf527

Please sign in to comment.