[PATCH v3 2/3] net: dhcp6: pxe: Add DHCP/PXE commands for IPv6

Ramon Fried rfried.dev at gmail.com
Tue Apr 25 21:06:44 CEST 2023


On Tue, Apr 11, 2023 at 8:48 PM <seanedmond at linux.microsoft.com> wrote:
>
> From: Sean Edmond <seanedmond at 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 <seanedmond at 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              | 85 ++++++++++++++++++++++++++++++++++--------
>  cmd/sysboot.c          |  2 +-
>  include/pxe_utils.h    | 10 ++++-
>  8 files changed, 132 insertions(+), 23 deletions(-)
>
> diff --git a/boot/bootmeth_distro.c b/boot/bootmeth_distro.c
> index 356929828b..b4b73ecbf5 100644
> --- a/boot/bootmeth_distro.c
> +++ b/boot/bootmeth_distro.c
> @@ -150,7 +150,7 @@ static int distro_boot(struct udevice *dev, struct bootflow *bflow)
>         info.dev = dev;
>         info.bflow = bflow;
>         ret = pxe_setup_ctx(&ctx, &cmdtp, distro_getfile, &info, true,
> -                           bflow->subdir);
> +                           bflow->subdir, false);
>         if (ret)
>                 return log_msg_ret("ctx", -EINVAL);
>
> diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c
> index ecf8557af8..5a8af2bbd0 100644
> --- a/boot/bootmeth_pxe.c
> +++ b/boot/bootmeth_pxe.c
> @@ -70,7 +70,7 @@ static int distro_pxe_read_bootflow(struct udevice *dev, struct bootflow *bflow)
>         addr = simple_strtoul(addr_str, NULL, 16);
>
>         log_debug("calling pxe_get()\n");
> -       ret = pxe_get(addr, &bootdir, &size);
> +       ret = pxe_get(addr, &bootdir, &size, false);
>         log_debug("pxe_get() returned %d\n", ret);
>         if (ret)
>                 return log_msg_ret("pxeb", ret);
> @@ -146,7 +146,7 @@ static int distro_pxe_boot(struct udevice *dev, struct bootflow *bflow)
>         info.bflow = bflow;
>         info.cmdtp = &cmdtp;
>         ret = pxe_setup_ctx(ctx, &cmdtp, distro_pxe_getfile, &info, false,
> -                           bflow->subdir);
> +                           bflow->subdir, false);
>         if (ret)
>                 return log_msg_ret("ctx", -EINVAL);
>
> diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c
> index 3a1e50f2b1..d13c47dd94 100644
> --- a/boot/pxe_utils.c
> +++ b/boot/pxe_utils.c
> @@ -1578,7 +1578,7 @@ void handle_pxe_menu(struct pxe_context *ctx, struct pxe_menu *cfg)
>
>  int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl *cmdtp,
>                   pxe_getfile_func getfile, void *userdata,
> -                 bool allow_abs_path, const char *bootfile)
> +                 bool allow_abs_path, const char *bootfile, bool use_ipv6)
>  {
>         const char *last_slash;
>         size_t path_len = 0;
> @@ -1588,6 +1588,7 @@ int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl *cmdtp,
>         ctx->getfile = getfile;
>         ctx->userdata = userdata;
>         ctx->allow_abs_path = allow_abs_path;
> +       ctx->use_ipv6 = use_ipv6;
>
>         /* figure out the boot directory, if there is one */
>         if (bootfile && strlen(bootfile) >= MAX_TFTP_PATH_LEN)
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index e45b8847ae..460f29883a 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -1673,6 +1673,15 @@ config CMD_DHCP
>         help
>           Boot image via network using DHCP/TFTP protocol
>
> +config CMD_DHCP6
> +       bool "dhcp6"
> +       depends on IPV6
> +       help
> +         Boot image via network using DHCPv6/TFTP protocol using IPv6.
> +
> +         Will perform 4-message exchange with DHCPv6 server, requesting
> +         the minimum required options to TFTP boot. Complies with RFC 8415.
> +
>  config BOOTP_MAY_FAIL
>         bool "Allow for the BOOTP/DHCP server to not be found"
>         depends on CMD_BOOTP
> @@ -1786,6 +1795,23 @@ config BOOTP_VCI_STRING
>         default "U-Boot.arm" if ARM
>         default "U-Boot"
>
> +if CMD_DHCP6
> +
> +config DHCP6_PXE_CLIENTARCH
> +       hex
> +       default 0x16 if ARM64
> +       default 0x15 if ARM
> +       default 0xFF
> +
> +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..76fd2e7d34 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..677142520b 100644
> --- a/cmd/pxe.c
> +++ b/cmd/pxe.c
> @@ -8,6 +8,8 @@
>  #include <command.h>
>  #include <fs.h>
>  #include <net.h>
> +#include <net6.h>
> +#include <malloc.h>
>
>  #include "pxe_utils.h"
>
> @@ -29,12 +31,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 +53,22 @@ static int do_get_tftp(struct pxe_context *ctx, const char *file_path,
>         return 1;
>  }
>
> +/*
> + * 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 int pxe_dhcp_option_path(struct pxe_context *ctx, unsigned long pxefile_addr_r)
> +{
> +       int ret = get_pxe_file(ctx, pxelinux_configfile, pxefile_addr_r);
> +
> +       free(pxelinux_configfile);
> +
> +       return ret;
> +}
> +
>  /*
>   * Looks for a pxe file with a name based on the pxeuuid environment variable.
>   *
> @@ -105,15 +131,24 @@ 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 (IS_ENABLED(CONFIG_DHCP6_PXE_DHCP_OPTION) &&
> +           pxelinux_configfile && use_ipv6) {
> +               if (pxe_dhcp_option_path(&ctx, pxefile_addr_r) > 0)
> +                       goto done;
> +
> +               goto error_exit;
> +       }
> +
>         /*
>          * Keep trying paths until we successfully get a file we're looking
>          * for.
> @@ -131,6 +166,7 @@ int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong *sizep)
>                 i++;
>         }
>
> +error_exit:
>         pxe_destroy_ctx(&ctx);
>
>         return -ENOENT;
> @@ -169,9 +205,18 @@ 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 (!strcmp(argv[argc - 1], USE_IP6_CMD_PARAM))
> +                       use_ipv6 = true;
> +
> +               if (!(argc == 1 || (argc == 2 && use_ipv6)))
> +                       return CMD_RET_USAGE;
> +       } else {
> +               if (argc != 1)
> +                       return CMD_RET_USAGE;
> +       }
>
>         pxefile_addr_str = from_env("pxefile_addr_r");
>
> @@ -183,7 +228,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 +256,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 +280,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 +295,8 @@ do_pxe_boot(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
>  }
>
>  static struct cmd_tbl cmd_pxe_sub[] = {
> -       U_BOOT_CMD_MKENT(get, 1, 1, do_pxe_get, "", ""),
> -       U_BOOT_CMD_MKENT(boot, 2, 1, do_pxe_boot, "", "")
> +       U_BOOT_CMD_MKENT(get, 2, 1, do_pxe_get, "", ""),
> +       U_BOOT_CMD_MKENT(boot, 3, 1, do_pxe_boot, "", "")
>  };
>
>  static void __maybe_unused pxe_reloc(void)
> @@ -281,9 +332,11 @@ static int do_pxe(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
>         return CMD_RET_USAGE;
>  }
>
> -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"
> +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"
>  );
> -#endif
> +
> +#endif /* CONFIG_CMD_NET */
> diff --git a/cmd/sysboot.c b/cmd/sysboot.c
> index 04c0702026..63a7806deb 100644
> --- a/cmd/sysboot.c
> +++ b/cmd/sysboot.c
> @@ -101,7 +101,7 @@ static int do_sysboot(struct cmd_tbl *cmdtp, int flag, int argc,
>         }
>
>         if (pxe_setup_ctx(&ctx, cmdtp, sysboot_read_file, &info, true,
> -                         filename)) {
> +                         filename, false)) {
>                 printf("Out of memory\n");
>                 return CMD_RET_FAILURE;
>         }
> diff --git a/include/pxe_utils.h b/include/pxe_utils.h
> index 1e5e8424f5..9f19593048 100644
> --- a/include/pxe_utils.h
> +++ b/include/pxe_utils.h
> @@ -93,6 +93,7 @@ typedef int (*pxe_getfile_func)(struct pxe_context *ctx, const char *file_path,
>   * @bootdir: Directory that files are loaded from ("" if no directory). This is
>   *     allocated
>   * @pxe_file_size: Size of the PXE file
> + * @use_ipv6: TRUE : use IPv6 addressing, FALSE : use IPv4 addressing
>   */
>  struct pxe_context {
>         struct cmd_tbl *cmdtp;
> @@ -112,6 +113,7 @@ struct pxe_context {
>         bool allow_abs_path;
>         char *bootdir;
>         ulong pxe_file_size;
> +       bool use_ipv6;
>  };
>
>  /**
> @@ -209,12 +211,14 @@ int format_mac_pxe(char *outbuf, size_t outbuf_len);
>   * @allow_abs_path: true to allow absolute paths
>   * @bootfile: Bootfile whose directory loaded files are relative to, NULL if
>   *     none
> + * @use_ipv6: TRUE : use IPv6 addressing
> + *            FALSE : use IPv4 addressing
>   * Return: 0 if OK, -ENOMEM if out of memory, -E2BIG if bootfile is larger than
>   *     MAX_TFTP_PATH_LEN bytes
>   */
>  int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl *cmdtp,
>                   pxe_getfile_func getfile, void *userdata,
> -                 bool allow_abs_path, const char *bootfile);
> +                 bool allow_abs_path, const char *bootfile, bool use_ipv6);
>
>  /**
>   * pxe_destroy_ctx() - Destroy a PXE context
> @@ -251,7 +255,9 @@ int pxe_get_file_size(ulong *sizep);
>   *     "rpi/info", which indicates that all files should be fetched from the
>   *     "rpi/" subdirectory
>   * @sizep: Size of the PXE file (not bootfile)
> + * @use_ipv6: TRUE : use IPv6 addressing
> + *            FALSE : use IPv4 addressing
>   */
> -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);
>
>  #endif /* __PXE_UTILS_H */
> --
> 2.40.0
>
Reviewed-by: Ramon Fried <rfried.dev at gmail.com>


More information about the U-Boot mailing list