yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/esxi/net_topology.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 "sort" 20 21 "github.com/vmware/govmomi/vim25/mo" 22 "golang.org/x/sync/errgroup" 23 24 "yunion.io/x/pkg/errors" 25 "yunion.io/x/pkg/util/netutils" 26 "yunion.io/x/pkg/util/regutils" 27 ) 28 29 func (cli *SESXiClient) HostVmIPsInDc(ctx context.Context, dc *SDatacenter) (SNetworkInfo, error) { 30 var hosts []mo.HostSystem 31 err := cli.scanMObjects(dc.object.Entity().Self, HOST_SYSTEM_PROPS, &hosts) 32 if err != nil { 33 return SNetworkInfo{}, errors.Wrap(err, "scanMObjects") 34 } 35 return cli.hostVMIPs(ctx, hosts) 36 } 37 38 func (cli *SESXiClient) HostVmIPsInCluster(ctx context.Context, cluster *SCluster) (SNetworkInfo, error) { 39 var hosts []mo.HostSystem 40 err := cli.scanMObjects(cluster.object.Entity().Self, HOST_SYSTEM_PROPS, &hosts) 41 if err != nil { 42 return SNetworkInfo{}, errors.Wrap(err, "scanMObjects") 43 } 44 return cli.hostVMIPs(ctx, hosts) 45 } 46 47 type SNetworkInfo struct { 48 SNetworkInfoBase 49 50 HostIps map[string]netutils.IPV4Addr 51 VlanIps map[int32][]netutils.IPV4Addr 52 } 53 54 func (s *SNetworkInfo) Insert(proc SIPProc, ip netutils.IPV4Addr) { 55 s.SNetworkInfoBase.Insert(proc, ip) 56 s.VlanIps[proc.VlanId] = append(s.VlanIps[proc.VlanId], ip) 57 } 58 59 func (cli *SESXiClient) hostVMIPs(ctx context.Context, hosts []mo.HostSystem) (SNetworkInfo, error) { 60 ret := SNetworkInfo{} 61 dvpgMap, err := cli.getDVPGMap() 62 if err != nil { 63 return ret, errors.Wrap(err, "unable to get dvpgKeyVlanMap") 64 } 65 group, ctx := errgroup.WithContext(ctx) 66 collection := make([]*SNetworkInfo, len(hosts)) 67 for i := range hosts { 68 j := i 69 group.Go(func() error { 70 nInfo, err := cli.vmIPs(&hosts[j], dvpgMap) 71 if err != nil { 72 return err 73 } 74 collection[j] = nInfo.(*SNetworkInfo) 75 return nil 76 }) 77 } 78 79 hostIps := make(map[string]netutils.IPV4Addr, len(hosts)) 80 for i := range hosts { 81 // find ip 82 host := &SHost{SManagedObject: newManagedObject(cli, &hosts[i], nil)} 83 ipStr := host.GetAccessIp() 84 ip, err := netutils.NewIPV4Addr(ipStr) 85 if err != nil { 86 return ret, errors.Wrapf(err, "invalid host ip %q", ipStr) 87 } 88 hostIps[host.GetName()] = ip 89 } 90 err = group.Wait() 91 if err != nil { 92 return ret, err 93 } 94 // length 95 if len(collection) == 0 { 96 ret.HostIps = hostIps 97 return ret, nil 98 } 99 ni := cli.mergeNetworInfo(collection) 100 ni.HostIps = hostIps 101 return ni, nil 102 } 103 104 func (cli *SESXiClient) mergeNetworInfo(nInfos []*SNetworkInfo) SNetworkInfo { 105 var vmsLen, vlanIpLen, ipPoolLen int 106 for i := range nInfos { 107 vmsLen += len(nInfos[i].VMs) 108 vlanIpLen += len(nInfos[i].VlanIps) 109 ipPoolLen += nInfos[i].IPPool.Len() 110 } 111 ret := SNetworkInfo{ 112 SNetworkInfoBase: SNetworkInfoBase{ 113 IPPool: NewIPPool(ipPoolLen), 114 VMs: make([]SSimpleVM, 0, vmsLen), 115 }, 116 VlanIps: make(map[int32][]netutils.IPV4Addr, vlanIpLen), 117 } 118 for i := range nInfos { 119 ret.VMs = append(ret.VMs, nInfos[i].VMs...) 120 for vlan, ips := range nInfos[i].VlanIps { 121 ret.VlanIps[vlan] = append(ret.VlanIps[vlan], ips...) 122 } 123 ret.IPPool.Merge(&nInfos[i].IPPool) 124 } 125 for _, ips := range ret.VlanIps { 126 sort.Slice(ips, func(i, j int) bool { 127 return ips[i] < ips[j] 128 }) 129 } 130 return ret 131 } 132 133 func (cli *SESXiClient) HostVmIPs(ctx context.Context) (SNetworkInfo, error) { 134 var hosts []mo.HostSystem 135 err := cli.scanAllMObjects(SIMPLE_HOST_PROPS, &hosts) 136 if err != nil { 137 return SNetworkInfo{}, errors.Wrap(err, "scanAllMObjects") 138 } 139 return cli.hostVMIPs(ctx, hosts) 140 } 141 142 func (cli *SESXiClient) vmIPs(host *mo.HostSystem, vpgMap sVPGMap) (INetworkInfo, error) { 143 nInfo := NewNetworkInfo(false, len(host.Vm)) 144 if len(host.Vm) == 0 { 145 return nInfo, nil 146 } 147 var vms []mo.VirtualMachine 148 err := cli.references2Objects(host.Vm, SIMPLE_VM_PROPS, &vms) 149 if err != nil { 150 return nInfo, errors.Wrap(err, "references2Objects") 151 } 152 for i := range vms { 153 vm := vms[i] 154 if vm.Config == nil || vm.Config.Template { 155 continue 156 } 157 if vm.Guest == nil { 158 continue 159 } 160 macVlanMap, err := cli.macVlanMap(host, &vm, vpgMap) 161 if err != nil { 162 return nInfo, errors.Wrap(err, "macVlanMap") 163 } 164 guestIps := make([]SIPVlan, 0) 165 for _, net := range vm.Guest.Net { 166 if len(net.Network) == 0 { 167 continue 168 } 169 mac := net.MacAddress 170 for _, ip := range net.IpAddress { 171 if !regutils.MatchIP4Addr(ip) { 172 continue 173 } 174 if !vmIPV4Filter.Contains(ip) { 175 continue 176 } 177 ipaddr, _ := netutils.NewIPV4Addr(ip) 178 if netutils.IsLinkLocal(ipaddr) { 179 continue 180 } 181 proc := macVlanMap[mac] 182 guestIps = append(guestIps, SIPVlan{ 183 IP: ipaddr, 184 VlanId: proc.VlanId, 185 }) 186 nInfo.Insert(proc, ipaddr) 187 break 188 } 189 } 190 nInfo.AppendVMs(vm.Name, guestIps) 191 } 192 return nInfo, nil 193 }