[Libguestfs] [PATCH v2v v2 2/2] v2v: Copy static IP address information over for Windows guests (RHBZ#1626503).

Pino Toscano ptoscano at redhat.com
Thu Apr 25 14:30:11 UTC 2019


On Tuesday, 16 April 2019 10:55:40 CEST Richard W.M. Jones wrote:
> For Linux the guest itself remembers the IP address associated with
> each MAC address.  Thus it doesn't matter if the interface type
> changes (ie. to virtio-net), because as long as we preserve the MAC
> address the guest will use the same IP address or the same DHCP
> configuration.
> 
> However on Windows this association is not maintained by MAC address.
> In fact the MAC address isn't saved anywhere in the guest registry.
> (It seems instead this is likely done through PCI device type and
> address which we don't record at the moment and is almost impossible
> to preserve.)  When a guest which doesn't use DHCP is migrated, the
> guest sees the brand new virtio-net devices and doesn't know what to
> do with them, and meanwhile the right static IPs are still associated
> with the old and now-defunct interfaces in the registry.
> 
> We cannot collect the required information from within the guest.
> However we can collect it outside the tool by some other means
> (eg. using VMware Tools APIs) and present this information to virt-v2v
> which then writes it into the Windows guest at firstboot time.
> 
> This commit adds the --mac ..:ip:.. sub-option which creates a
> Powershell script to set network adapters at firstboot.  An option
> such as:
> 
>   --mac 00:0c:29:e6:3d:9d:ip:192.168.0.89,192.168.0.1,24,192.168.0.254
> 
> approximately turns into this script:
> 
>   # Wait for the netkvm (virtio-net) driver to become active.
>   $adapters = @()
>   While (-Not $adapters) {
>       Start-Sleep -Seconds 5
>       $adapters = Get-NetAdapter -Physical |
>                      Where DriverFileName -eq "netkvm.sys"
>   }
>   $mac_address = '00-0c-29-e6-3d-9d'
>   $ifindex = (Get-NetAdapter -Physical |
>                  Where MacAddress -eq $mac_address).ifIndex
>   if ($ifindex) {
>       New-NetIPAddress -InterfaceIndex $ifindex
>                        -IPAddress '192.168.0.89'
>                        -DefaultGateway '192.168.0.1'
>                        -PrefixLength 24
>       Set-DnsClientServerAddress -InterfaceIndex $ifindex
>                        -ServerAddresses ('192.168.0.254')
>   }
> 
> Thanks: Brett Thurber for diagnosing the problem and suggesting paths
> towards a fix.
> ---

I have no experience on the Windows-specific parts, so I can only
comment on the v2v integration.

> diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
> index 641eed017..82f9a7da6 100644
> --- a/v2v/cmdline.ml
> +++ b/v2v/cmdline.ml
> @@ -41,11 +41,12 @@ type cmdline = {
>    print_estimate : bool;
>    print_source : bool;
>    root_choice : root_choice;
> +  static_ips : static_ip list;
>    ks : Tools_utils.key_store;
>  }

Instead of a separate list (which needs to be passed around, etc), most
probably this can fit as part of the Network module, adding a new
element to the vnet_type type, e.g.:

and vnet_type = Bridge | Network | Static_ip of static_ip

Most probably the static IP specification string can be parsed in a new
Network.add_static_ip method, which would also take care to check for
duplicated MAC specifications.

> +  and configure_network_interfaces net_driver =
> +    (* If we were asked to force network interfaces to have particular
> +     * static IP addresses then it is done here by installing a
> +     * Powershell script which runs at boot.
> +     *)
> +    if static_ips <> [] then (
> +      let psh_filename = "v2vnetcf.ps1" in
> +      let psh = ref [] in
> +      let add = List.push_back psh in
> +
> +      add "Set-PSDebug -Trace 1";
> +      add "";

I suggest adding a simple helper here:
  let sq = sprintf "'%s'" in
(sq = Single Quote)

> +
> +      (* If virtio-net was added to the registry, we must wait for
> +       * it to be installed at runtime.
> +       *)
> +      if net_driver = Virtio_net then (
> +        add "# Wait for the netkvm (virtio-net) driver to become active.";
> +        add "$adapters = @()";
> +        add "While (-Not $adapters) {";
> +        add "    Start-Sleep -Seconds 5";
> +        add "    $adapters = Get-NetAdapter -Physical | Where DriverFileName -eq \"netkvm.sys\"";
> +        add "    Write-Host \"adapters = '$adapters'\"";
> +        add "}";
> +        add ""
> +      );
> +
> +      List.iter (
> +        fun { if_mac_addr; if_ip_address; if_default_gateway;
> +              if_prefix_length; if_nameservers } ->
> +          add (sprintf "$mac_address = '%s'"
> +                       (String.replace if_mac_addr ":" "-"));
> +          add "$ifindex = (Get-NetAdapter -Physical | Where MacAddress -eq $mac_address).ifIndex";
> +          add "if ($ifindex) {";
> +
> +          add "    Write-Host \"setting IP address of adapter at $ifindex\"";
> +
> +          (* New-NetIPAddress command *)
> +          let args = ref [] in
> +          List.push_back args "-InterfaceIndex";
> +          List.push_back args "$ifindex";
> +          List.push_back args "-IPAddress";
> +          List.push_back args (sprintf "'%s'" if_ip_address);

'sq' can be used here.

> +          (match if_default_gateway with
> +           | None -> ()
> +           | Some gw ->
> +              List.push_back args "-DefaultGateway";
> +              List.push_back args (sprintf "'%s'" gw)

'sq' can be used here.

> +          );
> +          (match if_prefix_length with
> +           | None -> ()
> +           | Some len ->
> +              List.push_back args "-PrefixLength";
> +              List.push_back args (string_of_int len)
> +          );
> +          let cmd1 = "New-NetIPAddress " ^ String.concat " " !args in
> +          add ("    " ^ cmd1);

Most probably this can be:

         add (sprintf "    New-NetIPAddress %s" (String.concat " " !args));

(just for consistency with the same pattern done few lines below this.)

> +
> +          (* Set-DnsClientServerAddress command *)
> +          if if_nameservers <> [] then (
> +            add (sprintf "    Set-DnsClientServerAddress -InterfaceIndex $ifindex -ServerAddresses (%s)"
> +                         (String.concat "," (List.map (sprintf "'%s'") if_nameservers)))

'sq' can be used here.

> +          );
> +          add "}";
> +          add ""

install_firstboot_powershell already adds a newline at the end, so most
probably this empty line can be removed.

-- 
Pino Toscano
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: This is a digitally signed message part.
URL: <http://listman.redhat.com/archives/libguestfs/attachments/20190425/87786de2/attachment.sig>


More information about the Libguestfs mailing list