yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/esxi/net_topology_pro.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package esxi
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"sort"
    21  	"sync"
    22  
    23  	"github.com/vmware/govmomi/vim25/mo"
    24  	"github.com/vmware/govmomi/vim25/types"
    25  	"golang.org/x/sync/errgroup"
    26  
    27  	"yunion.io/x/jsonutils"
    28  	"yunion.io/x/log"
    29  	"yunion.io/x/pkg/errors"
    30  	"yunion.io/x/pkg/util/netutils"
    31  	"yunion.io/x/pkg/util/regutils"
    32  )
    33  
    34  var (
    35  	SIMPLE_HOST_PROPS    = []string{"name", "config.network", "vm"}
    36  	SIMPLE_VM_PROPS      = []string{"name", "guest.net", "config.template", "config.hardware.device"}
    37  	SIMPLE_DVPG_PROPS    = []string{"key", "config.defaultPortConfig", "config.distributedVirtualSwitch"}
    38  	SIMPLE_DVS_PROPS     = []string{"name", "config"}
    39  	SIMPLE_NETWORK_PROPS = []string{"name"}
    40  )
    41  
    42  type SIPVlan struct {
    43  	IP     netutils.IPV4Addr
    44  	VlanId int32
    45  }
    46  
    47  type SSimpleVM struct {
    48  	Name    string
    49  	IPVlans []SIPVlan
    50  }
    51  
    52  type SSimpleHostDev struct {
    53  	Name string
    54  	Id   string
    55  	Mac  string
    56  }
    57  
    58  func (cli *SESXiClient) scanAllDvPortgroups() ([]*SDistributedVirtualPortgroup, error) {
    59  	var modvpgs []mo.DistributedVirtualPortgroup
    60  	err := cli.scanAllMObjects(SIMPLE_DVPG_PROPS, &modvpgs)
    61  	if err != nil {
    62  		return nil, errors.Wrap(err, "scanAllMObjects")
    63  	}
    64  	dvpgs := make([]*SDistributedVirtualPortgroup, 0, len(modvpgs))
    65  	for i := range modvpgs {
    66  		dvpgs = append(dvpgs, NewDistributedVirtualPortgroup(cli, &modvpgs[i], nil))
    67  	}
    68  	return dvpgs, nil
    69  }
    70  
    71  func (cli *SESXiClient) scanAllNetworks() ([]mo.Network, error) {
    72  	var monets []mo.Network
    73  	err := cli.scanAllMObjects(SIMPLE_NETWORK_PROPS, &monets)
    74  	if err != nil {
    75  		return nil, errors.Wrap(err, "scanAllMObjects")
    76  	}
    77  	return monets, nil
    78  }
    79  
    80  func (cli *SESXiClient) networkName(refV string) (string, error) {
    81  	if cli.networkQueryMap == nil {
    82  		nets, err := cli.scanAllNetworks()
    83  		if err != nil {
    84  			return "", err
    85  		}
    86  		cli.networkQueryMap = &sync.Map{}
    87  		for i := range nets {
    88  			cli.networkQueryMap.Store(nets[i].Reference().Value, nets[i].Name)
    89  		}
    90  	}
    91  	iter, ok := cli.networkQueryMap.Load(refV)
    92  	if !ok {
    93  		return "", nil
    94  	}
    95  	return iter.(string), nil
    96  }
    97  
    98  func (cli *SESXiClient) hostVMIPsPro(ctx context.Context, hosts []mo.HostSystem) (SNetworkInfoPro, error) {
    99  	ret := SNetworkInfoPro{
   100  		SNetworkInfoBase: SNetworkInfoBase{
   101  			VMs:    []SSimpleVM{},
   102  			IPPool: SIPPool{},
   103  		},
   104  		HostIps: make(map[string][]netutils.IPV4Addr),
   105  	}
   106  	vsMap, err := cli.getVirtualSwitchs(hosts)
   107  	if err != nil {
   108  		return ret, errors.Wrap(err, "unable to getVirtualSwitchs")
   109  	}
   110  	ret.VsMap = vsMap
   111  	dvpgMap, err := cli.getDVPGMap()
   112  	if err != nil {
   113  		return ret, errors.Wrap(err, "unable to get dvpgKeyVlanMap")
   114  	}
   115  	group, ctx := errgroup.WithContext(ctx)
   116  	collection := make([]*SNetworkInfoPro, len(hosts))
   117  	for i := range hosts {
   118  		j := i
   119  		group.Go(func() error {
   120  			nInfo, err := cli.vmIPsPro(&hosts[j], dvpgMap)
   121  			if err != nil {
   122  				return err
   123  			}
   124  			collection[j] = nInfo.(*SNetworkInfoPro)
   125  			return nil
   126  		})
   127  	}
   128  
   129  	err = group.Wait()
   130  	if err != nil {
   131  		return ret, err
   132  	}
   133  	cli.mergeNetworInfoPro(&ret, collection)
   134  	vsList := vsMap.List()
   135  	for i := range vsList {
   136  		vs := vsList[i]
   137  		for hName, ips := range vs.HostIps {
   138  			sort.Slice(ips, func(i, j int) bool {
   139  				return ips[i] < ips[j]
   140  			})
   141  			for _, ip := range ips {
   142  				ret.IPPool.Insert(ip, SIPProc{
   143  					VlanId: 0,
   144  					VSId:   vs.Id,
   145  					IsHost: true,
   146  				})
   147  			}
   148  			ret.HostIps[hName] = append(ret.HostIps[hName], ips...)
   149  		}
   150  	}
   151  	return ret, nil
   152  }
   153  
   154  func (cli *SESXiClient) mergeNetworInfoPro(ret *SNetworkInfoPro, nInfos []*SNetworkInfoPro) {
   155  	log.Infof("nInfos before mergeNetworInfoPro: %s", jsonutils.Marshal(nInfos))
   156  	var vmsLen, ipPoolLen int
   157  	for i := range nInfos {
   158  		vmsLen += len(nInfos[i].VMs)
   159  		ipPoolLen += nInfos[i].IPPool.Len()
   160  	}
   161  	ret.VMs = make([]SSimpleVM, 0, vmsLen)
   162  	ret.IPPool = NewIPPool(ipPoolLen)
   163  	for i := range nInfos {
   164  		ret.VMs = append(ret.VMs, nInfos[i].VMs...)
   165  		ret.IPPool.Merge(&nInfos[i].IPPool)
   166  		ret.VsMap.Merge(&nInfos[i].VsMap)
   167  	}
   168  }
   169  
   170  func (cli *SESXiClient) HostVmIPsPro(ctx context.Context) (SNetworkInfoPro, error) {
   171  	var hosts []mo.HostSystem
   172  	err := cli.scanAllMObjects(SIMPLE_HOST_PROPS, &hosts)
   173  	if err != nil {
   174  		return SNetworkInfoPro{}, errors.Wrap(err, "scanAllMObjects")
   175  	}
   176  	filtedHosts := make([]mo.HostSystem, 0, len(hosts))
   177  	for i := range hosts {
   178  		if hosts[i].Config == nil || hosts[i].Config.Network == nil {
   179  			continue
   180  		}
   181  		filtedHosts = append(filtedHosts, hosts[i])
   182  	}
   183  	return cli.hostVMIPsPro(ctx, filtedHosts)
   184  }
   185  
   186  func vpgMapKey(prefix, key string) string {
   187  	if len(prefix) == 0 {
   188  		return key
   189  	}
   190  	return fmt.Sprintf("%s-%s", prefix, key)
   191  }
   192  
   193  func (cli *SESXiClient) macVlanMap(mohost *mo.HostSystem, movm *mo.VirtualMachine, dvpgMap sVPGMap) (map[string]SIPProc, error) {
   194  	vpgMap := cli.getVPGMap(mohost)
   195  	ret := make(map[string]SIPProc, 2)
   196  	for _, device := range movm.Config.Hardware.Device {
   197  		bcard, ok := device.(types.BaseVirtualEthernetCard)
   198  		if !ok {
   199  			continue
   200  		}
   201  		card := bcard.GetVirtualEthernetCard()
   202  		mac := card.MacAddress
   203  		switch bk := card.Backing.(type) {
   204  		case *types.VirtualEthernetCardDistributedVirtualPortBackingInfo:
   205  			key := vpgMapKey("", bk.Port.PortgroupKey)
   206  			proc, ok := dvpgMap.Get(key)
   207  			if !ok {
   208  				log.Errorf("dvpg %s not found in key-vlanid map", key)
   209  				continue
   210  			}
   211  			ret[mac] = proc
   212  		case *types.VirtualEthernetCardNetworkBackingInfo:
   213  			netName, err := cli.networkName(bk.Network.Value)
   214  			if err != nil {
   215  				return nil, errors.Wrapf(err, "cli.networkName of %q", bk.Network.Value)
   216  			}
   217  			key := vpgMapKey(mohost.Reference().Value, netName)
   218  			proc, ok := vpgMap.Get(key)
   219  			if !ok {
   220  				log.Errorf("vpg %s not found in key-vlanid map", key)
   221  				continue
   222  			}
   223  			ret[mac] = proc
   224  		}
   225  	}
   226  	return ret, nil
   227  }
   228  
   229  type SNetworkInfoPro struct {
   230  	SNetworkInfoBase
   231  
   232  	HostIps map[string][]netutils.IPV4Addr
   233  	VsMap   SVirtualSwitchMap
   234  }
   235  
   236  func (s *SNetworkInfoPro) Insert(proc SIPProc, ip netutils.IPV4Addr) {
   237  	s.SNetworkInfoBase.Insert(proc, ip)
   238  	s.VsMap.AddVlanIp(proc.VSId, proc.VlanId, ip)
   239  }
   240  
   241  type SNetworkInfoBase struct {
   242  	VMs    []SSimpleVM
   243  	IPPool SIPPool
   244  }
   245  
   246  func (s *SNetworkInfoBase) Insert(proc SIPProc, ip netutils.IPV4Addr) {
   247  	s.IPPool.Insert(ip, proc)
   248  }
   249  
   250  func (s *SNetworkInfoBase) AppendVMs(name string, IpVlans []SIPVlan) {
   251  	s.VMs = append(s.VMs, SSimpleVM{name, IpVlans})
   252  }
   253  
   254  type INetworkInfo interface {
   255  	Insert(SIPProc, netutils.IPV4Addr)
   256  	AppendVMs(name string, IpVlans []SIPVlan)
   257  }
   258  
   259  func NewNetworkInfo(dvs bool, size int) INetworkInfo {
   260  	base := SNetworkInfoBase{
   261  		VMs:    make([]SSimpleVM, 0, size),
   262  		IPPool: NewIPPool(int(size)),
   263  	}
   264  	if dvs {
   265  		return &SNetworkInfoPro{
   266  			SNetworkInfoBase: base,
   267  			VsMap:            NewVirtualSwitchMap(),
   268  		}
   269  	}
   270  	return &SNetworkInfo{
   271  		SNetworkInfoBase: base,
   272  		HostIps:          make(map[string]netutils.IPV4Addr),
   273  		VlanIps:          make(map[int32][]netutils.IPV4Addr),
   274  	}
   275  }
   276  
   277  func (cli *SESXiClient) vmIPsPro(host *mo.HostSystem, vpgMap sVPGMap) (INetworkInfo, error) {
   278  	nInfo := NewNetworkInfo(true, len(host.Vm))
   279  	if len(host.Vm) == 0 {
   280  		return nInfo, nil
   281  	}
   282  	var vms []mo.VirtualMachine
   283  	err := cli.references2Objects(host.Vm, SIMPLE_VM_PROPS, &vms)
   284  	if err != nil {
   285  		return nInfo, errors.Wrap(err, "references2Objects")
   286  	}
   287  	for i := range vms {
   288  		vm := vms[i]
   289  		if vm.Config == nil || vm.Config.Template {
   290  			continue
   291  		}
   292  		if vm.Guest == nil {
   293  			continue
   294  		}
   295  		macVlanMap, err := cli.macVlanMap(host, &vm, vpgMap)
   296  		if err != nil {
   297  			return nInfo, err
   298  		}
   299  		guestIps := make([]SIPVlan, 0)
   300  		for _, net := range vm.Guest.Net {
   301  			if len(net.Network) == 0 {
   302  				continue
   303  			}
   304  			mac := net.MacAddress
   305  			for _, ip := range net.IpAddress {
   306  				if !regutils.MatchIP4Addr(ip) {
   307  					continue
   308  				}
   309  				if !vmIPV4Filter.Contains(ip) {
   310  					continue
   311  				}
   312  				ipaddr, _ := netutils.NewIPV4Addr(ip)
   313  				if netutils.IsLinkLocal(ipaddr) {
   314  					continue
   315  				}
   316  				proc := macVlanMap[mac]
   317  				guestIps = append(guestIps, SIPVlan{
   318  					IP:     ipaddr,
   319  					VlanId: proc.VlanId,
   320  				})
   321  				nInfo.Insert(proc, ipaddr)
   322  				break
   323  			}
   324  		}
   325  		nInfo.AppendVMs(vm.Name, guestIps)
   326  	}
   327  	return nInfo, nil
   328  }
   329  
   330  type SVirtualSwitchSpec struct {
   331  	Name        string
   332  	Id          string
   333  	Distributed bool
   334  	Hosts       []SSimpleHostDev
   335  	HostIps     map[string][]netutils.IPV4Addr
   336  	Vlans       map[int32][]netutils.IPV4Addr
   337  }
   338  
   339  func NewVirtualSwitch() *SVirtualSwitchSpec {
   340  	return &SVirtualSwitchSpec{
   341  		HostIps: make(map[string][]netutils.IPV4Addr),
   342  		Vlans:   make(map[int32][]netutils.IPV4Addr),
   343  	}
   344  }
   345  
   346  func (vs *SVirtualSwitchSpec) Merge(vsc *SVirtualSwitchSpec) {
   347  	for vlan, ips := range vsc.Vlans {
   348  		vs.Vlans[vlan] = insert(vs.Vlans[vlan], ips)
   349  	}
   350  }
   351  
   352  func insert(base []netutils.IPV4Addr, add []netutils.IPV4Addr) []netutils.IPV4Addr {
   353  	for _, ip := range add {
   354  		index := sort.Search(len(base), func(n int) bool {
   355  			return base[n] > ip
   356  		})
   357  		base = append(base, 0)
   358  		base = append(base[:index+1], base[index:len(base)-1]...)
   359  		base[index] = ip
   360  	}
   361  	return base
   362  }
   363  
   364  type SVirtualSwitchMap struct {
   365  	vsList []SVirtualSwitchSpec
   366  	vsMap  map[string]*SVirtualSwitchSpec
   367  }
   368  
   369  func NewVirtualSwitchMap(length ...int) SVirtualSwitchMap {
   370  	initLen := 0
   371  	if len(length) > 0 {
   372  		initLen = length[0]
   373  	}
   374  	return SVirtualSwitchMap{
   375  		vsList: make([]SVirtualSwitchSpec, 0, initLen),
   376  		vsMap:  make(map[string]*SVirtualSwitchSpec, initLen),
   377  	}
   378  }
   379  
   380  func (vsm *SVirtualSwitchMap) Insert(id string, vs SVirtualSwitchSpec) {
   381  	ovs, ok := vsm.vsMap[id]
   382  	if ok {
   383  		ovs.Merge(&vs)
   384  		return
   385  	}
   386  	vsm.vsList = append(vsm.vsList, vs)
   387  	vsm.vsMap[id] = &vsm.vsList[len(vsm.vsList)-1]
   388  }
   389  
   390  func (vms *SVirtualSwitchMap) Merge(ovsm *SVirtualSwitchMap) {
   391  	for i := range ovsm.vsList {
   392  		vs := ovsm.vsList[i]
   393  		vms.Insert(vs.Id, vs)
   394  	}
   395  }
   396  
   397  func (vsm *SVirtualSwitchMap) AddVlanIp(id string, vlanId int32, ip netutils.IPV4Addr) bool {
   398  	vs, ok := vsm.vsMap[id]
   399  	if !ok {
   400  		vs = NewVirtualSwitch()
   401  		vs.Id = id
   402  		vsm.Insert(id, *vs)
   403  		vs = vsm.vsMap[id]
   404  	}
   405  	vs.Vlans[vlanId] = append(vs.Vlans[vlanId], ip)
   406  	return true
   407  }
   408  
   409  func (vsm *SVirtualSwitchMap) List() []SVirtualSwitchSpec {
   410  	return vsm.vsList
   411  }
   412  
   413  func findIp(hs *mo.HostSystem, nic string) netutils.IPV4Addr {
   414  	for i := range hs.Config.Network.Pnic {
   415  		pnic := hs.Config.Network.Pnic[i]
   416  		if pnic.Device != nic {
   417  			continue
   418  		}
   419  		ip := pnic.Spec.Ip.IpAddress
   420  		if len(ip) == 0 {
   421  			return netutils.IPV4Addr(0)
   422  		}
   423  		if !regutils.MatchIP4Addr(ip) {
   424  			return netutils.IPV4Addr(0)
   425  		}
   426  		ipaddr, _ := netutils.NewIPV4Addr(ip)
   427  		if netutils.IsLinkLocal(ipaddr) {
   428  			return netutils.IPV4Addr(0)
   429  		}
   430  		return ipaddr
   431  	}
   432  	return netutils.IPV4Addr(0)
   433  }
   434  
   435  func getNicDevice(vs *types.HostVirtualSwitch) []string {
   436  	bridge := vs.Spec.Bridge
   437  	switch b := bridge.(type) {
   438  	case *types.HostVirtualSwitchAutoBridge:
   439  		return b.ExcludedNicDevice
   440  	case *types.HostVirtualSwitchBondBridge:
   441  		return b.NicDevice
   442  	case *types.HostVirtualSwitchSimpleBridge:
   443  		return []string{b.NicDevice}
   444  	default:
   445  		return nil
   446  	}
   447  }
   448  
   449  func (cli *SESXiClient) getVirtualSwitchs(hss []mo.HostSystem) (SVirtualSwitchMap, error) {
   450  	nic2Ip := make(map[string]netutils.IPV4Addr, len(hss))
   451  	nic2Mac := make(map[string]string, len(hss))
   452  	for j := range hss {
   453  		hs := hss[j]
   454  		macToIp := make(map[string]string, len(hs.Config.Network.Vnic))
   455  		for i := range hs.Config.Network.Vnic {
   456  			vnic := hs.Config.Network.Vnic[i]
   457  			if len(vnic.Spec.Ip.IpAddress) == 0 {
   458  				continue
   459  			}
   460  			macToIp[vnic.Spec.Mac] = vnic.Spec.Ip.IpAddress
   461  		}
   462  		for i := range hs.Config.Network.ConsoleVnic {
   463  			vnic := hs.Config.Network.Vnic[i]
   464  			if len(vnic.Spec.Ip.IpAddress) == 0 {
   465  				continue
   466  			}
   467  			macToIp[vnic.Spec.Mac] = vnic.Spec.Ip.IpAddress
   468  		}
   469  		for i := range hs.Config.Network.Pnic {
   470  			pnic := hs.Config.Network.Pnic[i]
   471  			ip := pnic.Spec.Ip.IpAddress
   472  			nicKey := fmt.Sprintf("%s-%s", hs.Self.Value, pnic.Device)
   473  			nic2Mac[nicKey] = pnic.Mac
   474  			if len(ip) == 0 {
   475  				ip = macToIp[pnic.Mac]
   476  			}
   477  			if len(ip) == 0 {
   478  				log.Warningf("host %s pnic %s has no ipaddress", hs.Name, pnic.Device)
   479  				continue
   480  			}
   481  			if !regutils.MatchIP4Addr(ip) {
   482  				log.Warningf("host %s pnic %s ipaddress %q is not IPV4Addr", hs.Name, pnic.Device, ip)
   483  				continue
   484  			}
   485  			ipaddr, _ := netutils.NewIPV4Addr(ip)
   486  			if netutils.IsLinkLocal(ipaddr) {
   487  				log.Warningf("host %s pnic %s ipaddress %q is link local addr", hs.Name, pnic.Device, ip)
   488  				continue
   489  			}
   490  			nic2Ip[nicKey] = ipaddr
   491  		}
   492  	}
   493  	value2name := make(map[string]string, len(hss))
   494  	for i := range hss {
   495  		value2name[hss[i].Self.Value] = hss[i].Name
   496  	}
   497  	// dvs
   498  	var dvss []mo.DistributedVirtualSwitch
   499  	err := cli.scanAllMObjects(SIMPLE_DVS_PROPS, &dvss)
   500  	if err != nil {
   501  		return SVirtualSwitchMap{}, err
   502  	}
   503  	ret := NewVirtualSwitchMap(len(dvss) + len(hss))
   504  	for i := range dvss {
   505  		dvs := dvss[i]
   506  		vsId := dvs.Self.Value
   507  		vsName := fmt.Sprintf("%s", dvs.Name)
   508  		hosts := dvs.Config.GetDVSConfigInfo().Host
   509  		vs := SVirtualSwitchSpec{
   510  			Name:        vsName,
   511  			Id:          vsId,
   512  			Distributed: true,
   513  			HostIps:     make(map[string][]netutils.IPV4Addr, len(hosts)),
   514  			Vlans:       make(map[int32][]netutils.IPV4Addr),
   515  		}
   516  		for _, host := range hosts {
   517  			hostName := value2name[host.Config.Host.Value]
   518  			vs.HostIps[hostName] = []netutils.IPV4Addr{}
   519  			hostDev := SSimpleHostDev{
   520  				Id:   host.Config.Host.Value,
   521  				Name: hostName,
   522  			}
   523  			switch back := host.Config.Backing.(type) {
   524  			case *types.DistributedVirtualSwitchHostMemberPnicBacking:
   525  				for i := range back.PnicSpec {
   526  					nicDevice := back.PnicSpec[i].PnicDevice
   527  					nicKey := fmt.Sprintf("%s-%s", host.Config.Host.Value, nicDevice)
   528  					hostDev.Mac = nic2Mac[nicKey]
   529  					ip, ok := nic2Ip[nicKey]
   530  					if ok {
   531  						vs.HostIps[hostName] = append(vs.HostIps[hostName], ip)
   532  					}
   533  				}
   534  			case *types.DistributedVirtualSwitchHostMemberBacking:
   535  			}
   536  			vs.Hosts = append(vs.Hosts, hostDev)
   537  		}
   538  		ret.Insert(vsId, vs)
   539  	}
   540  	// vs
   541  	for i := range hss {
   542  		hs := hss[i]
   543  		if hs.Config == nil || hs.Config.Network == nil {
   544  			continue
   545  		}
   546  		for i := range hs.Config.Network.Vswitch {
   547  			ivs := hs.Config.Network.Vswitch[i]
   548  			vsId := fmt.Sprintf("%s/%s", hs.Self.Value, ivs.Name)
   549  			vsName := fmt.Sprintf("%s/%s", hs.Name, ivs.Name)
   550  			vs := SVirtualSwitchSpec{
   551  				Name:        vsName,
   552  				Id:          vsId,
   553  				Distributed: false,
   554  				HostIps:     make(map[string][]netutils.IPV4Addr),
   555  				Vlans:       make(map[int32][]netutils.IPV4Addr),
   556  			}
   557  			hostDev := SSimpleHostDev{
   558  				Id:   hs.Self.Value,
   559  				Name: hs.Name,
   560  			}
   561  			for _, nic := range getNicDevice(&ivs) {
   562  				nicKey := fmt.Sprintf("%s-%s", hs.Self.Value, nic)
   563  				log.Infof("nic: %s, nicKey: %s", nic, nicKey)
   564  				hostDev.Mac = nic2Mac[nicKey]
   565  				ip, ok := nic2Ip[nicKey]
   566  				if !ok {
   567  					continue
   568  				}
   569  				vs.HostIps[hs.Name] = append(vs.HostIps[hs.Name], ip)
   570  			}
   571  			vs.Hosts = append(vs.Hosts, hostDev)
   572  			ret.Insert(vsId, vs)
   573  		}
   574  	}
   575  	return ret, nil
   576  }
   577  
   578  func (cli *SESXiClient) getVPGMap(mohost *mo.HostSystem) sVPGMap {
   579  	sm := newVPGMap()
   580  	if mohost.Config == nil || mohost.Config.Network == nil {
   581  		return sm
   582  	}
   583  	for i := range mohost.Config.Network.Portgroup {
   584  		ipg := mohost.Config.Network.Portgroup[i]
   585  		key := vpgMapKey(mohost.Reference().Value, ipg.Spec.Name)
   586  		vlan := ipg.Spec.VlanId
   587  		vsId := fmt.Sprintf("%s/%s", mohost.Reference().Value, ipg.Spec.VswitchName)
   588  		sm.Insert(key, SIPProc{
   589  			VlanId: vlan,
   590  			VSId:   vsId,
   591  		})
   592  	}
   593  	return sm
   594  }
   595  
   596  func (cli *SESXiClient) getDVPGMap() (sVPGMap, error) {
   597  	sm := newVPGMap()
   598  	dvpgs, err := cli.scanAllDvPortgroups()
   599  	if err != nil {
   600  		return sm, err
   601  	}
   602  	for i := range dvpgs {
   603  		modvpg := dvpgs[i].getMODVPortgroup()
   604  		key := vpgMapKey("", modvpg.Key)
   605  		vlanid := dvpgs[i].GetVlanId()
   606  		vsId := modvpg.Config.DistributedVirtualSwitch.Value
   607  		sm.Insert(key, SIPProc{
   608  			VlanId: vlanid,
   609  			VSId:   vsId,
   610  		})
   611  	}
   612  	return sm, nil
   613  }
   614  
   615  func newVPGMap() sVPGMap {
   616  	return sVPGMap{m: &sync.Map{}}
   617  }
   618  
   619  type sVPGMap struct {
   620  	m *sync.Map
   621  }
   622  
   623  func (vm *sVPGMap) Insert(key string, proc SIPProc) {
   624  	vm.m.Store(key, proc)
   625  }
   626  
   627  func (vm *sVPGMap) Get(key string) (SIPProc, bool) {
   628  	v, ok := vm.m.Load(key)
   629  	if !ok {
   630  		return SIPProc{}, ok
   631  	}
   632  	r := v.(SIPProc)
   633  	return r, ok
   634  }
   635  
   636  type SIPProc struct {
   637  	VSId   string
   638  	VlanId int32
   639  	IsHost bool
   640  }
   641  
   642  type SIPPool struct {
   643  	p map[netutils.IPV4Addr]SIPProc
   644  }
   645  
   646  func NewIPPool(size ...int) SIPPool {
   647  	if len(size) > 0 {
   648  		return SIPPool{p: make(map[netutils.IPV4Addr]SIPProc, size[0])}
   649  	}
   650  	return SIPPool{p: make(map[netutils.IPV4Addr]SIPProc)}
   651  }
   652  
   653  func (p *SIPPool) Has(ip netutils.IPV4Addr) bool {
   654  	_, ok := p.p[ip]
   655  	return ok
   656  }
   657  
   658  func (p *SIPPool) Get(ip netutils.IPV4Addr) (SIPProc, bool) {
   659  	r, ok := p.p[ip]
   660  	return r, ok
   661  }
   662  
   663  func (p *SIPPool) Insert(ip netutils.IPV4Addr, proc SIPProc) {
   664  	p.p[ip] = proc
   665  }
   666  
   667  func (p *SIPPool) Merge(op *SIPPool) {
   668  	for ip, proc := range op.p {
   669  		if p.Has(ip) {
   670  			continue
   671  		}
   672  		p.Insert(ip, proc)
   673  	}
   674  }
   675  
   676  func (p *SIPPool) Len() int {
   677  	return len(p.p)
   678  }