vmd: fake netboot for auto_install

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

vmd: fake netboot for auto_install

Claudio Jeker
I want to be able to build vmd images more or less automatically.
This is why I added 'vmctl wait' and this here is the next step.
It allows to boot bsd.rd and pass the needed info to the kernel that the
system thinks it was PXE booted and so the installer will start an
auto_install automatically.

In short you can do now:
    vmctl create disk.img -s 10G
    vmctl start "installer" -Lc -B net -b ./bsd.rd -d disk.img

This will boot the installer which will then fetch install.conf from your
host. For this to work I adjusted the DHCP code to pass a bootfile of
auto_install in the lease (currently hardcoded). After that it is just a
regular network autoinstall

I decided to add a -B flag which could be extended to include things like
net, disk, cdrom and is therefor similar to qemu -boot option. Ideally vmd
would pass this flag also to SeaBIOS (I left this out for somebody else to
tackle). Especially once SeaBIOS support PXE booting it would be nice to
use this flag to flip the boot mode of the BIOS.

--
:wq Claudio

Index: vmctl/main.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmctl/main.c,v
retrieving revision 1.49
diff -u -p -r1.49 main.c
--- vmctl/main.c 4 Dec 2018 08:17:17 -0000 1.49
+++ vmctl/main.c 4 Dec 2018 12:04:45 -0000
@@ -79,7 +79,7 @@ struct ctl_command ctl_commands[] = {
  { "reset", CMD_RESET, ctl_reset, "[all|vms|switches]" },
  { "show", CMD_STATUS, ctl_status, "[id]" },
  { "start", CMD_START, ctl_start, "\"name\""
-    " [-Lc] [-b image] [-r image] [-m size]\n"
+    " [-Lc] [-b image] [-B device] [-r image] [-m size]\n"
     "\t\t[-n switch] [-i count] [-d disk]* [-t name]" },
  { "status", CMD_STATUS, ctl_status, "[id]" },
  { "stop", CMD_STOP, ctl_stop, "[id|-a] [-fw]" },
@@ -224,7 +224,7 @@ vmmaction(struct parse_result *res)
  case CMD_START:
  ret = vm_start(res->id, res->name, res->size, res->nifs,
     res->nets, res->ndisks, res->disks, res->disktypes,
-    res->path, res->isopath, res->instance);
+    res->path, res->isopath, res->instance, res->bootdevice);
  if (ret) {
  errno = ret;
  err(1, "start VM operation failed");
@@ -843,7 +843,7 @@ ctl_start(struct parse_result *res, int
  argc--;
  argv++;
 
- while ((ch = getopt(argc, argv, "b:r:cLm:n:d:i:t:")) != -1) {
+ while ((ch = getopt(argc, argv, "b:B:cd:i:Lm:n:r:t:")) != -1) {
  switch (ch) {
  case 'b':
  if (res->path)
@@ -852,6 +852,12 @@ ctl_start(struct parse_result *res, int
  err(1, "invalid boot image path");
  if ((res->path = strdup(path)) == NULL)
  errx(1, "strdup");
+ break;
+ case 'B':
+ if (res->bootdevice)
+ errx(1, "boot device specified multiple times");
+ if (strcmp("net", optarg) == 0)
+ res->bootdevice = VMBOOTDEV_NET;
  break;
  case 'r':
  if (res->isopath)
Index: vmctl/vmctl.8
===================================================================
RCS file: /cvs/src/usr.sbin/vmctl/vmctl.8,v
retrieving revision 1.55
diff -u -p -r1.55 vmctl.8
--- vmctl/vmctl.8 4 Dec 2018 08:17:17 -0000 1.55
+++ vmctl/vmctl.8 4 Dec 2018 12:04:45 -0000
@@ -143,6 +143,7 @@ command.
 .It Xo Cm start Ar name
 .Op Fl cL
 .Op Fl b Ar path
+.Op Fl B Ar device
 .Op Fl d Ar disk
 .Op Fl i Ar count
 .Op Fl m Ar size
@@ -158,6 +159,15 @@ Starts a VM defined by the specified nam
 Boot the VM with the specified kernel or BIOS image.
 If not specified, the default is to boot using the BIOS image in
 .Pa /etc/firmware/vmm-bios .
+.It Fl B Ar device
+Force system to boot from the specified device for the next boot.
+.Ar device
+can be set to
+.Ar net
+to perform a PXE boot using the first network interface.
+Currently only supported when starting the VM with
+.Fl b
+specifying a kernel image.
 .It Fl c
 Automatically connect to the VM console.
 .It Fl d Ar disk
Index: vmctl/vmctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmctl/vmctl.c,v
retrieving revision 1.64
diff -u -p -r1.64 vmctl.c
--- vmctl/vmctl.c 4 Dec 2018 08:17:17 -0000 1.64
+++ vmctl/vmctl.c 4 Dec 2018 12:04:45 -0000
@@ -73,7 +73,7 @@ unsigned int info_flags;
 int
 vm_start(uint32_t start_id, const char *name, int memsize, int nnics,
     char **nics, int ndisks, char **disks, int *disktypes, char *kernel,
-    char *iso, char *instance)
+    char *iso, char *instance, unsigned int bootdevice)
 {
  struct vmop_create_params *vmc;
  struct vm_create_params *vcp;
@@ -184,6 +184,7 @@ vm_start(uint32_t start_id, const char *
  if (strlcpy(vmc->vmc_instance, instance,
     sizeof(vmc->vmc_instance)) >= sizeof(vmc->vmc_instance))
  errx(1, "instance vm name too long");
+ vmc->vmc_bootdevice = bootdevice;
 
  imsg_compose(ibuf, IMSG_VMDOP_START_VM_REQUEST, 0, 0, -1,
     vmc, sizeof(struct vmop_create_params));
Index: vmctl/vmctl.h
===================================================================
RCS file: /cvs/src/usr.sbin/vmctl/vmctl.h,v
retrieving revision 1.29
diff -u -p -r1.29 vmctl.h
--- vmctl/vmctl.h 4 Dec 2018 08:17:17 -0000 1.29
+++ vmctl/vmctl.h 4 Dec 2018 12:04:45 -0000
@@ -59,6 +59,7 @@ struct parse_result {
  char *instance;
  unsigned int flags;
  unsigned int mode;
+ unsigned int bootdevice;
  struct ctl_command *ctl;
 };
 
@@ -93,7 +94,7 @@ int create_imagefile(int, const char *,
 int create_raw_imagefile(const char *, long);
 int create_qc2_imagefile(const char *, const char *, long);
 int vm_start(uint32_t, const char *, int, int, char **, int,
-    char **, int *, char *, char *, char *);
+    char **, int *, char *, char *, char *, unsigned int);
 int vm_start_complete(struct imsg *, int *, int);
 void terminate_vm(uint32_t, const char *, unsigned int);
 int terminate_vm_complete(struct imsg *, int *, unsigned int);
Index: vmd/dhcp.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/dhcp.c,v
retrieving revision 1.6
diff -u -p -r1.6 dhcp.c
--- vmd/dhcp.c 21 Nov 2018 12:31:47 -0000 1.6
+++ vmd/dhcp.c 4 Dec 2018 12:04:45 -0000
@@ -108,6 +108,9 @@ dhcp_request(struct vionet_dev *dev, cha
  resp.hlen = req.hlen;
  resp.xid = req.xid;
 
+ if (dev->pxeboot)
+ strlcpy(resp.file, "auto_install", sizeof resp.file);
+
  if ((client_addr.s_addr =
     vm_priv_addr(&env->vmd_cfg,
     dev->vm_vmid, dev->idx, 1)) == 0)
@@ -118,12 +121,10 @@ dhcp_request(struct vionet_dev *dev, cha
     sizeof(client_addr));
  ss2sin(&pc.pc_dst)->sin_port = htons(CLIENT_PORT);
 
- if ((server_addr.s_addr =
-    vm_priv_addr(&env->vmd_cfg,
-    dev->vm_vmid, dev->idx, 0)) == 0)
+ if ((server_addr.s_addr = vm_priv_addr(&env->vmd_cfg, dev->vm_vmid,
+    dev->idx, 0)) == 0)
  return (-1);
- memcpy(&resp.siaddr, &server_addr,
-    sizeof(server_addr));
+ memcpy(&resp.siaddr, &server_addr, sizeof(server_addr));
  memcpy(&ss2sin(&pc.pc_src)->sin_addr, &server_addr,
     sizeof(server_addr));
  ss2sin(&pc.pc_src)->sin_port = htons(SERVER_PORT);
Index: vmd/loadfile.h
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/loadfile.h,v
retrieving revision 1.10
diff -u -p -r1.10 loadfile.h
--- vmd/loadfile.h 29 Nov 2017 02:46:10 -0000 1.10
+++ vmd/loadfile.h 4 Dec 2018 12:04:45 -0000
@@ -74,7 +74,7 @@
 #define NPTE_PG (PAGE_SIZE / sizeof(uint64_t))
 
 int loadfile_elf(FILE *, struct vm_create_params *,
-    struct vcpu_reg_state *, uint32_t, uint32_t);
+    struct vcpu_reg_state *, uint32_t, uint32_t, unsigned int);
 
 size_t mread(FILE *, paddr_t, size_t);
 
Index: vmd/loadfile_elf.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/loadfile_elf.c,v
retrieving revision 1.30
diff -u -p -r1.30 loadfile_elf.c
--- vmd/loadfile_elf.c 17 Jul 2018 13:47:06 -0000 1.30
+++ vmd/loadfile_elf.c 4 Dec 2018 12:04:45 -0000
@@ -122,7 +122,7 @@ static void setsegment(struct mem_segmen
 static int elf32_exec(FILE *, Elf32_Ehdr *, u_long *, int);
 static int elf64_exec(FILE *, Elf64_Ehdr *, u_long *, int);
 static size_t create_bios_memmap(struct vm_create_params *, bios_memmap_t *);
-static uint32_t push_bootargs(bios_memmap_t *, size_t);
+static uint32_t push_bootargs(bios_memmap_t *, size_t, bios_bootmac_t *);
 static size_t push_stack(uint32_t, uint32_t, uint32_t, uint32_t);
 static void push_gdt(void);
 static void push_pt_32(void);
@@ -286,13 +286,15 @@ push_pt_64(void)
  */
 int
 loadfile_elf(FILE *fp, struct vm_create_params *vcp,
-    struct vcpu_reg_state *vrs, uint32_t bootdev, uint32_t howto)
+    struct vcpu_reg_state *vrs, uint32_t bootdev, uint32_t howto,
+    unsigned int bootdevice)
 {
  int r, is_i386 = 0;
  uint32_t bootargsz;
  size_t n, stacksize;
  u_long marks[MARK_MAX];
  bios_memmap_t memmap[VMM_MAX_MEM_RANGES + 1];
+ bios_bootmac_t bm, *bootmac = NULL;
 
  if ((r = fread(&hdr, 1, sizeof(hdr), fp)) != sizeof(hdr))
  return 1;
@@ -323,8 +325,12 @@ loadfile_elf(FILE *fp, struct vm_create_
  else
  push_pt_64();
 
+ if (bootdevice & VMBOOTDEV_NET) {
+ bootmac = &bm;
+ memcpy(bootmac, vcp->vcp_macs[0], ETHER_ADDR_LEN);
+ }
  n = create_bios_memmap(vcp, memmap);
- bootargsz = push_bootargs(memmap, n);
+ bootargsz = push_bootargs(memmap, n, bootmac);
  stacksize = push_stack(bootargsz, marks[MARK_END], bootdev, howto);
 
 #ifdef __i386__
@@ -409,9 +415,9 @@ create_bios_memmap(struct vm_create_para
  *  The size of the bootargs
  */
 static uint32_t
-push_bootargs(bios_memmap_t *memmap, size_t n)
+push_bootargs(bios_memmap_t *memmap, size_t n, bios_bootmac_t *bootmac)
 {
- uint32_t memmap_sz, consdev_sz, i;
+ uint32_t memmap_sz, consdev_sz, bootmac_sz, i;
  bios_consdev_t consdev;
  uint32_t ba[1024];
 
@@ -433,13 +439,22 @@ push_bootargs(bios_memmap_t *memmap, siz
  ba[i + 1] = consdev_sz;
  ba[i + 2] = consdev_sz;
  memcpy(&ba[i + 3], &consdev, sizeof(bios_consdev_t));
- i = i + 3 + (sizeof(bios_consdev_t) / 4);
+ i += consdev_sz / sizeof(int);
+
+ if (bootmac) {
+ bootmac_sz = 3 * sizeof(int) + (sizeof(bios_bootmac_t) + 3) & ~3;
+ ba[i] = 0x7;   /* bootmac */
+ ba[i + 1] = bootmac_sz;
+ ba[i + 2] = bootmac_sz;
+ memcpy(&ba[i + 3], bootmac, sizeof(bios_bootmac_t));
+ i += bootmac_sz / sizeof(int);
+ }
 
- ba[i] = 0xFFFFFFFF; /* BOOTARG_END */
+ ba[i++] = 0xFFFFFFFF; /* BOOTARG_END */
 
  write_mem(BOOTARGS_PAGE, ba, PAGE_SIZE);
 
- return (memmap_sz + consdev_sz);
+ return (i * sizeof(int));
 }
 
 /*
Index: vmd/virtio.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/virtio.c,v
retrieving revision 1.74
diff -u -p -r1.74 virtio.c
--- vmd/virtio.c 26 Nov 2018 10:39:30 -0000 1.74
+++ vmd/virtio.c 4 Dec 2018 12:04:45 -0000
@@ -1940,14 +1940,17 @@ virtio_init(struct vmd_vm *vm, int child
     vmc->vmc_ifflags[i] & VMIFF_LOCKED ? 1 : 0;
  vionet[i].local =
     vmc->vmc_ifflags[i] & VMIFF_LOCAL ? 1 : 0;
+ if (i == 0 && vmc->vmc_bootdevice & VMBOOTDEV_NET)
+ vionet[i].pxeboot = 1;
  vionet[i].idx = i;
  vionet[i].pci_id = id;
 
- log_debug("%s: vm \"%s\" vio%u lladdr %s%s%s",
+ log_debug("%s: vm \"%s\" vio%u lladdr %s%s%s%s",
     __func__, vcp->vcp_name, i,
     ether_ntoa((void *)vionet[i].mac),
     vionet[i].lockedmac ? ", locked" : "",
-    vionet[i].local ? ", local" : "");
+    vionet[i].local ? ", local" : "",
+    vionet[i].pxeboot ? ", pxeboot" : "");
  }
  }
 
Index: vmd/virtio.h
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/virtio.h,v
retrieving revision 1.33
diff -u -p -r1.33 virtio.h
--- vmd/virtio.h 26 Nov 2018 10:39:30 -0000 1.33
+++ vmd/virtio.h 4 Dec 2018 12:04:45 -0000
@@ -212,6 +212,7 @@ struct vionet_dev {
  int idx;
  int lockedmac;
  int local;
+ int pxeboot;
 
  uint8_t pci_id;
 };
Index: vmd/vm.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/vm.c,v
retrieving revision 1.41
diff -u -p -r1.41 vm.c
--- vmd/vm.c 8 Oct 2018 16:32:01 -0000 1.41
+++ vmd/vm.c 4 Dec 2018 12:04:45 -0000
@@ -335,7 +335,7 @@ start_vm(struct vmd_vm *vm, int fd)
 
  /* Load kernel image */
  ret = loadfile_elf(fp, vcp, &vrs,
-    vmboot.vbp_bootdev, vmboot.vbp_howto);
+    vmboot.vbp_bootdev, vmboot.vbp_howto, vmc->vmc_bootdevice);
 
  /*
  * Try BIOS as a fallback (only if it was provided as an image
Index: vmd/vmd.h
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/vmd.h,v
retrieving revision 1.87
diff -u -p -r1.87 vmd.h
--- vmd/vmd.h 4 Dec 2018 08:15:09 -0000 1.87
+++ vmd/vmd.h 4 Dec 2018 12:04:45 -0000
@@ -173,6 +173,11 @@ struct vmop_create_params {
  unsigned int vmc_checkaccess;
 
  /* userland-only part of the create params */
+ unsigned int vmc_bootdevice;
+#define VMBOOTDEV_AUTO 0
+#define VMBOOTDEV_DISK 1
+#define VMBOOTDEV_CDROM 2
+#define VMBOOTDEV_NET 3
  unsigned int vmc_ifflags[VMM_MAX_NICS_PER_VM];
 #define VMIFF_UP 0x01
 #define VMIFF_LOCKED 0x02

Reply | Threaded
Open this post in threaded view
|

Re: vmd: fake netboot for auto_install

Carlos Cardenas
On Tue, Dec 04, 2018 at 01:19:46PM +0100, Claudio Jeker wrote:

> I want to be able to build vmd images more or less automatically.
> This is why I added 'vmctl wait' and this here is the next step.
> It allows to boot bsd.rd and pass the needed info to the kernel that the
> system thinks it was PXE booted and so the installer will start an
> auto_install automatically.
>
> In short you can do now:
>     vmctl create disk.img -s 10G
>     vmctl start "installer" -Lc -B net -b ./bsd.rd -d disk.img
>
> This will boot the installer which will then fetch install.conf from your
> host. For this to work I adjusted the DHCP code to pass a bootfile of
> auto_install in the lease (currently hardcoded). After that it is just a
> regular network autoinstall
>
> I decided to add a -B flag which could be extended to include things like
> net, disk, cdrom and is therefor similar to qemu -boot option. Ideally vmd
> would pass this flag also to SeaBIOS (I left this out for somebody else to
> tackle). Especially once SeaBIOS support PXE booting it would be nice to
> use this flag to flip the boot mode of the BIOS.
>
> --
> :wq Claudio

I like this because it's lighter weight than the patch I had come up
with from g2k18.

At the pace you're going, are you sure you don't want to tackle boot
order with SeaBIOS? ;-)

Ok ccardenas@

+--+
Carlos