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