Migrate ESXi Host Physical Adapters to Specific dvUplink Port

When migrating to Distributed Switches I have a script that I have been using for a couple of years now that I modify to fit the customer’s environment. One of the things I had always been curious about, but had never really had a real requirement to research any further was how you could assign specific Physical NICs (vmnic0) to specific dvUplink (Uplink 0) Ports. The PowerCLI commands that I had been using did not appear to have any options available to specify which NIC would be assigned to which uplink. I ran in to a requirement to do just that today and found a way to assign each NIC to an explicitly specified Uplink using the vSphere API and Onyx.

When migrating to Distributed Switches I have a script that I have been using for a couple of years now that I modify to fit the customer’s environment. One of the things I had always been curious about, but had never really had a real requirement to research any further was how you could assign specific Physical NICs (vmnic0) to specific dvUplink (Uplink 0) Ports. The PowerCLI commands that I had been using did not appear to have any options available to specify which NIC would be assigned to which uplink. I ran in to a requirement to do just that today and found a way to assign each NIC to an explicitly specified Uplink using the vSphere API and Onyx.

When you use PowerCLI to add vmnics to a Distributed Switch, the Uplinks are assigned in the order that the vmnics are passed to the command. If I were to assign vmnic5 to the Distributed Switch first, it would be assigned “Uplink 0” (or “Uplink 1” if you did not rename your Uplinks from the default). The way that our Distributed switches were architected uses different Uplink failover orders depending on which Port Group is communicating. To standardize things, it was much simpler for us to match the vmnic number with the Uplink number. The way our hosts and switches were already configured mandated that we migrate vmnic0, 2, 3 and 4 first, where in the past I have been able to migrate vmnic0,1,2, and 3. The consecutive numbers are not a big deal, you just make sure that the script adds them in the appropriate order, and then they will be assigned to Uplink 0,1,2, and 3 respectively. In this new use case, however, I needed to find a way to explicitly assign NICs to specific Uplinks.

I had originally used the  Add-VDSwitchPhysicalNetworkAdapter command to migrate physical adapters over to a Distributed Switch, but in looking through the documentation, I was only able to confirm what I had originally suspected; there doesn’t appear to be a PowerCLI friendly way of specifying which NICs end up assigned to which uplinks (at least not with this command). After a brief search in the API explorer without any success, I turned to VMware Labs’ Onyx to expose the API behind the operation. If you use PowerCLI and you haven’t used Onyx yet, you should definitely give it a shot.

Since this is part of a larger script, I will only touch on the part needed to assign the NICs to specific Uplinks. First You will need to add your Host to the Distributed Switch (if it hasn’t been added already). Then the script gets the vDS object and all of the uplinks for the vDS that apply to your host.

$vhost = Get-VMHost <hostname>
Add-VDSwitchVMHost -VMHost $vhost -VDSwitch <switchname>
$vds = Get-VDSwitch <switchname>
$uplinks = $vhost | Get-VDSwitch | Get-VDPort -Uplink | where {$_.ProxyHost -like $vhost.Name}

Next, you will need to remove the NICs in question from the host. I will be working with vmnic0, 4, 2, and 3, in that order. You will need to modify the entries to fit your environment.

$vmnics = @("vmnic0","vmnic4","vmnic2","vmnic3"
$vhost | Get-VMHostNetworkAdapter -Name $vmnics | Remove-VirtualSwitchPhysicalNetworkAdapter -Confirm:$false

This next section is where the bulk of the work is done, you will need to make sure your numbers are filled in correctly for each pnicSpec.

$config = New-Object VMware.Vim.HostNetworkConfig
$config.proxySwitch = New-Object VMware.Vim.HostProxySwitchConfig[] (1)
$config.proxySwitch[0] = New-Object VMware.Vim.HostProxySwitchConfig
$config.proxySwitch[0].changeOperation = "edit"
$config.proxySwitch[0].uuid = $vds.Key
$config.proxySwitch[0].spec = New-Object VMware.Vim.HostProxySwitchSpec
$config.proxySwitch[0].spec.backing = New-Object VMware.Vim.DistributedVirtualSwitchHostMemberPnicBacking
$config.proxySwitch[0].spec.backing.pnicSpec = New-Object VMware.Vim.DistributedVirtualSwitchHostMemberPnicSpec[] (4)
$config.proxySwitch[0].spec.backing.pnicSpec[0] = New-Object VMware.Vim.DistributedVirtualSwitchHostMemberPnicSpec
$config.proxySwitch[0].spec.backing.pnicSpec[0].pnicDevice = "vmnic0"
$config.proxySwitch[0].spec.backing.pnicSpec[0].uplinkPortKey = ($uplinks | where {$_.Name -eq "Uplink 0"}).key
$config.proxySwitch[0].spec.backing.pnicSpec[1] = New-Object VMware.Vim.DistributedVirtualSwitchHostMemberPnicSpec
$config.proxySwitch[0].spec.backing.pnicSpec[1].pnicDevice = "vmnic4"
$config.proxySwitch[0].spec.backing.pnicSpec[1].uplinkPortKey = ($uplinks | where {$_.Name -eq "Uplink 4"}).key
$config.proxySwitch[0].spec.backing.pnicSpec[2] = New-Object VMware.Vim.DistributedVirtualSwitchHostMemberPnicSpec
$config.proxySwitch[0].spec.backing.pnicSpec[2].pnicDevice = "vmnic2"
$config.proxySwitch[0].spec.backing.pnicSpec[2].uplinkPortKey = ($uplinks | where {$_.Name -eq "Uplink 2"}).key
$config.proxySwitch[0].spec.backing.pnicSpec[3] = New-Object VMware.Vim.DistributedVirtualSwitchHostMemberPnicSpec
$config.proxySwitch[0].spec.backing.pnicSpec[3].pnicDevice = "vmnic3"
$config.proxySwitch[0].spec.backing.pnicSpec[3].uplinkPortKey = ($uplinks | where {$_.Name -eq "Uplink 3"}).key

$_this = Get-View (Get-View $vhost).ConfigManager.NetworkSystem
$_this.UpdateNetworkConfig($config, "modify")

The larger script that I use will then migrate all VMKs to their respective port groups and then modify each network adapter on each VM to connect to the appropriate port group on the vDS. Once all VM and Host networking has been migrated the script then removes the final four vmnics from the Standard switch.

$vmnics = @("vmnic1","vmnic5","vmnic6","vmnic7")
$vhost | Get-VMHostNetworkAdapter -Name $vmnics | Remove-VirtualSwitchPhysicalNetworkAdapter -Confirm:$false

The UpdateNetworkConfig method then needs to be run one last time to include all NICs that should now be connected to the vDS.

$config = New-Object VMware.Vim.HostNetworkConfig
$config.proxySwitch = New-Object VMware.Vim.HostProxySwitchConfig[] (1)
$config.proxySwitch[0] = New-Object VMware.Vim.HostProxySwitchConfig
$config.proxySwitch[0].changeOperation = "edit"
$config.proxySwitch[0].uuid = $vds.Key
$config.proxySwitch[0].spec = New-Object VMware.Vim.HostProxySwitchSpec
$config.proxySwitch[0].spec.backing = New-Object VMware.Vim.DistributedVirtualSwitchHostMemberPnicBacking
$config.proxySwitch[0].spec.backing.pnicSpec = New-Object VMware.Vim.DistributedVirtualSwitchHostMemberPnicSpec[] (8)
$config.proxySwitch[0].spec.backing.pnicSpec[0] = New-Object VMware.Vim.DistributedVirtualSwitchHostMemberPnicSpec
$config.proxySwitch[0].spec.backing.pnicSpec[0].pnicDevice = "vmnic0"
$config.proxySwitch[0].spec.backing.pnicSpec[0].uplinkPortKey = ($uplinks | where {$_.Name -eq "Uplink 0"}).key
$config.proxySwitch[0].spec.backing.pnicSpec[1] = New-Object VMware.Vim.DistributedVirtualSwitchHostMemberPnicSpec
$config.proxySwitch[0].spec.backing.pnicSpec[1].pnicDevice = "vmnic4"
$config.proxySwitch[0].spec.backing.pnicSpec[1].uplinkPortKey = ($uplinks | where {$_.Name -eq "Uplink 4"}).key
$config.proxySwitch[0].spec.backing.pnicSpec[2] = New-Object VMware.Vim.DistributedVirtualSwitchHostMemberPnicSpec
$config.proxySwitch[0].spec.backing.pnicSpec[2].pnicDevice = "vmnic2"
$config.proxySwitch[0].spec.backing.pnicSpec[2].uplinkPortKey = ($uplinks | where {$_.Name -eq "Uplink 2"}).key
$config.proxySwitch[0].spec.backing.pnicSpec[3] = New-Object VMware.Vim.DistributedVirtualSwitchHostMemberPnicSpec
$config.proxySwitch[0].spec.backing.pnicSpec[3].pnicDevice = "vmnic3"
$config.proxySwitch[0].spec.backing.pnicSpec[3].uplinkPortKey = ($uplinks | where {$_.Name -eq "Uplink 3"}).key
$config.proxySwitch[0].spec.backing.pnicSpec[4] = New-Object VMware.Vim.DistributedVirtualSwitchHostMemberPnicSpec
$config.proxySwitch[0].spec.backing.pnicSpec[4].pnicDevice = "vmnic1"
$config.proxySwitch[0].spec.backing.pnicSpec[4].uplinkPortKey = ($uplinks | where {$_.Name -eq "Uplink 1"}).key
$config.proxySwitch[0].spec.backing.pnicSpec[5] = New-Object VMware.Vim.DistributedVirtualSwitchHostMemberPnicSpec
$config.proxySwitch[0].spec.backing.pnicSpec[5].pnicDevice = "vmnic5"
$config.proxySwitch[0].spec.backing.pnicSpec[5].uplinkPortKey = ($uplinks | where {$_.Name -eq "Uplink 5"}).key
$config.proxySwitch[0].spec.backing.pnicSpec[6] = New-Object VMware.Vim.DistributedVirtualSwitchHostMemberPnicSpec
$config.proxySwitch[0].spec.backing.pnicSpec[6].pnicDevice = "vmnic6"
$config.proxySwitch[0].spec.backing.pnicSpec[6].uplinkPortKey = ($uplinks | where {$_.Name -eq "Uplink 6"}).key
$config.proxySwitch[0].spec.backing.pnicSpec[7] = New-Object VMware.Vim.DistributedVirtualSwitchHostMemberPnicSpec
$config.proxySwitch[0].spec.backing.pnicSpec[7].pnicDevice = "vmnic7"
$config.proxySwitch[0].spec.backing.pnicSpec[7].uplinkPortKey = ($uplinks | where {$_.Name -eq "Uplink 7"}).key

$_this = Get-View (Get-View $vhost).ConfigManager.NetworkSystem
$_this.UpdateNetworkConfig($config, "modify")

Hopefully this can help someone out.

One thought on “Migrate ESXi Host Physical Adapters to Specific dvUplink Port”

Leave a comment