Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

virt-v2v 2.5.2 not detecting the firmware type correctly in some flows #52

Open
bkhizgiy opened this issue Apr 9, 2024 · 13 comments
Open

Comments

@bkhizgiy
Copy link
Contributor

bkhizgiy commented Apr 9, 2024

When converting from OVA file that isnt specifing the firmware type in OVF configuration, the result yaml file contains the wrong firmware type.

attaching some conversion logs of VM with UEFI:

from the conversion steps it didnt recognize the UEFI type:

[ 105.9] Setting up the destination: -o kubevirt -os /var/tmp/v2v
[ 105.9] Assigning disks to buses
virtio-blk slot 0:
	0 [scsi]
[ 105.9] Checking if the guest needs BIOS or UEFI to boot

but from the debug logs it does recognizing UEFI, for example:

First-stage UEFI bootloader, app2_description: Initial UEFI bootloader that handles chaining to a trusted full\nbootloader under secure boot environments. This package contains the\nversion signed by the UEFI signing service.

and we ended up having this yaml:

apiVersion: kubevirt.io/v1
kind: VirtualMachineInstance
metadata:
  name: vm-mkzy
spec:
  domain:
    os:
      firmware: bios
    resources:
      requests:
        memory: 4096Mi
      features:
    cpu:
      cores: 2
    devices:
      rng: {}
      disks:
      - disk:
          bus: virtio
        name: disk-0
  volumes:
  - hostDisk:
      path: /var/tmp/v2v/vm-mkzy-sda
      type: Disk
    name: disk-0
  terminationGracePeriodSeconds: 0

expected:

  domain:
    os:
      firmware: uefi

Full conversion logs are attached.
virt-v2v-logs.txt

@rwmjones
Copy link
Member

rwmjones commented Apr 9, 2024

I think this is actually a bug in virt-v2v.

Here:

virt-v2v/input/OVF.ml

Lines 96 to 103 in 089d9a2

let firmware = Option.value ~default:"bios" (xpath_string "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/vmw:Config[@vmw:key=\"firmware\"]/@vmw:value") in
let firmware =
match firmware with
| "bios" -> BIOS
| "efi" -> UEFI
| s ->
error (f_"unknown Config:firmware value %s (expected \"bios\" \
or \"efi\")") s in

we attempt to parse the XPath expression /ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/vmw:Config[@vmw:key=\"firmware\"]/@vmw:value from image.ovf.

Unfortunately we don't log the contents of image.ovf, but trusting what you said in your description, that key is missing from the OVF file.

What happens if it is missing is we force it to default:"bios", which is wrong. This means it overrides the detection we do from the guest itself here:

virt-v2v/convert/convert.ml

Lines 269 to 277 in 089d9a2

let target_firmware =
match source.s_firmware with
| BIOS -> TargetBIOS
| UEFI -> TargetUEFI
| UnknownFirmware ->
match i_firmware with
| I_BIOS -> TargetBIOS
| I_UEFI _ -> TargetUEFI
in

What should instead happen is that, in input/OVF.ml, if the key is missing then we set the firmware to UnknownFirmware which will cause the guest-detected firmware to be used instead.

This is a very simple patch if you want to have a go at it.

@bkhizgiy
Copy link
Contributor Author

bkhizgiy commented Apr 9, 2024

Ah, that makes sense. I encountered this issue only with UEFI VMs, and when trying to convert the same VM (without the deleted property), the firmware was detected correctly, so it really looked like a default setting somewhere.

Sure, I can post the fix, It sounds pretty straightforward with all the provided info you added :)
I'll test it locally and open a PR.

@rwmjones
Copy link
Member

rwmjones commented Apr 9, 2024

When compiling virt-v2v, some tips:

  • Do NOT use make install or you'll have a bad day. Run virt-v2v locally from the build directory using ./run virt-v2v [etc]
  • Use dnf builddep virt-v2v to install all the build dependencies in one go.
  • Also install dnf install automake autoconf libtool and use autoreconf -i to regenerate the ./configure script.

@bkhizgiy
Copy link
Contributor Author

I've added the suggested changes, and now it's really using the UnknownFirmware for this flow, but the value is still wrong. tried to add some logs to the flow to understand where it's coming from, and it seems the detected firmware in the virt-v2v/convert/convert.ml file returns the wrong value (BIOS instead of UEFI), and I'm not really sure why it's happening. I've tried with only one VM in the meantime. I'll try to test it with another one later and see how it goes.

I've opened a draft PR in the meantime with the initial changes; let me know what you think: #53.

@rwmjones
Copy link
Member

Firmware detection is here: https://github.com/libguestfs/libguestfs-common/blob/master/mldrivers/firmware.ml

What's happening for this guest is it has a BIOS boot partition on /dev/sda2, which we prioritise to mean it's a BIOS guest (even though it has UEFI ESP etc, so otherwise looks like a UEFI guest).

This fallback was added recently in commit 22ec2d2

@rwmjones
Copy link
Member

I should say that it's somewhat unusual for us not to have the firmware type from the source hypervisor. I'm fairly sure that VMware-generated OVFs would always have that, and if we're using other methods like VMware VMX then similarly we'd always have that information available. Autodetection is mainly for the fallback case where someone is converting a local disk having "lost" the metadata.

@bkhizgiy
Copy link
Contributor Author

Yes, you make a valid point. In most cases, we do have this property in the OVF configuration set. However, we've encountered instances where it was missing, leading to migrated VMs not functioning correctly in OpenShift. Since we aim to provide full support for all cases, we've thought to rely on virt-v2v detection for this. So from the commit you added, I understand it should still cover the majority of cases, but we may end up having a small percentage of false detection. I think it may be good enough but I'll talk with Arik and see how and if we want to address it from the MTV side. In the meantime, I've switched the PR with the fix from draft to ready.

@avdrob
Copy link

avdrob commented Apr 11, 2024

The problem which we were trying to address in the original commit 22ec2d is to detect the correct firmware in case we have both BIOS boot and EFI partitions. This layout doesn't normally happen, and we chose to prioritize BIOS boot in this case. But this logic is still prone to erroneous resolutions, one of which I think we're seeing here.

Should we make the firmware detection logic a bit more sophisticated? For instance in case there's a ESP partition present we could mount it, inspect the content and look for EFI application files (BOOTX64.EFI, grubx64.efi etc.). I'm just wondering whether their presence would be an unambiguous indication that we're booting in EFI.

@rwmjones
Copy link
Member

Thanks Andrey. I think fundamentally the problem is that there can exist guests which can booted both ways! How do we know which is "preferred".

But also I like your idea of looking at the EFI partition. In addition I wonder if it's plausible to look at the first sector of the disk, looking for a BIOS bootloader?

Before we do anything, @bkhizgiy do you have a way to either send me or for me to create the guest you were trying to convert?

@avdrob
Copy link

avdrob commented Apr 11, 2024

Hmm, if your assumption is correct and we indeed can have a guest suitable for booting both ways, then this problem seems fundamentally unsolvable to me. We could have both 0xEF02 and 0xEF00 partitions present and each of them would have its own bootloader code stored inside. Then when booting a UEFI based VM (with edk2-ovmf) one bootloader code will be used, and when booting a BIOS based VM (seabios) with the same disk -- another bootloader code will be used.

In this case I think we better limit conversions with automatic firmware detection to unambiguous cases only, i.e. only when either BIOS boot or EFI partition contain bootloader (but not both). Otherwise it seems that we're doomed to getting erroneous detections every once in a while. And the normal way should be detecting firmware from the source hypervisor, as you mentioned above.

As for the BIOS bootloader detection, it seems that in case of both pure MBR or GPT + protective MBR + BIOS boot partition grub2 bootloader indeed leaves its traces in the first sector, namely in the first 440 bytes Boot Code area [1]. In particular, I can see the string "GRUB \0" in this first sector in case of BIOS boot partition. And in case of UEFI installation this Boot Code area is just filled with zeroes. So I guess we could use the presence of this string as an indication of BIOS bootloader.

[1] https://uefi.org/specs/UEFI/2.10/05_GUID_Partition_Table_Format.html#protective-mbr

@avdrob
Copy link

avdrob commented Apr 11, 2024

So just to clarify, the firmware detection logic I'm suggesting to implement is the following:

  • First try getting firmware type from the source hypervisor;
  • Then do the automatic detection relying on partition types. If we have pure MBR disk -- we're clearly using BIOS;
  • Otherwise we're having GPT + protective MBR. If we have either one of 0xef00 or 0xef02 partitions (not both) -- then we're good;
  • If we have both, we search for bootloaders of both kinds. For EFI we mount the partition and look for "*.efi" applications. For BIOS bootloader we inspect the 1st disk sector and look for "GRUB \0" string in the MBR;
  • If we've only found one type of bootloader -- we're good. If we've found both -- we emit an error.

@bkhizgiy
Copy link
Contributor Author

@rwmjones Sure, I saw it when trying with a RHEL 9 guest. I downloaded the file from Red Hat Cloud using the following link , and selected the VMware-compatible option.
I've uploaded the files to google drive, with.ova is the original file, and without.ova is the same file with the firmware configuration removed.

I used virt-v2v -i ova without.ova -o kubevirt -on vm -os . to execute the command.

let me know if you having any issues accessing the files.

@rwmjones
Copy link
Member

I downloaded them, thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants