[PATCH 2/2] net: dhcp6: pxe: Add DHCP/PXE commands for IPv6
Vyacheslav V. Mitrofanov
v.v.mitrofanov at yadro.com
Sun Mar 5 12:44:00 CET 2023
> From: Sean Edmond <seanedmond at microsoft.com>
>
> Adds commands to support DHCP and PXE with IPv6.
>
> 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/net.c | 22 +++++++++++
> cmd/pxe.c | 86 +++++++++++++++++++++++++++++++++++++---
> --
> cmd/sysboot.c | 2 +-
> include/net.h | 2 +
> include/net6.h | 2 -
> include/pxe_utils.h | 10 ++++-
> 9 files changed, 115 insertions(+), 18 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/net.c b/cmd/net.c
> index 4227321871..88d53d14d5 100644
> --- a/cmd/net.c
> +++ b/cmd/net.c
> @@ -111,6 +111,28 @@ 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",
> + "[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..ebc44fd661 100644
> --- a/cmd/pxe.c
> +++ b/cmd/pxe.c
> @@ -11,6 +11,10 @@
>
> #include "pxe_utils.h"
>
> +#if IS_ENABLED(CONFIG_IPV6)
> +#include <net6.h>
> +#endif
> +
> #ifdef CONFIG_CMD_NET
> const char *pxe_default_paths[] = {
> #ifdef CONFIG_SYS_SOC
> @@ -29,12 +33,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 +55,22 @@ 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 DHCP option 209.
> + *
> + * Returns 1 on success or < 0 on error.
> + */
> +static inline 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;
> +}
> +#endif
> /*
> * Looks for a pxe file with a name based on the pxeuuid environment
> variable.
> *
> @@ -105,15 +133,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)
> + 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,6 +169,7 @@ int pxe_get(ulong pxefile_addr_r, char
> **bootdirp, ulong *sizep)
> i++;
> }
>
> +error_exit:
> pxe_destroy_ctx(&ctx);
>
> return -ENOENT;
> @@ -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
> };
>
> 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
> +
> +#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/net.h b/include/net.h
> index cac818e292..7463b1285b 100644
> --- a/include/net.h
> +++ b/include/net.h
> @@ -49,6 +49,8 @@ struct udevice;
> */
> #define ARP_HLEN_ASCII (ARP_HLEN * 2) + (ARP_HLEN - 1)
>
> +#define USE_IP6_CMD_PARAM "-ipv6"
> +
> /* IPv4 addresses are always 32 bits in size */
> struct in_addr {
> __be32 s_addr;
> diff --git a/include/net6.h b/include/net6.h
> index 9b3de028e6..571c0593e5 100644
> --- a/include/net6.h
> +++ b/include/net6.h
> @@ -39,8 +39,6 @@ struct in6_addr {
> #define IPV6_ADDRSCOPE_ORG 0x08
> #define IPV6_ADDRSCOPE_GLOBAL 0x0E
>
> -#define USE_IP6_CMD_PARAM "-ipv6"
> -
> /**
> * struct ipv6hdr - Internet Protocol V6 (IPv6) header.
> *
> 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.39.0
>
Tested on Si-Five Hi-Five Unmatched board (RISC-V)
Tested-by: Viacheslav Mitrofanov <v.v.mitrofanov at yadro.com>
More information about the U-Boot
mailing list