github.com/vmware/govmomi@v0.51.0/simulator/dvs.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package simulator 6 7 import ( 8 "fmt" 9 "strconv" 10 "strings" 11 12 "github.com/google/uuid" 13 14 "github.com/vmware/govmomi/vim25/methods" 15 "github.com/vmware/govmomi/vim25/mo" 16 "github.com/vmware/govmomi/vim25/soap" 17 "github.com/vmware/govmomi/vim25/types" 18 ) 19 20 type DistributedVirtualSwitch struct { 21 mo.DistributedVirtualSwitch 22 23 types.FetchDVPortsResponse 24 } 25 26 func (s *DistributedVirtualSwitch) eventArgument() *types.DvsEventArgument { 27 return &types.DvsEventArgument{ 28 EntityEventArgument: types.EntityEventArgument{ 29 Name: s.Name, 30 }, 31 Dvs: s.Self, 32 } 33 } 34 35 func (s *DistributedVirtualSwitch) event(ctx *Context) types.DvsEvent { 36 return types.DvsEvent{ 37 Event: types.Event{ 38 Datacenter: datacenterEventArgument(ctx, s), 39 Dvs: s.eventArgument(), 40 }, 41 } 42 } 43 44 func (s *DistributedVirtualSwitch) AddDVPortgroupTask(ctx *Context, c *types.AddDVPortgroup_Task) soap.HasFault { 45 task := CreateTask(s, "addDVPortgroup", func(t *Task) (types.AnyType, types.BaseMethodFault) { 46 f := ctx.Map.getEntityParent(s, "Folder").(*Folder) 47 48 portgroups := s.Portgroup 49 portgroupNames := s.Summary.PortgroupName 50 51 for _, spec := range c.Spec { 52 pg := &DistributedVirtualPortgroup{} 53 pg.Name = spec.Name 54 pg.Entity().Name = pg.Name 55 56 // Standard AddDVPortgroupTask() doesn't allow duplicate names, but NSX 3.0 does create some DVPGs with the same name. 57 // Allow duplicate names using this prefix so we can reproduce and test this condition. 58 if strings.HasPrefix(pg.Name, "NSX-") || spec.BackingType == string(types.DistributedVirtualPortgroupBackingTypeNsx) { 59 if spec.LogicalSwitchUuid == "" { 60 spec.LogicalSwitchUuid = uuid.New().String() 61 } 62 if spec.SegmentId == "" { 63 spec.SegmentId = fmt.Sprintf("/infra/segments/vnet_%s", uuid.New().String()) 64 } 65 66 } else { 67 if obj := ctx.Map.FindByName(pg.Name, f.ChildEntity); obj != nil { 68 return nil, &types.DuplicateName{ 69 Name: pg.Name, 70 Object: obj.Reference(), 71 } 72 } 73 } 74 75 folderPutChild(ctx, &f.Folder, pg) 76 77 pg.Key = pg.Self.Value 78 pg.Config = types.DVPortgroupConfigInfo{ 79 Key: pg.Key, 80 Name: pg.Name, 81 NumPorts: spec.NumPorts, 82 DistributedVirtualSwitch: &s.Self, 83 DefaultPortConfig: spec.DefaultPortConfig, 84 Description: spec.Description, 85 Type: spec.Type, 86 Policy: spec.Policy, 87 PortNameFormat: spec.PortNameFormat, 88 Scope: spec.Scope, 89 VendorSpecificConfig: spec.VendorSpecificConfig, 90 ConfigVersion: spec.ConfigVersion, 91 AutoExpand: spec.AutoExpand, 92 VmVnicNetworkResourcePoolKey: spec.VmVnicNetworkResourcePoolKey, 93 LogicalSwitchUuid: spec.LogicalSwitchUuid, 94 SegmentId: spec.SegmentId, 95 BackingType: spec.BackingType, 96 } 97 98 if pg.Config.LogicalSwitchUuid != "" { 99 if pg.Config.BackingType == "" { 100 pg.Config.BackingType = "nsx" 101 } 102 } 103 104 if pg.Config.DefaultPortConfig == nil { 105 pg.Config.DefaultPortConfig = &types.VMwareDVSPortSetting{ 106 Vlan: new(types.VmwareDistributedVirtualSwitchVlanIdSpec), 107 UplinkTeamingPolicy: &types.VmwareUplinkPortTeamingPolicy{ 108 Policy: &types.StringPolicy{ 109 Value: "loadbalance_srcid", 110 }, 111 ReversePolicy: &types.BoolPolicy{ 112 Value: types.NewBool(true), 113 }, 114 NotifySwitches: &types.BoolPolicy{ 115 Value: types.NewBool(true), 116 }, 117 RollingOrder: &types.BoolPolicy{ 118 Value: types.NewBool(true), 119 }, 120 }, 121 } 122 } 123 124 if pg.Config.Policy == nil { 125 pg.Config.Policy = &types.VMwareDVSPortgroupPolicy{ 126 DVPortgroupPolicy: types.DVPortgroupPolicy{ 127 BlockOverrideAllowed: true, 128 ShapingOverrideAllowed: false, 129 VendorConfigOverrideAllowed: false, 130 LivePortMovingAllowed: false, 131 PortConfigResetAtDisconnect: true, 132 NetworkResourcePoolOverrideAllowed: types.NewBool(false), 133 TrafficFilterOverrideAllowed: types.NewBool(false), 134 }, 135 VlanOverrideAllowed: false, 136 UplinkTeamingOverrideAllowed: false, 137 SecurityPolicyOverrideAllowed: false, 138 IpfixOverrideAllowed: types.NewBool(false), 139 } 140 } 141 142 for i := 0; i < int(spec.NumPorts); i++ { 143 pg.PortKeys = append(pg.PortKeys, strconv.Itoa(i)) 144 } 145 146 portgroups = append(portgroups, pg.Self) 147 portgroupNames = append(portgroupNames, pg.Name) 148 149 for _, h := range s.Summary.HostMember { 150 pg.Host = append(pg.Host, h) 151 152 host := ctx.Map.Get(h).(*HostSystem) 153 ctx.Map.AppendReference(ctx, host, &host.Network, pg.Reference()) 154 155 parent := ctx.Map.Get(*host.HostSystem.Parent) 156 computeNetworks := append(hostParent(ctx, &host.HostSystem).Network, pg.Reference()) 157 ctx.Update(parent, []types.PropertyChange{ 158 {Name: "network", Val: computeNetworks}, 159 }) 160 } 161 162 ctx.postEvent(&types.DVPortgroupCreatedEvent{ 163 DVPortgroupEvent: pg.event(ctx), 164 }) 165 } 166 167 ctx.Update(s, []types.PropertyChange{ 168 {Name: "portgroup", Val: portgroups}, 169 {Name: "summary.portgroupName", Val: portgroupNames}, 170 }) 171 172 return nil, nil 173 }) 174 175 return &methods.AddDVPortgroup_TaskBody{ 176 Res: &types.AddDVPortgroup_TaskResponse{ 177 Returnval: task.Run(ctx), 178 }, 179 } 180 } 181 182 func (s *DistributedVirtualSwitch) ReconfigureDvsTask(ctx *Context, req *types.ReconfigureDvs_Task) soap.HasFault { 183 task := CreateTask(s, "reconfigureDvs", func(t *Task) (types.AnyType, types.BaseMethodFault) { 184 spec := req.Spec.GetDVSConfigSpec() 185 186 members := s.Summary.HostMember 187 188 for _, member := range spec.Host { 189 h := ctx.Map.Get(member.Host) 190 if h == nil { 191 return nil, &types.ManagedObjectNotFound{Obj: member.Host} 192 } 193 194 host := h.(*HostSystem) 195 196 switch types.ConfigSpecOperation(member.Operation) { 197 case types.ConfigSpecOperationAdd: 198 if FindReference(s.Summary.HostMember, member.Host) != nil { 199 return nil, &types.AlreadyExists{Name: host.Name} 200 } 201 202 hostNetworks := append(host.Network, s.Portgroup...) 203 ctx.Update(host, []types.PropertyChange{ 204 {Name: "network", Val: hostNetworks}, 205 }) 206 members = append(members, member.Host) 207 parent := ctx.Map.Get(*host.HostSystem.Parent) 208 209 var pgs []types.ManagedObjectReference 210 for _, ref := range s.Portgroup { 211 pg := ctx.Map.Get(ref).(*DistributedVirtualPortgroup) 212 pgs = append(pgs, ref) 213 214 pgHosts := append(pg.Host, member.Host) 215 ctx.Update(pg, []types.PropertyChange{ 216 {Name: "host", Val: pgHosts}, 217 }) 218 219 cr := hostParent(ctx, &host.HostSystem) 220 if FindReference(cr.Network, ref) == nil { 221 computeNetworks := append(cr.Network, ref) 222 ctx.Update(parent, []types.PropertyChange{ 223 {Name: "network", Val: computeNetworks}, 224 }) 225 } 226 } 227 228 ctx.postEvent(&types.DvsHostJoinedEvent{ 229 DvsEvent: s.event(ctx), 230 HostJoined: *host.eventArgument(), 231 }) 232 case types.ConfigSpecOperationRemove: 233 for _, ref := range host.Vm { 234 vm := ctx.Map.Get(ref).(*VirtualMachine) 235 if pg := FindReference(vm.Network, s.Portgroup...); pg != nil { 236 return nil, &types.ResourceInUse{ 237 Type: pg.Type, 238 Name: pg.Value, 239 } 240 } 241 } 242 243 RemoveReference(&members, member.Host) 244 245 ctx.postEvent(&types.DvsHostLeftEvent{ 246 DvsEvent: s.event(ctx), 247 HostLeft: *host.eventArgument(), 248 }) 249 case types.ConfigSpecOperationEdit: 250 return nil, &types.NotSupported{} 251 } 252 } 253 254 ctx.Update(s, []types.PropertyChange{ 255 {Name: "summary.hostMember", Val: members}, 256 }) 257 258 ctx.postEvent(&types.DvsReconfiguredEvent{ 259 DvsEvent: s.event(ctx), 260 ConfigSpec: spec, 261 }) 262 263 return nil, nil 264 }) 265 266 return &methods.ReconfigureDvs_TaskBody{ 267 Res: &types.ReconfigureDvs_TaskResponse{ 268 Returnval: task.Run(ctx), 269 }, 270 } 271 } 272 273 func (s *DistributedVirtualSwitch) FetchDVPorts(ctx *Context, req *types.FetchDVPorts) soap.HasFault { 274 body := &methods.FetchDVPortsBody{} 275 body.Res = &types.FetchDVPortsResponse{ 276 Returnval: s.dvPortgroups(ctx, req.Criteria), 277 } 278 return body 279 } 280 281 func (s *DistributedVirtualSwitch) DestroyTask(ctx *Context, req *types.Destroy_Task) soap.HasFault { 282 task := CreateTask(s, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) { 283 // TODO: should return ResourceInUse fault if any VM is using a port on this switch 284 // and past that, remove refs from each host.Network, etc 285 f := ctx.Map.getEntityParent(s, "Folder").(*Folder) 286 folderRemoveChild(ctx, &f.Folder, s.Reference()) 287 ctx.postEvent(&types.DvsDestroyedEvent{DvsEvent: s.event(ctx)}) 288 return nil, nil 289 }) 290 291 return &methods.Destroy_TaskBody{ 292 Res: &types.Destroy_TaskResponse{ 293 Returnval: task.Run(ctx), 294 }, 295 } 296 } 297 298 func (s *DistributedVirtualSwitch) dvPortgroups(ctx *Context, criteria *types.DistributedVirtualSwitchPortCriteria) []types.DistributedVirtualPort { 299 res := s.FetchDVPortsResponse.Returnval 300 if len(res) != 0 { 301 return res 302 } 303 304 for _, ref := range s.Portgroup { 305 pg := ctx.Map.Get(ref).(*DistributedVirtualPortgroup) 306 307 for _, key := range pg.PortKeys { 308 res = append(res, types.DistributedVirtualPort{ 309 DvsUuid: s.Uuid, 310 Key: key, 311 PortgroupKey: pg.Key, 312 Config: types.DVPortConfigInfo{ 313 Setting: pg.Config.DefaultPortConfig, 314 }, 315 }) 316 } 317 } 318 319 // filter ports by criteria 320 res = s.filterDVPorts(res, criteria) 321 322 return res 323 } 324 325 func (s *DistributedVirtualSwitch) filterDVPorts( 326 ports []types.DistributedVirtualPort, 327 criteria *types.DistributedVirtualSwitchPortCriteria, 328 ) []types.DistributedVirtualPort { 329 if criteria == nil { 330 return ports 331 } 332 333 ports = s.filterDVPortsByPortgroupKey(ports, criteria) 334 ports = s.filterDVPortsByPortKey(ports, criteria) 335 ports = s.filterDVPortsByConnected(ports, criteria) 336 337 return ports 338 } 339 340 func (s *DistributedVirtualSwitch) filterDVPortsByPortgroupKey( 341 ports []types.DistributedVirtualPort, 342 criteria *types.DistributedVirtualSwitchPortCriteria, 343 ) []types.DistributedVirtualPort { 344 if len(criteria.PortgroupKey) == 0 || criteria.Inside == nil { 345 return ports 346 } 347 348 // inside portgroup keys 349 if *criteria.Inside { 350 filtered := []types.DistributedVirtualPort{} 351 352 for _, p := range ports { 353 for _, pgk := range criteria.PortgroupKey { 354 if p.PortgroupKey == pgk { 355 filtered = append(filtered, p) 356 break 357 } 358 } 359 } 360 return filtered 361 } 362 363 // outside portgroup keys 364 filtered := []types.DistributedVirtualPort{} 365 366 for _, p := range ports { 367 found := false 368 for _, pgk := range criteria.PortgroupKey { 369 if p.PortgroupKey == pgk { 370 found = true 371 break 372 } 373 } 374 375 if !found { 376 filtered = append(filtered, p) 377 } 378 } 379 return filtered 380 } 381 382 func (s *DistributedVirtualSwitch) filterDVPortsByPortKey( 383 ports []types.DistributedVirtualPort, 384 criteria *types.DistributedVirtualSwitchPortCriteria, 385 ) []types.DistributedVirtualPort { 386 if len(criteria.PortKey) == 0 { 387 return ports 388 } 389 390 filtered := []types.DistributedVirtualPort{} 391 392 for _, p := range ports { 393 for _, pk := range criteria.PortKey { 394 if p.Key == pk { 395 filtered = append(filtered, p) 396 break 397 } 398 } 399 } 400 401 return filtered 402 } 403 404 func (s *DistributedVirtualSwitch) filterDVPortsByConnected( 405 ports []types.DistributedVirtualPort, 406 criteria *types.DistributedVirtualSwitchPortCriteria, 407 ) []types.DistributedVirtualPort { 408 if criteria.Connected == nil { 409 return ports 410 } 411 412 filtered := []types.DistributedVirtualPort{} 413 414 for _, p := range ports { 415 connected := p.Connectee != nil 416 if connected == *criteria.Connected { 417 filtered = append(filtered, p) 418 } 419 } 420 421 return filtered 422 }