I had the need to change the configuration of my ESX hosts so that the virtual switches had a single active and single standby adapter assigned to them. The reason for the need is rather irritating (the IBM I/O modules that we have in these particular blade centers are not really designed to handle a high amount of traffic), and it was causing some issues during vMotions.
This script allows me set the vmnics assigned to a vswitch to the desired active/standby configuration, and additionally allows me to set the port group’s vmnic active/standby policy. In my setup, I use two vSwitches, one for primary COS, vMotion and IP storage, and a second vSwitch for the virtual machines and secondary COS, each vSwitch has two NICs assigned (remember, they’re blade centers…limited network connectivity). In order to avoid vMotion taking all the bandwidth for storage I wanted to separate their traffic onto different NICs, but still provide redundancy.
The way that I accomplish this is by making the default for the vSwitch have, for example, vmnic0 active and vmnic2 standby. I then adjust the vMotion port group so that it has the opposite (vmnic2 active and vmnic0 standby). Redundancy is still present in the event of a NIC failure, but under normal circumstances, the traffic is separate.
Without further justification on my part….
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
#!/usr/bin/perl -w # # cfg-nic-policy.pl - written by Andrew Sullivan, 2009-02-03, http://www.get-admin.com # # Please report bugs and request improvements at http://get-admin.com/blog/?p=468 # # This script will adjust the active and standby NICs assigned to a virtual switch. It # is HIGHLY recommended that you place the ESX host in maintenance mode before adjusting # the virtual switch or port group configurations. # # Examples: # Set vmnic0 to active and vmnic1 to standby for a vswitch, connect through vCenter # ./cfg-nic-policy.pl --server your.esx.host --vihost your.esx.server --active vmnic0 --standby vmnic1 --vswitch vSwitch1 # # Set vmnic0 and vmnic1 to active for a vswitch, connect through vCenter # ./cfg-nic-policy.pl --server your.esx.host --vihost your.esx.server --active vmnic0,vmnic1 --vswitch vSwitch0 # # Set vmnic1 to active and vmnic0 to standby for a portgroup, connect directly to the host # ./cfg-nic-policy.pl --server your.esx.server --active vmnic1 --standby vmnic0 --portgroup "Some Random Portgroup" # # Note that the values specified for --active and --standby must be vmnic identifiers. Anything # that does not start with "vmnic" will be discarded. # # If you do not specify a vmnic as active or standby, but it is connected to the vSwitch, it will # be listed as "unused" when viewed from the VI Client. # # If you specify a vmnic that has not been assigned to the vSwitch an error will occur and the # vmnics assigned to the vSwitch will be printed. # use strict; use warnings; use FindBin; use lib "$FindBin::Bin/../"; use VMware::VIRuntime; my %opts = ( 'vihost' => { type => "=s", help => "The name of the ESX host, only required if you are connecting through vCenter", required => 0 }, 'vswitch' => { type => "=s", help => "The name of the vSwitch to modify", required => 0, default => "" }, 'portgroup' => { type => "=s", help => "The name of the portgroup to modify", required => 0, default => "" }, 'active' => { type => "=s", help => "A comma delimited list of nics to be active. At least one *valid* vmnic must be supplied.", required => 1 }, 'standby' => { type => "=s", help => "A comma delimited list of nics to be passive", required => 0, default => "" } ); Opts::add_options(%opts); Opts::parse(); Opts::validate(); Util::connect(); # Determine if we have to reset the variable depending on if we are connecting # thruough vCenter or not my $vihost; if (Opts::option_is_set('vihost') && Opts::get_option('vihost') ne "") { $vihost = Opts::get_option('vihost'); } else { $vihost = Opts::get_option('server'); } # get the host view my $host = Vim::find_entity_view( view_type => 'HostSystem', filter => { 'name' => qr/($vihost)/i } ); # get the network config view my $networkConfigView = Vim::get_view( mo_ref => $host->configManager->networkSystem ); # parse and validate the args...if the arg is not valid, # it is simply ignored my @activeNics; foreach (split(/,/, Opts::get_option('active'))) { if ($_ =~ /vmnicd+/) { chomp($_); push(@activeNics, $_); } } my @standbyNics; foreach (split(/,/, Opts::get_option('standby'))) { if ($_ =~ /vmnicd+/) { chomp($_); push(@standbyNics, $_); } } if (scalar(@activeNics) networkConfig->portgroup}) { if ($portgroup->spec->name eq $portgroupName) { # set our found var so that it doesn't misreport at the bottom $found = "true"; # update the policy with the new nic order $portgroup->spec->policy( createPolicy($portgroup->spec->policy, $active, $standby) ); # call the update method from the view eval { $networkView->UpdatePortGroup( pgName => $portgroup->spec->name, portgrp => $portgroup->spec ); }; # check for errors if ($@) { Util::trace(0, "An error occurred: " . $@ . "n"); } } } if ($found eq "false") { print "PortGroup " . $portgroupName . " was not foundn"; } } # # setVswitchConfig - creates the spec and updates the config for a vswitch to modify the nic policy # # $networkView - MO_REF to the host network system # $vswitchName - The name of the vSwitch to be modified # $active - an array reference to the array of nics to be set active # $standby - an array reference to the array of nics to be set standby # sub setVswitchConfig { my ($networkView, $vswitchName, $active, $standby) = @_; # variable to determine if the vswitch was found my $found = "false"; # loop through the vswitches, looking for the one we want foreach my $vswitch (@{$networkView->networkConfig->vswitch}) { if ($vswitch->name eq $vswitchName) { # set our found var so that it doesn't misreport at the bottom $found = "true"; # update the policy with the new nic order $vswitch->spec->policy( createPolicy($vswitch->spec->policy, $active, $standby) ); # call the update method from the view eval { $networkView->UpdateVirtualSwitch( vswitchName => $vswitch->name, spec => $vswitch->spec ); }; # check for errors if ($@) { if (ref($@) eq "SoapFault") { if (ref($@->detail) eq 'InvalidArgument') { # going to assume that this is because the user specified a NIC that doesn't belong to the vSwitch Util::trace(0, "vSwitch " . $vswitch->name . " has not been assigned one of the nics specified.n"); Util::trace(0, "NICs currently assigned are: " . join(" ", @{$vswitch->spec->bridge->nicDevice}) . "n"); } else { Util::trace(0, "Error during vSwitch " . $vswitch->name . " reconfigure: " . $@ . "n"); } } else { Util::trace(0, "An unknown error occurred: " . $@ . "n"); } } } } if ($found eq "false") { print "vSwitch " . $vswitchName . " was not foundn"; } } # # createPolicy - creates the policy portion of a spec based on parameters passed to it # # $oldPolicy - a reference to the policy object from the current config # $active - an array reference to the array of nics to be set active # $standby - an array reference to the array of nics to be set standby # sub createPolicy { my ($oldPolicy, $active, $standby) = @_; my $nicOrderPolicy = HostNicOrderPolicy->new( 'activeNic' => [ @$active ], 'standbyNic' => [ @$standby ] ); $oldPolicy->nicTeaming->nicOrder($nicOrderPolicy); return $oldPolicy; } |
The same philosophy will also work if you use a single vSwitch with four (or however many) NICs assigned to it. What will complicate things is if you are using a port channel (or LACP) setup. If you are, then the NICs must stay paired and both must be active. I say this assuming you are using only two links. If you have port channels that consist of two NICs and you have two channels per vSwitch (for a total of four NICs to a vSwitch), then just make sure that you keep the two channeled NICs together in the active/standby configuration.
To adjust the active/standby NICs from the command line is a little more obscure…you have to use the vmware-vim-cmd
, or vimsh
if you are using ESX < 3.5.
1 2 |
vmware-vim-cmd hostsvc/net/vswitch_setpolicy --nicorderpolicy-active=vmnic0 vSwitch0 vmware-vim-cmd hostsvc/net/vswitch_setpolicy --nicorderpolicy-standby=vmnic1 vSwitch0 |
xtravirt has some outstanding documentation on the voodoo behind the vimsh/vmware-vim-cmd commands, so be sure to check them out if you are going to be modifying port groups and vSwitches from the command line.