Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[vmware] Allow settings to be specified in the VMware .vmx file
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
Showing
4 changed files
with
287 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters