On 2023-04-07 11:55 a.m., Simon Glass wrote:
Hi Sean,

On Fri, 7 Apr 2023 at 18:56, <seanedm...@linux.microsoft.com> wrote:
From: Sean Edmond <seanedm...@microsoft.com>

Adds commands to support DHCP and PXE with IPv6.

New configs added:
- CMD_DHCP6
- DHCP6_PXE_CLIENTARCH
- DHCP6_PXE_DHCP_OPTION
- DHCP6_ENTERPRISE_ID

New commands added (when IPv6 is enabled):
- dhcp6
- pxe get -ipv6
- pxe boot -ipv6

Signed-off-by: Sean Edmond <seanedm...@microsoft.com>
---
  boot/bootmeth_distro.c |  2 +-
  boot/bootmeth_pxe.c    |  4 +-
  boot/pxe_utils.c       |  3 +-
  cmd/Kconfig            | 26 +++++++++++++
  cmd/net.c              | 23 +++++++++++
  cmd/pxe.c              | 86 +++++++++++++++++++++++++++++++++++++-----
  cmd/sysboot.c          |  2 +-
  include/pxe_utils.h    | 10 ++++-
  8 files changed, 140 insertions(+), 16 deletions(-)
With nits below:

Reviewed-by: Simon Glass <s...@chromium.org>

[..]

+if CMD_DHCP6
+
+config DHCP6_PXE_CLIENTARCH
+       hex
+       default 0x16 if ARM64
+       default 0x15 if ARM
+       default 0xFF
Do we need a separate option or could we use BOOTP_PXE_CLIENTARCH ?
I created a new option because I wanted to change the default to 0xFF ("undefined" Processor Architecture Types according to https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml). I wanted to do this without changing BOOTP_PXE_CLIENTARCH , and potentially disrupting exisiting DHCPv4 implementations.
+
+config DHCP6_PXE_DHCP_OPTION
+       bool "Request & store 'pxe_configfile' from DHCP6 server"
+
+config DHCP6_ENTERPRISE_ID
+       int "Enterprise ID to send in DHCPv6 Vendor Class Option"
+       default 0
+
+endif
+
  config CMD_TFTPBOOT
         bool "tftpboot"
         default y
diff --git a/cmd/net.c b/cmd/net.c
index d5e20843dd..95529a9d12 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -111,6 +111,29 @@ U_BOOT_CMD(
  );
  #endif

+#if defined(CONFIG_CMD_DHCP6)
+static int do_dhcp6(struct cmd_tbl *cmdtp, int flag, int argc,
+                   char *const argv[])
+{
+       int i;
+       int dhcp_argc;
+       char *dhcp_argv[] = {NULL, NULL, NULL, NULL};
+
+       /* Add -ipv6 flag for autoload */
+       for (i = 0; i < argc; i++)
+               dhcp_argv[i] = argv[i];
+       dhcp_argc = argc + 1;
+       dhcp_argv[dhcp_argc - 1] =  USE_IP6_CMD_PARAM;
+
+       return netboot_common(DHCP6, cmdtp, dhcp_argc, dhcp_argv);
+}
+
+U_BOOT_CMD(dhcp6,      3,      1,      do_dhcp6,
+          "boot image via network using DHCPv6/TFTP protocol. \n"
+          "Use IPv6 hostIPaddr framed with [] brackets",
+          "[loadAddress] [[hostIPaddr:]bootfilename]");
+#endif
+
  #if defined(CONFIG_CMD_DHCP)
  static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
                    char *const argv[])
diff --git a/cmd/pxe.c b/cmd/pxe.c
index db8e4697f2..71e6fd9633 100644
--- a/cmd/pxe.c
+++ b/cmd/pxe.c
@@ -8,6 +8,7 @@
  #include <command.h>
  #include <fs.h>
  #include <net.h>
+#include <net6.h>

  #include "pxe_utils.h"

@@ -29,12 +30,20 @@ static int do_get_tftp(struct pxe_context *ctx, const char 
*file_path,
  {
         char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
         int ret;
+       int num_args;

         tftp_argv[1] = file_addr;
         tftp_argv[2] = (void *)file_path;
+       if (ctx->use_ipv6) {
+               tftp_argv[3] = USE_IP6_CMD_PARAM;
+               num_args = 4;
+       } else {
+               num_args = 3;
+       }

-       if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
+       if (do_tftpb(ctx->cmdtp, 0, num_args, tftp_argv))
                 return -ENOENT;
+
         ret = pxe_get_file_size(sizep);
         if (ret)
                 return log_msg_ret("tftp", ret);
@@ -43,6 +52,23 @@ static int do_get_tftp(struct pxe_context *ctx, const char 
*file_path,
         return 1;
  }

+#if defined(CONFIG_DHCP6_PXE_DHCP_OPTION)
+/*
+ * Looks for a pxe file with specified config file name,
+ * which is received from DHCPv4 option 209 or
+ * DHCPv6 option 60.
+ *
+ * Returns 1 on success or < 0 on error.
+ */
+static inline int pxe_dhcp_option_path(struct pxe_context *ctx, unsigned long 
pxefile_addr_r)
Please drop the inline as the compiler can handle that.

+{
+       int ret = get_pxe_file(ctx, pxelinux_configfile, pxefile_addr_r);
+
+       free(pxelinux_configfile);
+
+       return ret;
+}
+#endif
  /*
   * Looks for a pxe file with a name based on the pxeuuid environment variable.
   *
@@ -105,15 +131,25 @@ static int pxe_ipaddr_paths(struct pxe_context *ctx, 
unsigned long pxefile_addr_
         return -ENOENT;
  }

-int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong *sizep)
+int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong *sizep, bool use_ipv6)
  {
         struct cmd_tbl cmdtp[] = {};    /* dummy */
         struct pxe_context ctx;
         int i;

         if (pxe_setup_ctx(&ctx, cmdtp, do_get_tftp, NULL, false,
-                         env_get("bootfile")))
+                         env_get("bootfile"), use_ipv6))
                 return -ENOMEM;
+
+#if defined(CONFIG_DHCP6_PXE_DHCP_OPTION)
It's a bit annoying that pxelinux_configfile causes these #ifdefs. How
about always having pxelinux_configfile and then you don't need to
worry. It can just be NULL when not used. It is only BSS space, after
all...

+       if (pxelinux_configfile && use_ipv6) {
+               if (pxe_dhcp_option_path(&ctx, pxefile_addr_r) > 0)
+                       goto done;
+
+               goto error_exit;
+       }
+#endif
+
         /*
          * Keep trying paths until we successfully get a file we're looking
          * for.
@@ -131,9 +167,12 @@ int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong 
*sizep)
                 i++;
         }

+#if defined(CONFIG_DHCP6_PXE_DHCP_OPTION)
...then you can use if (IS_ENABLED(... here

+error_exit:
         pxe_destroy_ctx(&ctx);

         return -ENOENT;
+#endif
  done:
         *bootdirp = env_get("bootfile");

@@ -169,9 +208,17 @@ do_pxe_get(struct cmd_tbl *cmdtp, int flag, int argc, char 
*const argv[])
         char *fname;
         ulong size;
         int ret;
+       bool use_ipv6 = false;

-       if (argc != 1)
-               return CMD_RET_USAGE;
+       if (IS_ENABLED(CONFIG_IPV6)) {
+               if (argc != 1 && argc != 2)
+                       return CMD_RET_USAGE;
+               if (!strcmp(argv[argc - 1], USE_IP6_CMD_PARAM))
+                       use_ipv6 = true;
+       } else {
+               if (argc != 1)
+                       return CMD_RET_USAGE;
+       }

         pxefile_addr_str = from_env("pxefile_addr_r");

@@ -183,7 +230,7 @@ do_pxe_get(struct cmd_tbl *cmdtp, int flag, int argc, char 
*const argv[])
         if (ret < 0)
                 return 1;

-       ret = pxe_get(pxefile_addr_r, &fname, &size);
+       ret = pxe_get(pxefile_addr_r, &fname, &size, use_ipv6);
         switch (ret) {
         case 0:
                 printf("Config file '%s' found\n", fname);
@@ -211,13 +258,19 @@ do_pxe_boot(struct cmd_tbl *cmdtp, int flag, int argc, 
char *const argv[])
         char *pxefile_addr_str;
         struct pxe_context ctx;
         int ret;
+       bool use_ipv6 = false;
+
+       if (IS_ENABLED(CONFIG_IPV6)) {
+               if (!strcmp(argv[argc - 1], USE_IP6_CMD_PARAM))
+                       use_ipv6 = true;
+       }

-       if (argc == 1) {
+       if (argc == 1 || (argc == 2 && use_ipv6)) {
                 pxefile_addr_str = from_env("pxefile_addr_r");
                 if (!pxefile_addr_str)
                         return 1;

-       } else if (argc == 2) {
+       } else if (argc == 2 || (argc == 3 && use_ipv6)) {
                 pxefile_addr_str = argv[1];
         } else {
                 return CMD_RET_USAGE;
@@ -229,7 +282,7 @@ do_pxe_boot(struct cmd_tbl *cmdtp, int flag, int argc, char 
*const argv[])
         }

         if (pxe_setup_ctx(&ctx, cmdtp, do_get_tftp, NULL, false,
-                         env_get("bootfile"))) {
+                         env_get("bootfile"), use_ipv6)) {
                 printf("Out of memory\n");
                 return CMD_RET_FAILURE;
         }
@@ -244,8 +297,13 @@ do_pxe_boot(struct cmd_tbl *cmdtp, int flag, int argc, 
char *const argv[])
  }

  static struct cmd_tbl cmd_pxe_sub[] = {
+#if IS_ENABLED(CONFIG_IPV6)
+       U_BOOT_CMD_MKENT(get, 2, 1, do_pxe_get, "", ""),
+       U_BOOT_CMD_MKENT(boot, 3, 1, do_pxe_boot, "", "")
+#else
         U_BOOT_CMD_MKENT(get, 1, 1, do_pxe_get, "", ""),
         U_BOOT_CMD_MKENT(boot, 2, 1, do_pxe_boot, "", "")
+#endif
That's a bit ugly. How about using the max and then checking it in the C code?

  };

  static void __maybe_unused pxe_reloc(void)
@@ -281,9 +339,19 @@ static int do_pxe(struct cmd_tbl *cmdtp, int flag, int 
argc, char *const argv[])
         return CMD_RET_USAGE;
  }

+#if IS_ENABLED(CONFIG_IPV6)
+U_BOOT_CMD(pxe, 4, 1, do_pxe,
+          "commands to get and boot from pxe files\n"
+          "To use IPv6 add -ipv6 parameter",
+          "get [" USE_IP6_CMD_PARAM "] - try to retrieve a pxe file using 
tftp\n"
+          "pxe boot [pxefile_addr_r] [-ipv6] - boot from the pxe file at 
pxefile_addr_r\n"
+);
+#else
  U_BOOT_CMD(pxe, 3, 1, do_pxe,
            "commands to get and boot from pxe files",
            "get - try to retrieve a pxe file using tftp\n"
            "pxe boot [pxefile_addr_r] - boot from the pxe file at 
pxefile_addr_r\n"
  );
  #endif
same here

+
+#endif /* CONFIG_CMD_NET */
[..]

Regards,
Simon

Reply via email to