[dhcp] Allow multiple interfaces in dhcp command
authorLars Kellogg-Stedman <lars@oddbit.com>
Sat, 31 Jul 2010 08:20:41 +0000 (09:20 +0100)
committerStefan Hajnoczi <stefanha@gmail.com>
Sun, 1 Aug 2010 20:39:08 +0000 (21:39 +0100)
The "dhcp" command now accepts a list of interfaces and to try until one
succeeds:

 gPXE> dhcp net0 net1 net2

If an interface does not exist a message is printed and it is skipped.

If given the single parameter "any" as an interface name, all interfaces
are tried in a manner similar to autoboot:

 gPXE> dhcp any
 DHCP (net0 xx:xx:xx:xx:xx:xx)........ Connection timed out (...)
 Could not configure net0: Connection timed out (...)
 DHCP (net1 xx:xx:xx:xx:xx:xx).... ok
 gPXE>

Note that interfaces which fail to DHCP are closed.  This is usually
desirable since an open interface consumes memory.  On machines with
several interfaces it is possible to exhaust the heap if all interfaces
are open simultaneously.  This behavior differs from the previous "dhcp"
command implementation but should not be detectable to user scripts
since they abort when the dhcp command exits with an error.

Acked-by: Marty Connor <mdc@etherboot.org>
Signed-off-by: Lars Kellogg-Stedman <lars@oddbit.com>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
src/hci/commands/dhcp_cmd.c

index 96aac8d..6f0a99f 100644 (file)
@@ -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,79 @@ FILE_LICENCE ( GPL2_OR_LATER );
  */
 static void dhcp_syntax ( char **argv ) {
        printf ( "Usage:\n"
-                "  %s <interface>\n"
+                "  %s <interface> [<interface> ...]\n"
+                "  %s any\n"
                 "\n"
                 "Configure a network interface using DHCP\n",
-                argv[0] );
+                argv[0], argv[0] );
+}
+
+/**
+ * Attempt to configure a device with dhcp
+ *
+ * @v netdev           Device to configure
+ * @ret rc             Exit code
+ */
+static int dhcp_one_device ( struct net_device *netdev ) {
+       int rc;
+
+       /* Perform DHCP */
+       if ( ( rc = dhcp ( netdev ) ) != 0 ) {
+               /* Close the device on error to avoid out-of-memory */
+               netdev_close ( netdev );
+
+               printf ( "Could not configure %s: %s\n", netdev->name,
+                        strerror ( rc ) );
+               return 1;
+       }
+
+       return 0;
+}
+
+/**
+ * Call dhcp_one_device() for each name in argv
+ *
+ * @v argc             Number of devices
+ * @v argv             List of device names
+ * @ret rc             Exit code
+ */
+static int dhcp_each_device_name ( int argc, char **argv ) {
+       int i;
+       char *netdev_name;
+       struct net_device *netdev;
+
+       for ( i = 0; i < argc; i++ ) {
+               netdev_name = argv[i];
+               netdev = find_netdev ( netdev_name );
+
+               if ( ! netdev ) {
+                       printf ( "No such interface: %s\n", netdev_name );
+                       continue;
+               }
+
+               if ( dhcp_one_device ( netdev ) == 0 )
+                       return 0;
+       }
+
+       printf ( "Could not configure any interface.\n" );
+       return 1;
+}
+
+/**
+ * Call dhcp_one_device() for each device in net_devices
+ *
+ * @ret rc             Exit code
+ */
+static int dhcp_each_device ( void ) {
+       struct net_device *netdev;
+
+       for_each_netdev ( netdev ) {
+               if ( dhcp_one_device ( netdev ) == 0 )
+                       return 0;
+       }
+
+       printf ( "Could not configure any interface.\n" );
+       return 1;
 }
 
 /**
@@ -63,10 +133,7 @@ static int dhcp_exec ( int argc, char **argv ) {
                { "help", 0, NULL, 'h' },
                { NULL, 0, NULL, 0 },
        };
-       const char *netdev_txt;
-       struct net_device *netdev;
        int c;
-       int rc;
 
        /* Parse options */
        while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
@@ -80,28 +147,16 @@ static int dhcp_exec ( int argc, char **argv ) {
                }
        }
 
-       /* Need exactly one interface name remaining after the options */
-       if ( optind != ( argc - 1 ) ) {
+       /* Need one or more interface names remaining after the options */
+       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;
-       }
-
-       /* Perform DHCP */
-       if ( ( rc = dhcp ( netdev ) ) != 0 ) {
-               printf ( "Could not configure %s: %s\n", netdev->name,
-                        strerror ( rc ) );
-               return 1;
-       }
+       if ( strcmp ( argv[optind], "any" ) == 0 )
+               return dhcp_each_device();
 
-       return 0;
+       return dhcp_each_device_name ( argc - optind, argv + optind );
 }
 
 /**