@@ -7,6 +7,10 @@ package network
77import (
88 "context"
99 "fmt"
10+ "sync"
11+ "time"
12+
13+ ctrl "sigs.k8s.io/controller-runtime"
1014
1115 "github.com/vmware/govmomi/object"
1216 "github.com/vmware/govmomi/property"
@@ -55,15 +59,60 @@ func (n nsxOpaqueBacking) Summary(_ context.Context) (*vimtypes.OpaqueNetworkSum
5559 }, nil
5660}
5761
58- // searchNsxtNetworkReference takes in NSX-T LogicalSwitchUUID and returns the reference of the network.
62+ var (
63+ // uuidToDVPGCache contains the cache used look up the CCR's DPVG for a
64+ // given LogicalSwitchUUID.
65+ uuidToDVPGCache sync.Map
66+
67+ clearUUIDToDVPGCache sync.Once
68+ )
69+
5970func searchNsxtNetworkReference (
6071 ctx context.Context ,
6172 ccr * object.ClusterComputeResource ,
6273 networkID string ) (object.NetworkReference , error ) {
6374
64- // This is more or less how the old code did it. We could save repeated work by moving this
65- // into the callers since it will always be for the same CCR, but the common case is one NIC,
66- // or at most a handful, so that's for later.
75+ clearUUIDToDVPGCache .Do (func () {
76+ // Start goroutine to periodically clear the cache.
77+ go func () {
78+ logger := ctrl .Log .WithName ("nsx-dvpg-cache-clearer" )
79+ ticker := time .NewTicker (time .Minute * 60 )
80+ for range ticker .C {
81+ logger .Info ("Clearing NSX LogicalSwitchUUID to DVPG cache" )
82+ uuidToDVPGCache .Clear ()
83+ }
84+ }()
85+ })
86+
87+ key := ccr .Reference ().Value
88+
89+ if c , ok := uuidToDVPGCache .Load (key ); ok {
90+ cc := c .(map [string ]vimtypes.ManagedObjectReference )
91+ if dvpg , ok := cc [networkID ]; ok {
92+ return object .NewDistributedVirtualPortgroup (ccr .Client (), dvpg ), nil
93+ }
94+ }
95+
96+ // On either miss - CCR or UUID not found - try to refresh the DVPGs for the CCR,
97+ // and always store the latest results in the cache. We could CompareAndSwap()
98+ // instead but let's have the latest win.
99+ uuidsToDPVG , err := getDVPGsForCCR (ctx , ccr )
100+ if err != nil {
101+ return nil , err
102+ }
103+ uuidToDVPGCache .Store (key , uuidsToDPVG )
104+
105+ if dvpg , ok := uuidsToDPVG [networkID ]; ok {
106+ return object .NewDistributedVirtualPortgroup (ccr .Client (), dvpg ), nil
107+ }
108+
109+ return nil , fmt .Errorf ("no DVPG with NSX network ID %q found" , networkID )
110+ }
111+
112+ func getDVPGsForCCR (
113+ ctx context.Context ,
114+ ccr * object.ClusterComputeResource ) (map [string ]vimtypes.ManagedObjectReference , error ) {
115+
67116 var obj mo.ClusterComputeResource
68117 if err := ccr .Properties (ctx , ccr .Reference (), []string {"network" }, & obj ); err != nil {
69118 return nil , err
@@ -77,7 +126,7 @@ func searchNsxtNetworkReference(
77126 }
78127
79128 if len (dvpgsMoRefs ) == 0 {
80- return nil , fmt . Errorf ( "ClusterComputeResource %s has no DVPGs" , ccr . Reference (). Value )
129+ return nil , nil
81130 }
82131
83132 var dvpgs []mo.DistributedVirtualPortgroup
@@ -86,21 +135,12 @@ func searchNsxtNetworkReference(
86135 return nil , err
87136 }
88137
89- var dvpgMoRefs [ ]vimtypes.ManagedObjectReference
138+ uuidToDPVG := make ( map [ string ]vimtypes.ManagedObjectReference , len ( dvpgs ))
90139 for _ , dvpg := range dvpgs {
91- if dvpg .Config .LogicalSwitchUuid == networkID {
92- dvpgMoRefs = append ( dvpgMoRefs , dvpg .Reference () )
140+ if uuid := dvpg .Config .LogicalSwitchUuid ; uuid != "" {
141+ uuidToDPVG [ uuid ] = dvpg .Reference ()
93142 }
94143 }
95144
96- switch len (dvpgMoRefs ) {
97- case 1 :
98- return object .NewDistributedVirtualPortgroup (ccr .Client (), dvpgMoRefs [0 ]), nil
99- case 0 :
100- return nil , fmt .Errorf ("no DVPG with NSX network ID %q found" , networkID )
101- default :
102- // The LogicalSwitchUuid is supposed to be unique per CCR, so this is likely an NCP
103- // misconfiguration, and we don't know which one to pick.
104- return nil , fmt .Errorf ("multiple DVPGs (%d) with NSX network ID %q found" , len (dvpgMoRefs ), networkID )
105- }
145+ return uuidToDPVG , nil
106146}
0 commit comments