Home > PowerCLI, PowerShell, dvSwitch, vSphere > dvSwitch scripting – Part 2 – dvPortgroup

dvSwitch scripting – Part 2 – dvPortgroup

October 12th, 2009 LucD Leave a comment Go to comments

In Part 1 of the dvSwitch scripting series I created a simple dvSwitch with 2 uplinks, which I connected to all the ESX hosts that were returned as possible candidates. In this part I will show you how to add a dvPortgroups and how you can connect Virtual Machines to this dvPortgroup.

This is the schematic of what we have so far.

dvSw1-general1

And the uplink port allocation.

dvSw1-general2

Update March 28th 2010

The previous version of the New-dvSwPortgroup function was rather simplistic.

This new, and completely re-vamped, version allows you to specify the VLAN type and the VLANIds if required. Note that the new version requires PowerShell v2 RTM.

Update July 22nd 2010

With this new version all the security and teaming options are available. Follow the hyperlinks for more information on the different parameters.

There are a number of options that you can’t configure from the vSphere client! For example the load based teaming as described in Frank Denneman’s blog.

The following table shows the available parameters. The new ones are highighted.

Parameter Type Default Comment
PgNumberPorts int 64
PgBinding string earlyBinding
PgVLANType string
PgVLANId int[]
SecPolPromiciousMode Boolean false
SecPolMacChanges Boolean true
SecPolForgedTransmits Boolean true
TeamingCheckDuplex Boolean false
TeamingCheckErrorPercent Boolean false
TeamingPercentage int
TeamingCheckSpeed Boolean false
TeamingSpeed int
TeamingPolicy string loadbalance_srcid Accepted values:

loadbalance_ip

loadbalance_srcmac

loadbalance_srcid

failover_explicit

loadbalance_loadbased

TeamingNotifySwitches Boolean true
TeamingRollingOrder Boolean false
TeamingReversePolicy Boolean true
TeamingActiveUplink string[]
TeamingStandbyUplink string[]
function Get-dvSwitch{
	param([parameter(Position = 0, Mandatory = $true)][string]$DatacenterName,
	[parameter(Position = 1, Mandatory = $true)][string]$dvSwitchName)

	$dcNetFolder = Get-View (Get-Datacenter $DatacenterName | Get-View).NetworkFolder
	$found = $null
	foreach($net in $dcNetFolder.ChildEntity){
		if($net.Type -eq "VmwareDistributedVirtualSwitch"){
			$temp = Get-View $net
			if($temp.Name -eq $dvSwitchName){
				$found = $temp
			}
		}
	}
	$found
}

function Get-VLANRanges{
	param ([int[]]$ids)

	$return = @()
	$nr = 0
	$start = $ids[$nr]
	$end = -1
	while($nr -lt ($ids.Count)){
		if(($ids[$nr + 1]-$ids[$nr]) -gt 1){
			$end = $ids[$nr]
			$nrange = New-Object VMware.Vim.NumericRange
			$nrange.start = $Start
			$nrange.end = $end
			$return += $nrange
			$start = $ids[$nr + 1]
			$end = -1
		}
		$nr++
	}
	if($end -lt 0){
		$nrange = New-Object VMware.Vim.NumericRange
		$nrange.start = $Start
		$nrange.end = $ids[-1]
		$return += $nrange
	}
	$return
}

function New-dvSwPortgroup{
	param([parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)][VMware.Vim.VmwareDistributedVirtualSwitch]$dvSw,
	[parameter(Position = 1, Mandatory = $true)][string]$PgName,
	[int]$PgNumberPorts = 64,
	[string]$PgBinding = "earlyBinding",
	[string]$PgVLANType = "none",
	[int[]]$PgVLANId,
	[switch]$SecPolPromiciousMode = $false,
	[switch]$SecPolMacChanges = $true,
	[switch]$SecPolForgedTransmits = $true,
	[switch]$TeamingCheckDuplex = $false,
	[switch]$TeamingCheckErrorPercent = $false,
	[string]$TeamingCheckSpeed = $false,
	[switch]$TeamingFullDuplex = $true,
	[int]$TeamingPercentage,
	[int]$TeamingSpeed,
	[string]$TeamingPolicy = "loadbalance_srcid",
	[switch]$TeamingNotifySwitches = $true,
	[switch]$TeamingRollingOrder = $false,
	[switch]$TeamingReversePolicy = $true,
	[string[]]$TeamingActiveUplink,
	[string[]]$TeamingStandbyUplink
	)
	process{
		$teamingPolicies = "loadbalance_ip",
						"loadbalance_srcmac",
						"loadbalance_srcid",
						"failover_explicit",
						"loadbalance_loadbased"

		$spec = New-Object VMware.Vim.DVPortgroupConfigSpec
		$spec.Name = $PgName
		$spec.Type = $PgBinding
		$spec.numPorts = $PgNumberPorts
		$spec.defaultPortConfig = New-Object VMware.Vim.VMwareDVSPortSetting
		switch($PgVLANType.ToLower()){
			"vlan" {
				$spec.defaultPortConfig.VLAN = New-Object VMware.Vim.VmwareDistributedVirtualSwitchVlanIdSpec
				$spec.defaultPortConfig.VLAN.vlanId = $PgVLANId[0]
			}
			"vlan trunking" {
				$spec.defaultPortConfig.VLAN = New-Object VMware.Vim.VmwareDistributedVirtualSwitchTrunkVlanSpec
				$spec.defaultPortConfig.VLAN.vlanId = Get-VLANRanges $PgVLANId
			}
			"private vlan" {
				$spec.defaultPortConfig.VLAN = New-Object VMware.Vim.VmwareDistributedVirtualSwitchPvlanSpec
				$spec.defaultPortConfig.VLAN.pvlanId = $PgVLANId[0]
			}
			Default{}
		}

		$spec.defaultPortConfig.securityPolicy = New-Object VMware.Vim.DVSSecurityPolicy
		$spec.defaultPortConfig.securityPolicy.allowPromiscuous = New-Object VMware.Vim.BoolPolicy
		$spec.defaultPortConfig.securityPolicy.allowPromiscuous.Value = $SecPolPromiciousMode
		$spec.defaultPortConfig.securityPolicy.forgedTransmits = New-Object VMware.Vim.BoolPolicy
		$spec.defaultPortConfig.securityPolicy.forgedTransmits.Value = $SecPolForgedTransmits
		$spec.defaultPortConfig.securityPolicy.macChanges = New-Object VMware.Vim.BoolPolicy
		$spec.defaultPortConfig.securityPolicy.macChanges.Value = $SecPolMacChanges

		$spec.defaultPortConfig.uplinkTeamingPolicy = New-Object VMware.Vim.VmwareUplinkPortTeamingPolicy
		$spec.defaultPortConfig.uplinkTeamingPolicy.failureCriteria = New-Object VMware.Vim.DVSFailureCriteria
		if($TeamingCheckDuplex){
			$spec.defaultPortConfig.uplinkTeamingPolicy.failureCriteria.checkDuplex = $TeamingCheckDuplex
			$spec.defaultPortConfig.uplinkTeamingPolicy.failureCriteria.fullDuplex = $TeamingFullDuplex
		}
		if($TeamingCheckErrorPercent){
			$spec.defaultPortConfig.uplinkTeamingPolicy.failureCriteria.checkErrorPercent = $TeamingCheckErrorPercent
			$spec.defaultPortConfig.uplinkTeamingPolicy.failureCriteria.percentage = $TeamingPercentage
		}
		if("exact","minimum" -contains $TeamingCheckSpeed){
			$spec.defaultPortConfig.uplinkTeamingPolicy.failureCriteria.checkSpeed = $TeamingCheckSpeed
			$spec.defaultPortConfig.uplinkTeamingPolicy.failureCriteria.speed = $TeamingSpeed
		}
		$spec.defaultPortConfig.uplinkTeamingPolicy.notifySwitches = New-Object VMware.Vim.BoolPolicy
		$spec.defaultPortConfig.uplinkTeamingPolicy.notifySwitches.Value = $NotifySwitches
		if($teamingPolicies -contains $TeamingPolicy){
			$spec.defaultPortConfig.uplinkTeamingPolicy.policy = New-Object VMware.Vim.StringPolicy
			$spec.defaultPortConfig.uplinkTeamingPolicy.policy.Value = $TeamingPolicy
		}
		$spec.defaultPortConfig.uplinkTeamingPolicy.reversePolicy = New-Object VMware.Vim.BoolPolicy
		$spec.defaultPortConfig.uplinkTeamingPolicy.reversePolicy.Value = $TeamingReversePolicy
		$spec.defaultPortConfig.uplinkTeamingPolicy.rollingOrder = New-Object VMware.Vim.BoolPolicy
		$spec.defaultPortConfig.uplinkTeamingPolicy.rollingOrder.Value = $TeamingRollingOrder
		$spec.defaultPortConfig.uplinkTeamingPolicy.uplinkPortOrder = New-Object VMware.Vim.VMwareUplinkPortOrderPolicy
		$spec.defaultPortConfig.uplinkTeamingPolicy.uplinkPortOrder.activeUplinkPort = $TeamingActiveUplink
		$spec.defaultPortConfig.uplinkTeamingPolicy.uplinkPortOrder.standbyUplinkPort = $TeamingStandbyUplink

		$taskMoRef = $dvSw.AddDVPortgroup_Task($spec)
		$task = Get-View $taskMoRef
		while("running","queued" -contains $task.Info.State){
			$task.UpdateViewData("Info")
		}
		$task.Info.Result
	}
}

Annotations:

Line 1: since there is in the current PowerCLI build no cmdlet to get the dvSwitch object, I had to write one. The function Get-dvSwitch loops through the children of the Network folder to find the dvSwitch that was requested. If the dvSwitch is not found, the function returns $null.

Line 18-44: The helper function Get-VLANRanges takes an array of VLAN Ids and converts them to the minimal number of NumericRange objects. The function returns an array with the resulting NumericRange objects.

Line 47-67: The New-dvSwPortgroup parameters. Note that several of the parameters have default values. Also note that the function has two positional parameters and that the other parameters are all named parameters. Have a look at the Example calls of the function a bit further along.

Line 69: To allow the function to be used in a pipeline, the new version uses the Process block.

Line 133: the AddDVPortgroup_Task requires the portgroup Type to be specified, allthough the SDK reference says otherwise in the description of the DVPortgroupConfigSpec object. The accepted values can be found in the DistributedVirtualPortgroupPortgroupType enumeration. The possible values are:

  • earlyBinding: free port assigned when the VM is configured to connect to the dvPortgroup
  • ephemeral: free port assigned when VM is powered on and removed when the VM is powered off
  • lateBinding: free port assigned when VM is powered on

These values correspond with what you see under Port binding in the vSphere client.

dvSw1-portbinding

Line 81-95: The part where the VLAN type of the the new portgroup is configured. Possible values here are:

  • None: the portgroup does not use a VLAN
  • VLAN: the portgroup uses a single VLAN Id
  • VLAN Trunking: the portgroup uses trunk mode.The guest OS manages its own VLAN tags.
  • Private VLAN: the portgroup uses a private VLAN Id. The dvSwitch needs to have primary and secondary VLANIds defined and you select the desired secondary PVLANId for this mode.

These values correspond with what you see under VLAN type in the vSphere client when you create a new Distributed Virtual Port Group .

Line 97-103: The part where the security settings are defined.
Line 105-131: The Teaming and failover settings.

Examples

Some sample calls of the New-dvSwPortgroup function.

$datacenterName = "Home1"
$dvSwitchName = "dvSw1"
$dvPgNumPorts = 32

$dvSw = Get-dvSwitch -DatacenterName $datacenterName -dvSwitchName $dvSwitchName

# No VLAN
$dvSwPg = New-dvSwPortgroup $dvSw "dvPg1"
$dvSwPg = Get-dvSwitch $datacenterName $dvSwitchName | New-dvSwPortgroup -PgName "dvPg2"
$dvSwPg = New-dvSwPortgroup $dvSw "dvPg3" -PgNumberPorts $dvPgNumPorts
$dvSwPg = New-dvSwPortgroup $dvSw "dvPg4" -PgBinding "earlyBinding" -PgVLANType "none"
$dvSwPg = New-dvSwPortgroup $dvSw "dvPg5" -PgBinding "ephemeral" -PgVLANType "none"
$dvSwPg = New-dvSwPortgroup $dvSw "dvPg6" -PgBinding "lateBinding" -PgVLANType "none"

# VLAN
$dvSwPg = New-dvSwPortgroup $dvSw "dvPg7" -PgNumberPorts $dvPgNumPorts -PgVLANType "VLAN" -PgVLANId 2011

# VLAN Trunking
$dvSwPg = New-dvSwPortgroup $dvSw "dvPg8" -PgNumberPorts $dvPgNumPorts -PgVLANType "VLAN Trunking" -PgVLANId (2023..2027)
$dvSwPg = New-dvSwPortgroup $dvSw "dvPg9" -PgNumberPorts $dvPgNumPorts -PgVLANType "VLAN Trunking" -PgVLANId 2023,2025,2027

# PVLAN
$dvSwPg = New-dvSwPortgroup $dvSw "dvPg10" -PgNumberPorts $dvPgNumPorts -PgBinding "lateBinding" -PgVLANType "Private VLAN" -PgVLANId 2031

# MAC addr changes
$dvSwPg = New-dvSwPortgroup $dvSw "dvPg11" -SecPolMacChanges:$false

# Teaming
$dvSwPg = New-dvSwPortgroup $dvSw "dvPg12" -TeamingPolicy "loadbalance_srcid" -TeamingActiveUplink "dvUplink1","dvUplink2"

Annotations

Line 8: Straightforward call, creates a new portgroup taking all the defaults

Line 9: The dvSw is passed through the pipeline to the New-dvSwPortgroup function. Again taking all the defaults.

Line 10: The number of ports is passed to the call.

Line 11-13: These show the possible values for the portgroup type, the PgBinding parameter.

Line 16: Creates a portgroup that uses a single VLAN Id

Line 19-20: Two examples how a portgroup with Trunking VLAN can be created. This shows the usefulness of the Get-VLANRanges helper function. In the vSphere Client you’ll see that a minimal number of ranges was used.

Line 23: A portgroup with a Private VLAN.

Line 26: Create a portgroup with the Security option MAC Address Changes set to Reject.

Line 29: A portgroup with Load Balancing based on the originating virtual port (the default)  and with 2 active uplinks.

Portgroup dvPg8

Portgroup dvPg9

Line 23: The final sample call shows how to create a portgroup that uses a Private VLAN. See also dvSwitch scripting – Part 6 – Private VLAN for the concept behind private VLANs.

The secondary VLANId on the Distributed Virtual Switch

The portgroup dvPg10

Now that there is a dvPortgroup, we can configure a VM to connect to the dvPortgroup.

function Set-VM2dvPortgroup{
 param($vmName, $nicName, $dvPgName)

 $vm = Get-VM $vmName | Get-View

# Find the NIC
 foreach($tempdev in $vm.Config.Hardware.Device){
 if($tempdev.DeviceInfo.Label -eq $nicName){
 $tgtdev = $tempdev
 }
 }

# Find the dvSwitch & dvPortGroup
 $esx = Get-View -Id $vm.Runtime.Host
 foreach($netMoRef in $esx.Network){
 if($netMoRef.Type -eq "DistributedVirtualPortGroup"){
 $net = Get-View -Id $netMoRef
 if($net.Name -eq $dvPgName){
 $dvPgKey = $net.MoRef.Value
 $dvSwitchUuid = (Get-View -Id $net.Config.DistributedVirtualSwitch).Summary.Uuid
 }
 }
 }

# Prepare Spec
 $spec = New-Object VMware.Vim.VirtualMachineConfigSpec
 $devChange = New-Object VMware.Vim.VirtualDeviceConfigSpec
 $devChange.operation = "edit"

 $dev = New-Object ("VMware.Vim." + $tgtdev.GetType().Name)
 $dev.deviceInfo = New-Object VMware.Vim.Description
 $dev.deviceInfo.label = $tgtdev.DeviceInfo.Label
 $dev.deviceInfo.summary = $tgtdev.DeviceInfo.Summary
 $dev.Backing = New-Object VMware.Vim.VirtualEthernetCardDistributedVirtualPortBackingInfo
 $dev.Backing.Port = New-Object VMware.Vim.DistributedVirtualSwitchPortConnection
 $dev.Backing.Port.PortgroupKey = $dvPgKey
 $dev.Backing.Port.SwitchUuid = $dvSwitchUuid
 $dev.Key = $tgtdev.Key

 $devChange.Device = $dev
 $spec.deviceChange = $devChange

 $taskMoRef = $vm.ReconfigVM_Task($spec)

 $task = Get-View $taskMoRef
 while("running","queued" -contains $task.Info.State){
 $task.UpdateViewData("Info")
 }
}

$vmName = "PC2"
$nicName = "Network adapter 1"
$dvPortgroupName = "dvPg1"

Set-VM2dvPortgroup $vmName $nicName $dvPortgroupNam

Annotations:

Line 30: the Device property in the VirtualDeviceConfigSpec object needs to have an object of a type that corresponds with the network card type you are trying to move to the dvPortgroup.

Line 43: Since this requires the ReconfigVM_Task method, which is executed on a VirtualMachine object, you can only migrate one guest per call. You can migrate multiple NICs of the guest in one call to ReconfigVM_Task. To do this you will have to create an array of VirtualDeviceConfigSpec objects. Each array element corresponding with 1 NIC.

Note that this function already appeared in a slightly different format on Arne’s blog. See the PowerCLI: Set-dvSwitch entry.

Schematically we now have something like this.

dvSw1-config2

This concludes Part2 of the dvSwitch series.

  1. Pablo
    July 22nd, 2010 at 22:45 | #1

    @LucD
    Wow… are you from this planet ? Thanks !!

  2. Pablo
    July 20th, 2010 at 20:08 | #2

    Hi Luc…

    I’ve been trying to get some experience with PowerShell\PowerCLI and your posts helped me a lot… thank you !

    I was just wondering if it would be possible to add some other properties to your New-dvSwPortgroup function, specifically… I am looking to change the default value “Mac Address Change : Accept” to Reject…

    Thanks in advance,
    Pablo.

    • July 22nd, 2010 at 21:44 | #3

      Hi Pablo, the script has been updated.
      It now has support for the security policy and for the teaming policy.
      14 new parameters available !

  3. March 2nd, 2010 at 23:16 | #4

    Hi Luc,

    Nice script you make. I am trying to refine your script to change to connect a vm to a dvportgroup.

    I have a NIC with a static mac address, but when I use the script it changes to a dynamic address.

    I found VMware.Vim.VirtualDeviceConnectInfo but I cannot get it to work.

    can you get me started?

    Gert

  4. February 2nd, 2010 at 14:20 | #7

    Hi,

    Maybe you can help me..

    I am looking for a way to check if a dvp with a certain VLAN exists. Do you have any idea how to do this?

    I am creating a sort of class setup with for each workspot a seperate vlan, connected on a distributed portgroup

    thanks in advance.

    greetings.

    Gert.

  5. Mark
    October 16th, 2009 at 11:41 | #10

    Wow, Luc you are a genius! This and part 1 was exactly what I needed, didn’t have to modify anything!

    One thing though, I have a requirement to create VMkernel ports for VMotion on the dvSwitches… do you have any idea how I can do that? or do i just need to wait a bit longer for part 3? :-)

    Keep up the great work!

    • October 16th, 2009 at 12:42 | #11

      Thanks Mark.
      The next part should be published in the coming days.

  1. October 12th, 2009 at 02:57 | #1
  2. July 22nd, 2010 at 22:14 | #2