When configuring a stretched VSAN cluster, the VSAN VMkernel interface is connected to the “default” netstack and manual routes must be added which point to VSAN subnet gateways, which enables VSAN communication in a stretched cluster configuration. Without the additional routes add to the ESXi-hosts, communication to the witness appliance and the remote site is not working.
This script below shows the manual added routes of each ESXi host (vmhost) in the VSAN-enabled cluster.
This really helps when doing stretched VSAN cluster troubleshooting!
Below a small explanation of the script (for the techies):
First retrieve the all ESXi hosts from the selected VSAN enabled cluster:
$vmhosts = ((Get-Cluster).where({$_.VsanEnabled -eq $true}) | Out-GridView -Title "Select VSAN Stretched cluster" -PassThru) | Get-VMHost
Creating a loop for all ESXi hosts and retrieve the required information from each individual host:
foreach ($vmhost in $vmhosts) {
#retrieve default netstack default gateway
$vmhostgw = $vmhost.ExtensionData.Config.Network.IpRouteConfig.DefaultGateway
#retrieve VSAN VMkernel interface details
$vsanvmk = Get-VMHostNetworkAdapter -VMHost $vmhost | ? {$_.VsanTrafficEnabled -eq $True}
#create variables for IP, SubnetMask and Subnet
$vsanIP = [IPaddress]$vsanvmk.IP
$vsansubnet = [IPaddress]$vsanvmk.SubnetMask
$vsanlocalsubnet = ([IPAddress] (([IPAddress] $vsanvmk.IP).Address -band ([IPAddress] $vsanvmk.SubnetMask).Address)).IPAddressToString
#retrieve VMhosts routes
$vmhostroutes = Get-VMHostRoute -VMHost $vmhost
The idea here is to filter the route list, filtering out IPv6-routes, local attached subnets and the default gateway route.
$vmhostipv4routes = $vmhostroutes.Where({$_.Gateway -like "*.*"}) #IPv4 filter
$vmhostipv4routes = $vmhostipv4routes.Where({$_.Gateway -ne "0.0.0.0"}) #local attached filter
$vmhostunknownroutes = $vmhostipv4routes.Where({$_.Gateway -ne $vmhostgw})#defaul gw filter
The results is a $vmhostunknownroutes variable which (prosumbaly) contain all manual added VSAN routes. It collects all routes and display them per host.
$vsanremotesubnets = @()
foreach ($route in $vmhostunknownroutes) {
$routegw = [IPaddress]$route.Gateway.Address
if (($routegw.Address -band $vsansubnet.Address) -eq ($vsanip.Address -band $vsansubnet.Address)) {$vsanremotesubnets += $route}
}
write-host $vmhost "has the following vsan (remote) routes: "$vsanremotesubnets
and finally close the foreach loop
}
below the whole script. ENJOY!
$vmhosts = ((Get-Cluster).where({$_.VsanEnabled -eq $true}) | Out-GridView -Title "Select VSAN Stretched cluster" -PassThru) | Get-VMHost
foreach ($vmhost in $vmhosts) {
$vmhostgw = $vmhost.ExtensionData.Config.Network.IpRouteConfig.DefaultGateway
$vsanvmk = Get-VMHostNetworkAdapter -VMHost $vmhost | ? {$_.VsanTrafficEnabled -eq $True}
$vsanIP = [IPaddress]$vsanvmk.IP
$vsansubnet = [IPaddress]$vsanvmk.SubnetMask
$vsanlocalsubnet = ([IPAddress] (([IPAddress] $vsanvmk.IP).Address -band ([IPAddress] $vsanvmk.SubnetMask).Address)).IPAddressToString
$vmhostroutes = Get-VMHostRoute -VMHost $vmhost
$vmhostipv4routes = $vmhostroutes.Where({$_.Gateway -like "*.*"})
$vmhostipv4routes = $vmhostipv4routes.Where({$_.Gateway -ne "0.0.0.0"})
$vmhostunknownroutes = $vmhostipv4routes.Where({$_.Gateway -ne $vmhostgw})
$vsanremotesubnets = @()
foreach ($route in $vmhostunknownroutes) {
$routegw = [IPaddress]$route.Gateway.Address
if (($routegw.Address -band $vsansubnet.Address) -eq ($vsanip.Address -band $vsansubnet.Address)) {$vsanremotesubnets += $route}
}
write-host $vmhost "has the following vsan (remote) routes: "$vsanremotesubnets
}
I’m trying to create a script which creates all (missing) routes based on the locally attached subnets (of the VSAN enabled VMK-interface) of all hosts. Check my blog for future updates!
June 25, 2019
[…] way of doing this, this should be automatizible/scriptable!”. I’ve started with a small PSscript, which helped with troubleshooting VSAN, but then I build out the same script (BIG time) a.k.a. 700 […]