[gPXE-devel] [gPXE] PATCH: Allow "dhcp" command to iterate over multiple interfaces like autoboot()

Stefan Hajnoczi stefanha at gmail.com
Fri Jul 30 16:52:39 EDT 2010


On Sat, Jul 24, 2010 at 07:04:43PM +0100, Stefan Hajnoczi wrote:
> CCed to the gpxe-devel at etherboot.org mailing list.  The original mail went to
> gpxe at etherboot.org.
> 
> Here is the dhcp multiple interface patch from Lars Kellogg-Stedman
> <lars at oddbit.com> inline for easy reviewing:

Please use gPXE coding style, see net/netdevice.c for examples.
Whitespace is used like this:

static void foo ( int arg ) {
	if ( arg > 2 )
		bar(); /* no spaces when function has no arguments */
}

> 
> diff --git a/src/hci/commands/dhcp_cmd.c b/src/hci/commands/dhcp_cmd.c
> index 96aac8d..a494068 100644
> --- a/src/hci/commands/dhcp_cmd.c
> +++ b/src/hci/commands/dhcp_cmd.c
> @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
>  #include <gpxe/in.h>
>  #include <gpxe/command.h>
>  #include <usr/dhcpmgmt.h>
> +#include <usr/ifmgmt.h>
>  
>  /** @file
>   *
> @@ -45,10 +46,87 @@ FILE_LICENCE ( GPL2_OR_LATER );
>   */
>  static void dhcp_syntax ( char **argv ) {
>  	printf ( "Usage:\n"
> -		 "  %s <interface>\n"
> +		 "  %s [-c] <interface> [<interface> ...]\n"
> +		 "  %s any\n"
>  		 "\n"
>  		 "Configure a network interface using DHCP\n",
> -		 argv[0] );
> +		 argv[0], argv[0] );
> +}
> +
> +/**
> + * Given a device name, attempt to configure that device using dhcp.
> + *
> + * @netdev_name		Name of the network device
> + */
> +static int dhcp_one_device_name (char *netdev_name) {
> +	int rc;
> +	struct net_device *netdev;
> +
> +	netdev = find_netdev ( netdev_name );
> +
> +	if ( ! netdev ) {
> +		printf ( "No such interface: %s\n", netdev_name );
> +		return 2;
> +	}
> +
> +	/* Perform DHCP */
> +	if ( ( rc = dhcp ( netdev ) ) != 0 ) {
> +		printf ( "Could not configure %s: %s\n", netdev->name,
> +				strerror ( rc ) );

If DHCP fails the device should be closed.  The dhcp() function will
automatically open the netdev.  Having multiple netdevs open
simultaneously can cause out-of-memory situations because gPXE only
claims a small chunk of memory to use as its heap.

Previously the command didn't close single netdevs.  gPXE aborts script
execution if a command fails, so I don't think existing users will
be able to detect this change.

> +		return 1;
> +	} 
> +
> +	return 0;
> +}
> +
> +/**
> + * Call dhcp_one_device_name() for each name in argv.
> + *
> + * @argc		Number of devices
> + * @argv		List of device names
> + * @keep_going		If TRUE, ignore errors caused by unknown device names.
> + */
> +static int dhcp_each_device_name (int argc, char *argv[], int keep_going) {
> +	int i;
> +
> +	for (i=0; i<argc; i++) {
> +		switch ( dhcp_one_device_name ( argv[i] ) ) {
> +			case 0:
> +				return 0;
> +			case 1:
> +				break;
> +			case 2:
> +				if (! keep_going)
> +					return 1;
> +		}
> +	}
> +
> +	printf( "Could not configure any interface.\n" );
> +	return 1;
> +}
> +
> +/**
> + * Call dhcp_one_device_name() for each device in net_devices.
> + */
> +static int dhcp_each_device () {

Please use a void argument list to mark a function with no arguments.
In C giving no argument list means the compiler doesn't type-check
calls, you could get away with using the function like this:

dhcp_each_device ( "hello", 123 );

> +	struct net_device *netdev;
> +
> +	for_each_netdev ( netdev ) {
> +		switch ( dhcp_one_device_name ( netdev->name ) ) {
> +			case 0:
> +				return 0;
> +			case 1:
> +				break;
> +			case 2:
> +				/* we should never get here, since we're working
> +				 * from a list of known device names.
> +				 */
> +				return 1;

If dhcp_one_device_name() doesn't do find_netdev(), then this switch
statement can turn into a simple if statement:

if ( ! dhcp_one_device_name ( netdev ) )
	return 0;

And the change to dhcp_each_device_name() would make the code nicer too,
I think.

> +		}
> +	}
> +
> +	printf( "Could not configure any interface.\n" );
> +	return 1;
>  }
>  
>  /**
> @@ -61,16 +139,18 @@ static void dhcp_syntax ( char **argv ) {
>  static int dhcp_exec ( int argc, char **argv ) {
>  	static struct option longopts[] = {
>  		{ "help", 0, NULL, 'h' },
> +		{ "continue", 0, NULL, 'c' },
>  		{ NULL, 0, NULL, 0 },
>  	};
> -	const char *netdev_txt;
> -	struct net_device *netdev;
>  	int c;
> -	int rc;
> +	int keep_going = 0;
>  
>  	/* Parse options */
> -	while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
> +	while ( ( c = getopt_long ( argc, argv, "ch", longopts, NULL ) ) >= 0 ){
>  		switch ( c ) {
> +		case 'c':
> +			keep_going = 1;
> +			break;
>  		case 'h':
>  			/* Display help text */
>  		default:
> @@ -81,27 +161,19 @@ static int dhcp_exec ( int argc, char **argv ) {
>  	}
>  
>  	/* Need exactly one interface name remaining after the options */
> -	if ( optind != ( argc - 1 ) ) {
> +	if ( ( argc - optind ) < 1 ) {
>  		dhcp_syntax ( argv );
>  		return 1;
>  	}
> -	netdev_txt = argv[optind];
>  
> -	/* Parse arguments */
> -	netdev = find_netdev ( netdev_txt );
> -	if ( ! netdev ) {
> -		printf ( "No such interface: %s\n", netdev_txt );
> -		return 1;
> +	if (strcmp(argv[optind], "any") == 0) {
> +		return dhcp_each_device ();
> +	} else {
> +		return dhcp_each_device_name (argc-optind, argv+optind, keep_going);
>  	}

I'd move dhcp_each_device_name() outside an "else"...

>  
> -	/* Perform DHCP */
> -	if ( ( rc = dhcp ( netdev ) ) != 0 ) {
> -		printf ( "Could not configure %s: %s\n", netdev->name,
> -			 strerror ( rc ) );
> -		return 1;
> -	}
> -
> -	return 0;
> +	/* we should never get here. */
> +	return 1;

...and drop these two lines of dead code.

>  }
>  
>  /**


More information about the gPXE-devel mailing list