• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

noironetworks / aci-containers / 12058

10 Jul 2026 12:47PM UTC coverage: 64.017% (+0.05%) from 63.969%
12058

push

travis-pro

web-flow
Merge pull request #1745 from noironetworks/hpp-dir-fix-mmr

[mmr-6.1.1] Rework hpp direct mode for scale, restart safety and correctness

552 of 707 new or added lines in 11 files covered. (78.08%)

56 existing lines in 2 files now uncovered.

13745 of 21471 relevant lines covered (64.02%)

0.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.34
/pkg/controller/controller.go
1
// Copyright 2017 Cisco Systems, Inc.
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 controller
16

17
import (
18
        "encoding/json"
19
        "fmt"
20
        "net"
21
        "os"
22
        "reflect"
23
        "strconv"
24
        "strings"
25
        "sync"
26
        "sync/atomic"
27
        "time"
28

29
        "github.com/sirupsen/logrus"
30
        "github.com/yl2chen/cidranger"
31
        "golang.org/x/time/rate"
32

33
        v1 "k8s.io/api/core/v1"
34
        discovery "k8s.io/api/discovery/v1"
35
        v1net "k8s.io/api/networking/v1"
36
        "k8s.io/apimachinery/pkg/labels"
37
        "k8s.io/apimachinery/pkg/util/wait"
38
        "k8s.io/client-go/kubernetes"
39
        "k8s.io/client-go/tools/cache"
40
        "k8s.io/client-go/util/workqueue"
41

42
        "github.com/noironetworks/aci-containers/pkg/apicapi"
43
        fabattv1 "github.com/noironetworks/aci-containers/pkg/fabricattachment/apis/aci.fabricattachment/v1"
44
        fabattclset "github.com/noironetworks/aci-containers/pkg/fabricattachment/clientset/versioned"
45
        hppv1 "github.com/noironetworks/aci-containers/pkg/hpp/apis/aci.hpp/v1"
46
        "github.com/noironetworks/aci-containers/pkg/index"
47
        "github.com/noironetworks/aci-containers/pkg/ipam"
48
        istiov1 "github.com/noironetworks/aci-containers/pkg/istiocrd/apis/aci.istio/v1"
49
        "github.com/noironetworks/aci-containers/pkg/metadata"
50
        nodeinfo "github.com/noironetworks/aci-containers/pkg/nodeinfo/apis/aci.snat/v1"
51
        rdConfig "github.com/noironetworks/aci-containers/pkg/rdconfig/apis/aci.snat/v1"
52
        snatglobalinfo "github.com/noironetworks/aci-containers/pkg/snatglobalinfo/apis/aci.snat/v1"
53
        "github.com/noironetworks/aci-containers/pkg/util"
54
)
55

56
type podUpdateFunc func(*v1.Pod) (*v1.Pod, error)
57
type nodeUpdateFunc func(*v1.Node) (*v1.Node, error)
58
type serviceUpdateFunc func(*v1.Service) (*v1.Service, error)
59
type listNetworkPoliciesFunc func(string) (*v1net.NetworkPolicyList, error)
60
type listNamespacesFunc func() (*v1.NamespaceList, error)
61

62
type AciController struct {
63
        log    *logrus.Logger
64
        config *ControllerConfig
65
        env    Environment
66

67
        defaultEg string
68
        defaultSg string
69

70
        unitTestMode bool
71

72
        podQueue               workqueue.RateLimitingInterface
73
        netPolQueue            workqueue.RateLimitingInterface
74
        qosQueue               workqueue.RateLimitingInterface
75
        serviceQueue           workqueue.RateLimitingInterface
76
        snatQueue              workqueue.RateLimitingInterface
77
        netflowQueue           workqueue.RateLimitingInterface
78
        erspanQueue            workqueue.RateLimitingInterface
79
        snatNodeInfoQueue      workqueue.RateLimitingInterface
80
        rdConfigQueue          workqueue.RateLimitingInterface
81
        istioQueue             workqueue.RateLimitingInterface
82
        nodeFabNetAttQueue     workqueue.RateLimitingInterface
83
        netFabConfigQueue      workqueue.RateLimitingInterface
84
        nadVlanMapQueue        workqueue.RateLimitingInterface
85
        fabricVlanPoolQueue    workqueue.RateLimitingInterface
86
        netFabL3ConfigQueue    workqueue.RateLimitingInterface
87
        remIpContQueue         workqueue.RateLimitingInterface
88
        hppQueue               workqueue.RateLimitingInterface
89
        epgDnCacheUpdateQueue  workqueue.RateLimitingInterface
90
        aaepMonitorConfigQueue workqueue.RateLimitingInterface
91

92
        namespaceIndexer                     cache.Indexer
93
        namespaceInformer                    cache.Controller
94
        podIndexer                           cache.Indexer
95
        podInformer                          cache.Controller
96
        serviceIndexer                       cache.Indexer
97
        serviceInformer                      cache.Controller
98
        replicaSetIndexer                    cache.Indexer
99
        replicaSetInformer                   cache.Controller
100
        deploymentIndexer                    cache.Indexer
101
        deploymentInformer                   cache.Controller
102
        nodeIndexer                          cache.Indexer
103
        nodeInformer                         cache.Controller
104
        networkPolicyIndexer                 cache.Indexer
105
        networkPolicyInformer                cache.Controller
106
        snatIndexer                          cache.Indexer
107
        snatInformer                         cache.Controller
108
        snatNodeInfoIndexer                  cache.Indexer
109
        snatNodeInformer                     cache.Controller
110
        snatLocalInfoInformer                cache.Controller
111
        crdInformer                          cache.Controller
112
        rdConfigInformer                     cache.Controller
113
        rdConfigIndexer                      cache.Indexer
114
        qosIndexer                           cache.Indexer
115
        qosInformer                          cache.Controller
116
        netflowIndexer                       cache.Indexer
117
        netflowInformer                      cache.Controller
118
        erspanIndexer                        cache.Indexer
119
        erspanInformer                       cache.Controller
120
        nodePodIfIndexer                     cache.Indexer
121
        nodePodIfInformer                    cache.Controller
122
        istioIndexer                         cache.Indexer
123
        istioInformer                        cache.Controller
124
        endpointSliceIndexer                 cache.Indexer
125
        endpointSliceInformer                cache.Controller
126
        snatCfgInformer                      cache.Controller
127
        updatePod                            podUpdateFunc
128
        updateNode                           nodeUpdateFunc
129
        updateServiceStatus                  serviceUpdateFunc
130
        listNetworkPolicies                  listNetworkPoliciesFunc
131
        listNamespaces                       listNamespacesFunc
132
        nodeFabNetAttInformer                cache.SharedIndexInformer
133
        netFabConfigInformer                 cache.SharedIndexInformer
134
        nadVlanMapInformer                   cache.SharedIndexInformer
135
        fabricVlanPoolInformer               cache.SharedIndexInformer
136
        networkFabricL3ConfigurationInformer cache.SharedIndexInformer
137
        fabNetAttClient                      *fabattclset.Clientset
138
        proactiveConfInformer                cache.SharedIndexInformer
139
        aaepMonitorInformer                  cache.SharedIndexInformer
140
        poster                               *EventPoster
141
        hppInformer                          cache.SharedIndexInformer
142
        hppRemoteIpInformer                  cache.SharedIndexInformer
143

144
        indexMutex sync.Mutex
145
        hppMutex   sync.Mutex
146

147
        configuredPodNetworkIps *netIps
148
        podNetworkIps           *netIps
149
        serviceIps              *ipam.IpCache
150
        staticServiceIps        *netIps
151
        nodeServiceIps          *netIps
152

153
        // index of pods matched by deployments
154
        depPods *index.PodSelectorIndex
155
        // index of pods matched by network policies
156
        netPolPods *index.PodSelectorIndex
157
        // index of pods matched by network policy ingress rules
158
        netPolIngressPods *index.PodSelectorIndex
159
        // index of pods matched by network policy egress rules
160
        netPolEgressPods *index.PodSelectorIndex
161
        // index of IP addresses contained in endpoints objects
162
        endpointsIpIndex cidranger.Ranger
163
        // index of service target ports
164
        targetPortIndex map[string]*portIndexEntry
165
        // index of services with named target ports
166
        namedPortServiceIndex map[string]*namedPortServiceIndexEntry
167
        // index of ip blocks referenced by network policy egress rules
168
        netPolSubnetIndex cidranger.Ranger
169
        // index of pods matched by erspan policies
170
        erspanPolPods *index.PodSelectorIndex
171

172
        apicConn *apicapi.ApicConnection
173

174
        nodeServiceMetaCache map[string]*nodeServiceMeta
175
        nodeACIPod           map[string]aciPodAnnot
176
        nodeACIPodAnnot      map[string]aciPodAnnot
177
        nodeOpflexDevice     map[string]apicapi.ApicSlice
178
        nodePodNetCache      map[string]*nodePodNetMeta
179
        serviceMetaCache     map[string]*serviceMeta
180
        snatPolicyCache      map[string]*ContSnatPolicy
181
        delayedEpSlices      []*DelayedEpSlice
182
        snatServices         map[string]bool
183
        snatNodeInfoCache    map[string]*nodeinfo.NodeInfo
184
        rdConfigCache        map[string]*rdConfig.RdConfig
185
        rdConfigSubnetCache  map[string]*rdConfig.RdConfigSpec
186
        istioCache           map[string]*istiov1.AciIstioOperator
187
        podIftoEp            map[string]*EndPointData
188
        // Node Name and Policy Name
189
        snatGlobalInfoCache map[string]map[string]*snatglobalinfo.GlobalInfo
190
        nodeSyncEnabled     bool
191
        serviceSyncEnabled  bool
192
        snatSyncEnabled     bool
193
        hppSyncEnabled      atomic.Bool
194
        syncQueue           workqueue.RateLimitingInterface
195
        syncProcessors      map[string]func() bool
196
        serviceEndPoints    ServiceEndPointType
197
        crdHandlers         map[string]func(*AciController, <-chan struct{})
198
        stopCh              <-chan struct{}
199
        //index of containerportname to ctrPortNameEntry
200
        ctrPortNameCache map[string]*ctrPortNameEntry
201
        // named networkPolicies
202
        nmPortNp map[string]bool
203
        //maps network policy hash to hpp (HPP-optimization, APIC path)
204
        hppOptRef map[string]hppOptReference
205
        //maps network policy hash to hpp CR (HPP-Direct path)
206
        hppDirRef map[string]hppDirReference
207
        // remoteIpCache maps RIC name (peer-selector hash) to sorted resolved IPs
208
        remoteIpCache map[string][]string
209
        // ricRefCount maps RIC name to the set of hppNames that reference it
210
        ricRefCount map[string]map[string]bool
211
        // cache to look for Epg DNs which are bound to Vmm domain
212
        cachedEpgDns             []string
213
        vmmClusterFaultSupported bool
214
        additionalNetworkCache   map[string]*AdditionalNetworkMeta
215
        //Used in Shared mode
216
        sharedEncapCache       map[int]*sharedEncapData
217
        sharedEncapAepCache    map[string]map[int]bool
218
        sharedEncapSviCache    map[int]*NfL3Data
219
        sharedEncapVrfCache    map[string]*NfVrfData
220
        sharedEncapTenantCache map[string]*NfTenantData
221
        nfl3configGenerationId int64
222
        // vlan to propertiesList
223
        sharedEncapNfcCache         map[int]*NfcData
224
        sharedEncapNfcVlanMap       map[int]*NfcData
225
        sharedEncapNfcLabelMap      map[string]*NfcData
226
        sharedEncapNfcAppProfileMap map[string]bool
227
        // nadVlanMap encapLabel to vlan
228
        sharedEncapLabelMap      map[string][]int
229
        lldpIfCache              map[string]*NfLLDPIfData
230
        globalVlanConfig         globalVlanConfig
231
        fabricVlanPoolMap        map[string]map[string]string
232
        openStackFabricPathDnMap map[string]openstackOpflexOdevInfo
233
        hostFabricPathDnMap      map[string]hostFabricInfo
234
        openStackSystemId        string
235
        sharedAaepMonitor        map[string]map[string]*AaepEpgAttachData
236
}
237

238
type hostFabricInfo struct {
239
        fabricPathDn string
240
        host         string
241
        vpcIfDn      map[string]struct{}
242
}
243

244
type NfLLDPIfData struct {
245
        LLDPIf string
246
        // As of now, manage at the NAD level
247
        // more granular introduces intf tracking complexities
248
        // for not sufficient benefits
249
        Refs map[string]bool
250
}
251

252
type NfL3OutData struct {
253
        // +kubebuilder:validation:Enum:"import"
254
        RtCtrl     string
255
        PodId      int
256
        RtrNodeMap map[int]*fabattv1.FabricL3OutRtrNode
257
        ExtEpgMap  map[string]*fabattv1.PolicyPrefixGroup
258
        SviMap     map[int]bool
259
}
260

261
type NfTenantData struct {
262
        CommonTenant     bool
263
        L3OutConfig      map[string]*NfL3OutData
264
        BGPPeerPfxConfig map[string]*fabattv1.BGPPeerPrefixPolicy
265
}
266

267
type NfVrfData struct {
268
        TenantConfig map[string]*NfTenantData
269
}
270

271
type NfL3Networks struct {
272
        fabattv1.PrimaryNetwork
273
        Subnets map[string]*fabattv1.FabricL3Subnet
274
}
275

276
type NfL3Data struct {
277
        Tenant      string
278
        Vrf         fabattv1.VRF
279
        PodId       int
280
        ConnectedNw *NfL3Networks
281
        NetAddr     map[string]*RoutedNetworkData
282
        Nodes       map[int]fabattv1.FabricL3OutNode
283
}
284

285
type NfcData struct {
286
        Aeps map[string]bool
287
        Epg  fabattv1.Epg
288
}
289

290
type sharedEncapData struct {
291
        //node to NAD to pods
292
        Pods   map[string]map[string][]string
293
        NetRef map[string]*AdditionalNetworkMeta
294
        Aeps   map[string]bool
295
}
296

297
type globalVlanConfig struct {
298
        SharedPhysDom apicapi.ApicObject
299
        SharedL3Dom   apicapi.ApicObject
300
}
301

302
// hppOptReference is the HPP-optimization (APIC) mode cache entry.
303
// Keyed by aciNameForKey("np", CreateHashFromNetPol(np)).
304
type hppOptReference struct {
305
        RefCount       uint                       `json:"ref-count,omitempty"`
306
        Npkeys         []string                   `json:"npkeys,omitempty"`
307
        HppObj         apicapi.ApicSlice          `json:"hpp-obj,omitempty"`
308
        NpIngressRules map[string]map[string]bool `json:"-"` // npKey → set of ingress rule names
309
}
310

311
// hppDirReference is the HPP-Direct (CR) mode cache entry.
312
// Keyed by aciNameForKey("np", CreateCanonicalHashFromNetPol(np)).
313
type hppDirReference struct {
314
        RefCount       uint                       `json:"ref-count,omitempty"`
315
        Npkeys         []string                   `json:"npkeys,omitempty"`
316
        HppCr          hppv1.HostprotPol          `json:"hpp-cr,omitempty"`
317
        NpIngressRules map[string]map[string]bool `json:"-"` // npKey → set of ingress rule names
318
        RicNames       map[string]bool            `json:"-"` // set of RIC names referenced by rules
319
}
320

321
type DelayedEpSlice struct {
322
        ServiceKey  string
323
        OldEpSlice  *discovery.EndpointSlice
324
        NewEpSlice  *discovery.EndpointSlice
325
        DelayedTime time.Time
326
}
327

328
type aciPodAnnot struct {
329
        aciPod         string
330
        disconnectTime time.Time
331
        lastErrorTime  time.Time
332
}
333

334
type nodeServiceMeta struct {
335
        serviceEp metadata.ServiceEndpoint
336
}
337

338
type nodePodNetMeta struct {
339
        nodePods            map[string]bool
340
        podNetIps           metadata.NetIps
341
        podNetIpsAnnotation string
342
}
343

344
type openstackOpflexOdevInfo struct {
345
        opflexODevDn map[string]struct{}
346
        fabricPathDn string
347
}
348

349
type serviceMeta struct {
350
        requestedIps     []net.IP
351
        ingressIps       []net.IP
352
        staticIngressIps []net.IP
353
}
354

355
type ipIndexEntry struct {
356
        ipNet net.IPNet
357
        keys  map[string]bool
358
}
359

360
type targetPort struct {
361
        proto v1.Protocol
362
        // portServiceMap maps a resolved numeric port number to the set of
363
        // service keys whose endpoints resolve the named port to that number.
364
        // eg.: {80: {"default/svc1": true, "default/svc2": true}, 8080: {"default/svc3": true}}
365
        portServiceMap map[int]map[string]bool
366
}
367

368
// portIndexEntry is an entry in the targetPortIndex, keyed by a port
369
// specification string (e.g. "tcp-name-http" or "tcp-num-80"). It tracks
370
// which services have resolved endpoints to specific numeric ports for
371
// this port spec, and which network policies reference it.
372
type portIndexEntry struct {
373
        portMapping       targetPort
374
        networkPolicyKeys map[string]bool
375
}
376

377
// hasServiceKeys returns true if any per-port inner map contains
378
// at least one service key.
379
func (e *portIndexEntry) hasServiceKeys() bool {
1✔
380
        for _, svcKeys := range e.portMapping.portServiceMap {
2✔
381
                if len(svcKeys) > 0 {
2✔
382
                        return true
1✔
383
                }
1✔
384
        }
385
        return false
1✔
386
}
387

388
// removeServiceKey removes a service key from all per-port inner
389
// maps. If an inner map becomes empty it is set to nil so the port
390
// number itself is preserved (it may still be needed by NP tracking).
391
func (e *portIndexEntry) removeServiceKey(key string) {
1✔
392
        for p, svcKeys := range e.portMapping.portServiceMap {
2✔
393
                if svcKeys != nil {
2✔
394
                        delete(svcKeys, key)
1✔
395
                        if len(svcKeys) == 0 {
2✔
396
                                e.portMapping.portServiceMap[p] = nil
1✔
397
                        }
1✔
398
                }
399
        }
400
}
401

402
type namedPortServiceIndexPort struct {
403
        targetPortName string
404
        resolvedPorts  map[int]bool
405
}
406

407
type namedPortServiceIndexEntry map[string]*namedPortServiceIndexPort
408

409
type portRangeSnat struct {
410
        start int
411
        end   int
412
}
413

414
// EndPointData holds PodIF data in controller.
415
type EndPointData struct {
416
        MacAddr    string
417
        EPG        string
418
        Namespace  string
419
        AppProfile string
420
}
421

422
type ctrPortNameEntry struct {
423
        // Proto+port->pods
424
        ctrNmpToPods map[string]map[string]bool
425
}
426

427
type LinkData struct {
428
        Link []string
429
        Pods []string
430
}
431

432
type RoutedNodeData struct {
433
        addr string
434
        idx  int
435
}
436

437
type RoutedNetworkData struct {
438
        subnet       string
439
        netAddress   string
440
        maskLen      int
441
        numAllocated int
442
        maxAddresses int
443
        baseAddress  net.IP
444
        nodeMap      map[string]RoutedNodeData
445
        availableMap map[int]bool
446
}
447

448
type AdditionalNetworkMeta struct {
449
        NetworkName string
450
        EncapVlan   string
451
        //node+localiface->fabricLinks
452
        FabricLink map[string]map[string]LinkData
453
        NodeCache  map[string]*fabattv1.NodeFabricNetworkAttachment
454
        Mode       util.EncapMode
455
}
456

457
type ServiceEndPointType interface {
458
        InitClientInformer(kubeClient *kubernetes.Clientset)
459
        Run(stopCh <-chan struct{})
460
        Wait(stopCh <-chan struct{})
461
        UpdateServicesForNode(nodename string)
462
        GetnodesMetadata(key string, service *v1.Service, nodeMap map[string]*metadata.ServiceEndpoint)
463
        SetServiceApicObject(aobj apicapi.ApicObject, service *v1.Service) bool
464
        SetNpServiceAugmentForService(servicekey string, service *v1.Service, prs *portRemoteSubnet,
465
                portAugments map[string]*portServiceAugment, subnetIndex cidranger.Ranger, logger *logrus.Entry)
466
}
467

468
type serviceEndpointSlice struct {
469
        cont *AciController
470
}
471

472
type AaepEpgAttachData struct {
473
        encapVlan     int
474
        nadName       string
475
        namespaceName string
476
        nadCreated    bool
477
}
478

479
type EpgVlanMap struct {
480
        epgDn     string
481
        encapVlan int
482
}
483

484
func (seps *serviceEndpointSlice) InitClientInformer(kubeClient *kubernetes.Clientset) {
×
485
        seps.cont.initEndpointSliceInformerFromClient(kubeClient)
×
486
}
×
487

488
func (seps *serviceEndpointSlice) Run(stopCh <-chan struct{}) {
1✔
489
        go seps.cont.endpointSliceInformer.Run(stopCh)
1✔
490
}
1✔
491

492
func (seps *serviceEndpointSlice) Wait(stopCh <-chan struct{}) {
1✔
493
        seps.cont.log.Debug("Waiting for EndPointSlicecache sync")
1✔
494
        cache.WaitForCacheSync(stopCh,
1✔
495
                seps.cont.endpointSliceInformer.HasSynced,
1✔
496
                seps.cont.serviceInformer.HasSynced)
1✔
497
}
1✔
498

499
func (e *ipIndexEntry) Network() net.IPNet {
1✔
500
        return e.ipNet
1✔
501
}
1✔
502

503
func newNodePodNetMeta() *nodePodNetMeta {
1✔
504
        return &nodePodNetMeta{
1✔
505
                nodePods: make(map[string]bool),
1✔
506
        }
1✔
507
}
1✔
508

509
func createQueue(name string) workqueue.RateLimitingInterface {
1✔
510
        return workqueue.NewNamedRateLimitingQueue(
1✔
511
                workqueue.NewMaxOfRateLimiter(
1✔
512
                        workqueue.NewItemExponentialFailureRateLimiter(5*time.Millisecond,
1✔
513
                                10*time.Second),
1✔
514
                        &workqueue.BucketRateLimiter{
1✔
515
                                Limiter: rate.NewLimiter(rate.Limit(10), int(100)),
1✔
516
                        },
1✔
517
                ),
1✔
518
                "delta")
1✔
519
}
1✔
520

521
func NewController(config *ControllerConfig, env Environment, log *logrus.Logger, unittestmode bool) *AciController {
1✔
522
        cont := &AciController{
1✔
523
                log:          log,
1✔
524
                config:       config,
1✔
525
                env:          env,
1✔
526
                defaultEg:    "",
1✔
527
                defaultSg:    "",
1✔
528
                unitTestMode: unittestmode,
1✔
529

1✔
530
                podQueue:               createQueue("pod"),
1✔
531
                netPolQueue:            createQueue("networkPolicy"),
1✔
532
                qosQueue:               createQueue("qos"),
1✔
533
                netflowQueue:           createQueue("netflow"),
1✔
534
                erspanQueue:            createQueue("erspan"),
1✔
535
                serviceQueue:           createQueue("service"),
1✔
536
                snatQueue:              createQueue("snat"),
1✔
537
                snatNodeInfoQueue:      createQueue("snatnodeinfo"),
1✔
538
                rdConfigQueue:          createQueue("rdconfig"),
1✔
539
                istioQueue:             createQueue("istio"),
1✔
540
                nodeFabNetAttQueue:     createQueue("nodefabricnetworkattachment"),
1✔
541
                netFabConfigQueue:      createQueue("networkfabricconfiguration"),
1✔
542
                nadVlanMapQueue:        createQueue("nadvlanmap"),
1✔
543
                fabricVlanPoolQueue:    createQueue("fabricvlanpool"),
1✔
544
                netFabL3ConfigQueue:    createQueue("networkfabricl3configuration"),
1✔
545
                remIpContQueue:         createQueue("remoteIpContainer"),
1✔
546
                hppQueue:               createQueue("hostprotPol"),
1✔
547
                epgDnCacheUpdateQueue:  createQueue("epgDnCache"),
1✔
548
                aaepMonitorConfigQueue: createQueue("aaepepgmap"),
1✔
549
                syncQueue: workqueue.NewNamedRateLimitingQueue(
1✔
550
                        &workqueue.BucketRateLimiter{
1✔
551
                                Limiter: rate.NewLimiter(rate.Limit(10), int(100)),
1✔
552
                        }, "sync"),
1✔
553

1✔
554
                configuredPodNetworkIps: newNetIps(),
1✔
555
                podNetworkIps:           newNetIps(),
1✔
556
                serviceIps:              ipam.NewIpCache(),
1✔
557
                staticServiceIps:        newNetIps(),
1✔
558
                nodeServiceIps:          newNetIps(),
1✔
559

1✔
560
                nodeACIPod:       make(map[string]aciPodAnnot),
1✔
561
                nodeACIPodAnnot:  make(map[string]aciPodAnnot),
1✔
562
                nodeOpflexDevice: make(map[string]apicapi.ApicSlice),
1✔
563

1✔
564
                nodeServiceMetaCache:        make(map[string]*nodeServiceMeta),
1✔
565
                nodePodNetCache:             make(map[string]*nodePodNetMeta),
1✔
566
                serviceMetaCache:            make(map[string]*serviceMeta),
1✔
567
                snatPolicyCache:             make(map[string]*ContSnatPolicy),
1✔
568
                snatServices:                make(map[string]bool),
1✔
569
                snatNodeInfoCache:           make(map[string]*nodeinfo.NodeInfo),
1✔
570
                rdConfigCache:               make(map[string]*rdConfig.RdConfig),
1✔
571
                rdConfigSubnetCache:         make(map[string]*rdConfig.RdConfigSpec),
1✔
572
                podIftoEp:                   make(map[string]*EndPointData),
1✔
573
                snatGlobalInfoCache:         make(map[string]map[string]*snatglobalinfo.GlobalInfo),
1✔
574
                istioCache:                  make(map[string]*istiov1.AciIstioOperator),
1✔
575
                crdHandlers:                 make(map[string]func(*AciController, <-chan struct{})),
1✔
576
                ctrPortNameCache:            make(map[string]*ctrPortNameEntry),
1✔
577
                nmPortNp:                    make(map[string]bool),
1✔
578
                additionalNetworkCache:      make(map[string]*AdditionalNetworkMeta),
1✔
579
                sharedEncapCache:            make(map[int]*sharedEncapData),
1✔
580
                sharedEncapAepCache:         make(map[string]map[int]bool),
1✔
581
                sharedEncapSviCache:         make(map[int]*NfL3Data),
1✔
582
                sharedEncapVrfCache:         make(map[string]*NfVrfData),
1✔
583
                sharedEncapTenantCache:      make(map[string]*NfTenantData),
1✔
584
                sharedEncapNfcCache:         make(map[int]*NfcData),
1✔
585
                sharedEncapNfcVlanMap:       make(map[int]*NfcData),
1✔
586
                sharedEncapNfcLabelMap:      make(map[string]*NfcData),
1✔
587
                sharedEncapNfcAppProfileMap: make(map[string]bool),
1✔
588
                sharedEncapLabelMap:         make(map[string][]int),
1✔
589
                lldpIfCache:                 make(map[string]*NfLLDPIfData),
1✔
590
                fabricVlanPoolMap:           make(map[string]map[string]string),
1✔
591
                openStackFabricPathDnMap:    make(map[string]openstackOpflexOdevInfo),
1✔
592
                hostFabricPathDnMap:         make(map[string]hostFabricInfo),
1✔
593
                remoteIpCache:               make(map[string][]string),
1✔
594
                sharedAaepMonitor:           make(map[string]map[string]*AaepEpgAttachData),
1✔
595
        }
1✔
596
        if config.HppOptimization {
2✔
597
                cont.hppOptRef = make(map[string]hppOptReference)
1✔
598
        }
1✔
599
        if config.EnableHppDirect {
2✔
600
                cont.hppDirRef = make(map[string]hppDirReference)
1✔
601
                cont.ricRefCount = make(map[string]map[string]bool)
1✔
602
        }
1✔
603
        cont.syncProcessors = map[string]func() bool{
1✔
604
                "snatGlobalInfo": cont.syncSnatGlobalInfo,
1✔
605
                "rdConfig":       cont.syncRdConfig,
1✔
606
                /* Commenting code to remove dependency from istio.io/istio package.
1✔
607
                   Vulnerabilties were detected by quay.io security scan of aci-containers-controller
1✔
608
                   and aci-containers-operator images for istio.io/istio package
1✔
609

1✔
610
                "istioCR":        cont.createIstioCR,
1✔
611
                */
1✔
612
        }
1✔
613
        return cont
1✔
614
}
615

616
func (cont *AciController) Init() {
×
617
        if cont.config.ChainedMode {
×
618
                cont.log.Info("In chained mode")
×
619
        }
×
620
        if cont.config.VmmLite {
×
621
                cont.log.Info("In VMM lite mode")
×
622
        }
×
623

624
        egdata, err := json.Marshal(cont.config.DefaultEg)
×
625
        if err != nil {
×
626
                cont.log.Error("Could not serialize default endpoint group")
×
627
                panic(err.Error())
×
628
        }
629
        cont.defaultEg = string(egdata)
×
630

×
631
        sgdata, err := json.Marshal(cont.config.DefaultSg)
×
632
        if err != nil {
×
633
                cont.log.Error("Could not serialize default security groups")
×
634
                panic(err.Error())
×
635
        }
636
        cont.defaultSg = string(sgdata)
×
637

×
638
        cont.log.Debug("Initializing IPAM")
×
639
        cont.initIpam()
×
640

×
641
        cont.serviceEndPoints = &serviceEndpointSlice{}
×
642
        cont.serviceEndPoints.(*serviceEndpointSlice).cont = cont
×
643
        cont.log.Info("Initializing ServiceEndpointSlices")
×
644

×
645
        err = cont.env.Init(cont)
×
646
        if err != nil {
×
647
                panic(err.Error())
×
648
        }
649
}
650

651
func (cont *AciController) processQueue(queue workqueue.RateLimitingInterface,
652
        store cache.Store, handler func(interface{}) bool,
653
        deleteHandler func(string) bool,
654
        postDelHandler func() bool, stopCh <-chan struct{}) {
1✔
655
        go wait.Until(func() {
2✔
656
                for {
2✔
657
                        key, quit := queue.Get()
1✔
658
                        if quit {
2✔
659
                                break
1✔
660
                        }
661

662
                        var requeue bool
1✔
663
                        switch key := key.(type) {
1✔
664
                        case chan struct{}:
1✔
665
                                close(key)
1✔
666
                        case string:
1✔
667
                                if strings.HasPrefix(key, "DELETED_") {
2✔
668
                                        delKey := strings.Trim(key, "DELETED_")
1✔
669
                                        requeue = deleteHandler(delKey)
1✔
670
                                } else {
2✔
671
                                        obj, exists, err := store.GetByKey(key)
1✔
672
                                        if err != nil {
1✔
673
                                                cont.log.Debugf("Error fetching object with key %s from store: %v", key, err)
×
674
                                        }
×
675
                                        //Handle Add/Update/Delete
676
                                        if exists && handler != nil {
2✔
677
                                                requeue = handler(obj)
1✔
678
                                        }
1✔
679
                                        //Handle Post Delete
680
                                        if !exists && postDelHandler != nil {
1✔
681
                                                requeue = postDelHandler()
×
682
                                        }
×
683
                                }
684
                        }
685
                        if requeue {
2✔
686
                                queue.AddRateLimited(key)
1✔
687
                        } else {
2✔
688
                                queue.Forget(key)
1✔
689
                        }
1✔
690
                        queue.Done(key)
1✔
691
                }
692
        }, time.Second, stopCh)
693
        <-stopCh
1✔
694
        queue.ShutDown()
1✔
695
}
696

697
func (cont *AciController) processReconcileQueue(queue workqueue.RateLimitingInterface,
698
        handler func(string) bool, stopCh <-chan struct{}) {
1✔
699
        go wait.Until(func() {
2✔
700
                for {
2✔
701
                        key, quit := queue.Get()
1✔
702
                        if quit {
2✔
703
                                break
1✔
704
                        }
705

706
                        var requeue bool
1✔
707
                        switch key := key.(type) {
1✔
708
                        case chan struct{}:
×
709
                                close(key)
×
710
                        case string:
1✔
711
                                if handler != nil {
2✔
712
                                        requeue = handler(key)
1✔
713
                                }
1✔
714
                        }
715
                        if requeue {
2✔
716
                                queue.AddRateLimited(key)
1✔
717
                        } else {
2✔
718
                                queue.Forget(key)
1✔
719
                        }
1✔
720
                        queue.Done(key)
1✔
721
                }
722
        }, time.Second, stopCh)
723
        <-stopCh
1✔
724
        queue.ShutDown()
1✔
725
}
726

727
func (cont *AciController) enableHppSyncAfterCheckpoint(stopCh <-chan struct{}) {
1✔
728
        done := make(chan struct{})
1✔
729
        cont.netPolQueue.Add(done)
1✔
730
        select {
1✔
731
        case <-done:
1✔
732
                cont.hppSyncEnabled.Store(true)
1✔
733
                cont.log.Info("NetworkPolicy initial sync checkpoint complete; enabling stale HPP/RIC prune")
1✔
734
        case <-stopCh:
1✔
735
        }
736
}
737

738
func (cont *AciController) processEpgDnCacheUpdateQueue(queue workqueue.RateLimitingInterface,
739
        handler func(interface{}) bool,
740
        postDelHandler func() bool, stopCh <-chan struct{}) {
1✔
741
        go wait.Until(func() {
2✔
742
                for {
2✔
743
                        key, quit := queue.Get()
1✔
744
                        if quit {
2✔
745
                                break
1✔
746
                        }
747

748
                        var requeue bool
1✔
749
                        switch key := key.(type) {
1✔
750
                        case chan struct{}:
×
751
                                close(key)
×
752
                        case bool:
1✔
753
                                if handler != nil {
2✔
754
                                        requeue = handler(key)
1✔
755
                                }
1✔
756
                                if postDelHandler != nil {
1✔
757
                                        requeue = postDelHandler()
×
758
                                }
×
759
                        }
760
                        if requeue {
1✔
761
                                queue.AddRateLimited(key)
×
762
                        } else {
1✔
763
                                queue.Forget(key)
1✔
764
                        }
1✔
765
                        queue.Done(key)
1✔
766

767
                }
768
        }, time.Second, stopCh)
769
        <-stopCh
1✔
770
        queue.ShutDown()
1✔
771
}
772

773
func (cont *AciController) globalStaticObjs() apicapi.ApicSlice {
1✔
774
        return apicapi.ApicSlice{}
1✔
775
}
1✔
776

777
func (cont *AciController) aciNameForKey(ktype, key string) string {
1✔
778
        return util.AciNameForKey(cont.config.AciPrefix, ktype, key)
1✔
779
}
1✔
780

781
func (cont *AciController) initStaticObjs() {
1✔
782
        cont.env.InitStaticAciObjects()
1✔
783
        cont.apicConn.WriteStaticApicObjects(cont.config.AciPrefix+"_static",
1✔
784
                cont.globalStaticObjs())
1✔
785
}
1✔
786

787
func (cont *AciController) vmmDomainProvider() (vmmProv string) {
1✔
788
        vmmProv = "Kubernetes"
1✔
789
        if strings.ToLower(cont.config.AciVmmDomainType) == "openshift" {
1✔
790
                vmmProv = "OpenShift"
×
791
        }
×
792
        return
1✔
793
}
794

795
func (cont *AciController) Run(stopCh <-chan struct{}) {
1✔
796
        var err error
1✔
797
        var privKey []byte
1✔
798
        var apicCert []byte
1✔
799

1✔
800
        cont.config.AciVrfDn = "uni/tn-" + cont.config.AciVrfTenant + "/ctx-" + cont.config.AciVrf
1✔
801

1✔
802
        if cont.config.ApicPrivateKeyPath != "" {
1✔
803
                privKey, err = os.ReadFile(cont.config.ApicPrivateKeyPath)
×
804
                if err != nil {
×
805
                        panic(err)
×
806
                }
807
        }
808
        if cont.config.ApicCertPath != "" {
1✔
809
                apicCert, err = os.ReadFile(cont.config.ApicCertPath)
×
810
                if err != nil {
×
811
                        panic(err)
×
812
                }
813
        }
814
        // If not defined, default is 1800
815
        if cont.config.ApicRefreshTimer == "" {
2✔
816
                cont.config.ApicRefreshTimer = "1800"
1✔
817
        }
1✔
818
        refreshTimeout, err := strconv.Atoi(cont.config.ApicRefreshTimer)
1✔
819
        if err != nil {
1✔
820
                panic(err)
×
821
        }
822
        cont.log.Info("ApicRefreshTimer conf is set to: ", refreshTimeout)
1✔
823

1✔
824
        // Bailout if the refreshTimeout is more than 12Hours or less than 5Mins
1✔
825
        if refreshTimeout > (12*60*60) || refreshTimeout < (5*60) {
1✔
826
                cont.log.Info("ApicRefreshTimer can't be more than 12Hrs or less than 5Mins")
×
827
                panic(err)
×
828
        }
829

830
        // If RefreshTickerAdjustInterval is not defined, default to 150Sec.
831
        if cont.config.ApicRefreshTickerAdjust == "" {
2✔
832
                cont.config.ApicRefreshTickerAdjust = "210"
1✔
833
        }
1✔
834
        refreshTickerAdjust, err := strconv.Atoi(cont.config.ApicRefreshTickerAdjust)
1✔
835
        if err != nil {
1✔
836
                panic(err)
×
837
        }
838

839
        // If not defined, default to 900s
840
        if cont.config.LeafRebootCheckInterval == 0 {
2✔
841
                cont.config.LeafRebootCheckInterval = 900
1✔
842
        }
1✔
843

844
        //If ApicSubscriptionDelay is not defined, default to 100ms
845
        if cont.config.ApicSubscriptionDelay == 0 {
2✔
846
                cont.config.ApicSubscriptionDelay = 100
1✔
847
        }
1✔
848
        cont.log.Info("ApicSubscriptionDelay conf is set to: ", cont.config.ApicSubscriptionDelay)
1✔
849

1✔
850
        // If OpflexDeviceDeleteTimeout is not defined, default to 1800s
1✔
851
        if cont.config.OpflexDeviceDeleteTimeout == 0 {
2✔
852
                cont.config.OpflexDeviceDeleteTimeout = 1800
1✔
853
        }
1✔
854

855
        // If OpflexDeviceReconnectWaitTimeout is not defined, default to 25s
856
        if cont.config.OpflexDeviceReconnectWaitTimeout == 0 {
2✔
857
                cont.config.OpflexDeviceReconnectWaitTimeout = 25
1✔
858
        }
1✔
859
        cont.log.Debug("OpflexDeviceReconnectWaitTimeout set to: ", cont.config.OpflexDeviceReconnectWaitTimeout)
1✔
860

1✔
861
        // If SleepTimeSnatGlobalInfoSync is not defined, default to 60
1✔
862
        if cont.config.SleepTimeSnatGlobalInfoSync == 0 {
2✔
863
                cont.config.SleepTimeSnatGlobalInfoSync = 60
1✔
864
        }
1✔
865

866
        // If not defined, default to 32
867
        if cont.config.PodIpPoolChunkSize == 0 {
2✔
868
                cont.config.PodIpPoolChunkSize = 32
1✔
869
        }
1✔
870
        if !cont.isCNOEnabled() {
2✔
871
                cont.log.Info("PodIpPoolChunkSize conf is set to: ", cont.config.PodIpPoolChunkSize)
1✔
872
        }
1✔
873

874
        // If ApicConnectionRetryLimit is not defined, default to 5
875
        if cont.config.ApicConnectionRetryLimit == 0 {
2✔
876
                cont.config.ApicConnectionRetryLimit = 5
1✔
877
        }
1✔
878
        cont.log.Debug("ApicConnectionRetryLimit set to: ", cont.config.ApicConnectionRetryLimit)
1✔
879

1✔
880
        // If not valid, default to 5000-65000
1✔
881
        // other permissible values 1-65000
1✔
882
        defStart := 5000
1✔
883
        defEnd := 65000
1✔
884
        if cont.config.SnatDefaultPortRangeStart == 0 {
2✔
885
                cont.config.SnatDefaultPortRangeStart = defStart
1✔
886
        }
1✔
887
        if cont.config.SnatDefaultPortRangeEnd == 0 {
2✔
888
                cont.config.SnatDefaultPortRangeEnd = defEnd
1✔
889
        }
1✔
890
        if cont.config.SnatDefaultPortRangeStart < 0 || cont.config.SnatDefaultPortRangeEnd < 0 ||
1✔
891
                cont.config.SnatDefaultPortRangeStart > defEnd || cont.config.SnatDefaultPortRangeEnd > defEnd ||
1✔
892
                cont.config.SnatDefaultPortRangeStart > cont.config.SnatDefaultPortRangeEnd {
1✔
893
                cont.config.SnatDefaultPortRangeStart = defStart
×
894
                cont.config.SnatDefaultPortRangeEnd = defEnd
×
895
        }
×
896

897
        // Set default value for pbr programming delay if services list is not empty
898
        // and delay value is empty
899
        if cont.config.ServiceGraphEndpointAddDelay.Delay == 0 &&
1✔
900
                cont.config.ServiceGraphEndpointAddDelay.Services != nil &&
1✔
901
                len(cont.config.ServiceGraphEndpointAddDelay.Services) > 0 {
1✔
902
                cont.config.ServiceGraphEndpointAddDelay.Delay = 90
×
903
        }
×
904
        if cont.config.ServiceGraphEndpointAddDelay.Delay > 0 {
1✔
905
                cont.log.Info("ServiceGraphEndpointAddDelay set to: ", cont.config.ServiceGraphEndpointAddDelay.Delay)
×
906
        }
×
907

908
        // Set contract scope for snat svc graph to global by default
909
        if cont.config.SnatSvcContractScope == "" {
2✔
910
                cont.config.SnatSvcContractScope = "global"
1✔
911
        }
1✔
912
        if cont.config.MaxSvcGraphNodes == 0 {
2✔
913
                cont.config.MaxSvcGraphNodes = 32
1✔
914
        }
1✔
915
        if !cont.isCNOEnabled() {
2✔
916
                cont.log.Info("Max number of nodes per svc graph is set to: ", cont.config.MaxSvcGraphNodes)
1✔
917
        }
1✔
918
        cont.apicConn, err = apicapi.New(cont.log, cont.config.ApicHosts,
1✔
919
                cont.config.ApicUsername, cont.config.ApicPassword,
1✔
920
                privKey, apicCert, cont.config.AciPrefix,
1✔
921
                refreshTimeout, refreshTickerAdjust, cont.config.LeafRebootCheckInterval, cont.config.ApicSubscriptionDelay,
1✔
922
                cont.config.AciVrfTenant, cont.UpdateLLDPIfLocked, cont.isCNOEnabled())
1✔
923
        if err != nil {
1✔
924
                panic(err)
×
925
        }
926

927
        cont.apicConn.FilterOpflexDevice = cont.config.FilterOpflexDevice
1✔
928
        cont.apicConn.Flavor = cont.config.Flavor
1✔
929
        cont.apicConn.VmmDomain = cont.config.AciVmmDomain
1✔
930
        cont.apicConn.ReconnectRetryLimit = cont.config.ApicConnectionRetryLimit
1✔
931
        cont.apicConn.RequestRetryDelayBase = cont.config.ApicRequestRetryDelayBase
1✔
932
        cont.apicConn.EnableRequestRetry = cont.config.EnableApicRequestRetry
1✔
933
        cont.apicConn.DisableRateLimit = cont.config.DisableApicRateLimit
1✔
934

1✔
935
        if len(cont.config.ApicHosts) != 0 {
1✔
936
        APIC_SWITCH:
×
937
                cont.log.WithFields(logrus.Fields{
×
938
                        "mod":  "APICAPI",
×
939
                        "host": cont.apicConn.Apic[cont.apicConn.ApicIndex],
×
940
                }).Debug("Connecting to APIC to determine the Version")
×
941

×
942
                version, err := cont.apicConn.GetVersion()
×
943
                if err != nil {
×
944
                        cont.log.Error("Could not get APIC version, switching to next APIC")
×
945
                        cont.apicConn.ApicIndex = (cont.apicConn.ApicIndex + 1) % len(cont.apicConn.Apic)
×
946
                        time.Sleep(cont.apicConn.ReconnectInterval)
×
947
                        goto APIC_SWITCH
×
948
                }
949
                cont.apicConn.CachedVersion = version
×
950
                apicapi.ApicVersion = version
×
951
                if version >= "4.2(4i)" {
×
952
                        cont.apicConn.SnatPbrFltrChain = true
×
953
                } else {
×
954
                        cont.apicConn.SnatPbrFltrChain = false
×
955
                }
×
956
                if version >= "5.2" {
×
957
                        cont.vmmClusterFaultSupported = true
×
958
                }
×
959
        } else { // For unit-tests
1✔
960
                cont.apicConn.SnatPbrFltrChain = true
1✔
961
        }
1✔
962

963
        if !cont.isCNOEnabled() {
2✔
964
                cont.log.Debug("SnatPbrFltrChain set to:", cont.apicConn.SnatPbrFltrChain)
1✔
965
                // Make sure Pod/NodeBDs are assoicated to same VRF.
1✔
966
                if len(cont.config.ApicHosts) != 0 && cont.config.AciPodBdDn != "" && cont.config.AciNodeBdDn != "" {
1✔
967
                        var expectedVrfRelations []string
×
968
                        expectedVrfRelations = append(expectedVrfRelations, cont.config.AciPodBdDn, cont.config.AciNodeBdDn)
×
969
                        cont.log.Debug("expectedVrfRelations:", expectedVrfRelations)
×
970
                        err = cont.apicConn.ValidateAciVrfAssociation(cont.config.AciVrfDn, expectedVrfRelations)
×
971
                        if err != nil {
×
972
                                cont.log.Error("Pod/NodeBDs and AciL3Out VRF association is incorrect")
×
973
                                panic(err)
×
974
                        }
975
                }
976
        }
977

978
        if len(cont.config.ApicHosts) != 0 && cont.vmmClusterFaultSupported && !cont.isCNOEnabled() {
1✔
979
                //Clear fault instances when the controller starts
×
980
                cont.clearFaultInstances()
×
981
                //Subscribe for vmmEpPD for a given domain
×
982
                var tnTargetFilterEpg string
×
983
                tnTargetFilterEpg += fmt.Sprintf("uni/vmmp-%s/dom-%s/", cont.vmmDomainProvider(), cont.config.AciVmmDomain)
×
984
                subnetTargetFilterEpg := fmt.Sprintf("and(wcard(vmmEpPD.dn,\"%s\"))", tnTargetFilterEpg)
×
985
                cont.apicConn.AddSubscriptionClass("vmmEpPD",
×
986
                        []string{"vmmEpPD"}, subnetTargetFilterEpg)
×
987
                cont.apicConn.SetSubscriptionHooks("vmmEpPD",
×
988
                        func(obj apicapi.ApicObject) bool {
×
989
                                cont.vmmEpPDChanged(obj)
×
990
                                return true
×
991
                        },
×
992
                        func(dn string) {
×
993
                                cont.vmmEpPDDeleted(dn)
×
994
                        })
×
995
        }
996

997
        cont.initStaticObjs()
1✔
998

1✔
999
        err = cont.env.PrepareRun(stopCh)
1✔
1000
        if err != nil {
1✔
1001
                panic(err.Error())
×
1002
        }
1003

1004
        cont.apicConn.FullSyncHook = func() {
1✔
1005
                // put a channel into each work queue and wait on it to
×
1006
                // checkpoint object syncing in response to new subscription
×
1007
                // updates
×
1008
                cont.log.Debug("Starting checkpoint")
×
1009
                var chans []chan struct{}
×
1010
                qs := make([]workqueue.RateLimitingInterface, 0)
×
1011
                _, ok := cont.env.(*K8sEnvironment)
×
1012
                if ok {
×
1013
                        qs = []workqueue.RateLimitingInterface{cont.podQueue}
×
1014
                        if !cont.isCNOEnabled() {
×
1015
                                if !cont.config.DisableHppRendering {
×
1016
                                        qs = append(qs, cont.netPolQueue)
×
1017
                                }
×
1018
                                if cont.config.EnableHppDirect {
×
NEW
1019
                                        qs = append(qs, cont.remIpContQueue, cont.hppQueue)
×
1020
                                }
×
1021
                                qs = append(qs, cont.qosQueue, cont.serviceQueue,
×
1022
                                        cont.snatQueue, cont.netflowQueue, cont.snatNodeInfoQueue,
×
1023
                                        cont.rdConfigQueue, cont.erspanQueue,
×
1024
                                        cont.epgDnCacheUpdateQueue)
×
1025
                        }
1026
                }
1027
                for _, q := range qs {
×
1028
                        c := make(chan struct{})
×
1029
                        chans = append(chans, c)
×
1030
                        q.Add(c)
×
1031
                }
×
1032
                for _, c := range chans {
×
1033
                        <-c
×
1034
                }
×
1035
                cont.log.Debug("Checkpoint complete")
×
1036
        }
1037

1038
        if len(cont.config.ApicHosts) != 0 && !cont.isCNOEnabled() {
1✔
1039
                cont.BuildSubnetDnCache(cont.config.AciVrfDn, cont.config.AciVrfDn)
×
1040
                cont.scheduleRdConfig()
×
1041
                if strings.Contains(cont.config.Flavor, "openstack") {
×
1042
                        cont.setOpenStackSystemId()
×
1043
                }
×
1044
        }
1045

1046
        if !cont.isCNOEnabled() {
2✔
1047
                if cont.config.AciPolicyTenant != cont.config.AciVrfTenant {
2✔
1048
                        cont.apicConn.AddSubscriptionDn("uni/tn-"+cont.config.AciPolicyTenant,
1✔
1049
                                []string{"hostprotPol"})
1✔
1050
                }
1✔
1051
        } else {
1✔
1052
                cont.apicConn.AddSubscriptionDn("uni/tn-"+cont.config.AciPolicyTenant,
1✔
1053
                        []string{"fvBD", "fvAp"})
1✔
1054
                cont.apicConn.AddSubscriptionClass("fvnsVlanInstP",
1✔
1055
                        []string{"fvnsVlanInstP"}, "")
1✔
1056
                cont.apicConn.AddSubscriptionClass("infraRsDomP",
1✔
1057
                        []string{"infraRsDomP"}, "")
1✔
1058
                cont.apicConn.AddSubscriptionClass("physDomP",
1✔
1059
                        []string{"physDomP"}, "")
1✔
1060
                cont.apicConn.AddSubscriptionClass("l3extDomP",
1✔
1061
                        []string{"l3extDomP"}, "")
1✔
1062
                cont.apicConn.AddSubscriptionClass("infraRsVlanNs",
1✔
1063
                        []string{"infraRsVlanNs"}, "")
1✔
1064
                cont.apicConn.AddSubscriptionClass("infraGeneric",
1✔
1065
                        []string{"infraGeneric", "infraRsFuncToEpg"}, "")
1✔
1066
                cont.apicConn.AddSubscriptionClass("l3extOut",
1✔
1067
                        []string{"l3extInstP", "l3extSubnet", "fvRsCons", "fvRsProv", "l3extRsEctx", "l3extRsL3DomAtt", "l3extLNodeP", "l3extRsNodeL3OutAtt", "ipRouteP", "ipNexthopP", "l3extLIfP", "l3extVirtualLIfP", "l3extRsDynPathAtt",
1✔
1068
                                "l3extRsPathL3OutAtt", "l3extMember", "l3extIp", "bgpExtP", "bgpPeerP", "bgpAsP", "bgpLocalAsnP", "bgpRsPeerPfxPol"}, "")
1✔
1069
                cont.apicConn.AddSubscriptionClass("bgpPeerPfxPol",
1✔
1070
                        []string{"bgpPeerPfxPol"}, "")
1✔
1071
        }
1✔
1072

1073
        if cont.config.VmmLite {
1✔
1074
                cont.apicConn.AddSubscriptionClass("infraAttEntityP",
×
1075
                        []string{"infraRsFuncToEpg"}, "")
×
1076

×
1077
                cont.apicConn.SetSubscriptionHooks(
×
1078
                        "infraAttEntityP",
×
1079
                        func(obj apicapi.ApicObject) bool {
×
1080
                                cont.log.Debug("EPG attached to AAEP")
×
1081
                                cont.handleAaepEpgAttach(obj)
×
1082
                                return true
×
1083
                        },
×
1084
                        func(dn string) {
×
1085
                                cont.log.Debug("EPG detached from AAEP")
×
1086
                                cont.handleAaepEpgDetach(dn)
×
1087
                        },
×
1088
                )
1089
        }
1090

1091
        if !cont.isCNOEnabled() {
2✔
1092
                // Websocket notifications for objects under vrfTenant are filtered in
1✔
1093
                // handleSocketUpdate() using DN-based prefix matching (conn.prefix + "_").
1✔
1094
                // All MO names created via AciNameForKey contain this prefix pattern.
1✔
1095
                subscribeMo := []string{"fvBD", "vnsLDevVip", "vnsAbsGraph", "vnsLDevCtx",
1✔
1096
                        "vzFilter", "vzBrCP", "l3extInstP", "vnsSvcRedirectPol",
1✔
1097
                        "vnsRedirectHealthGroup", "fvIPSLAMonitoringPol"}
1✔
1098
                if cont.config.AciPolicyTenant == cont.config.AciVrfTenant {
1✔
1099
                        subscribeMo = append(subscribeMo, "hostprotPol")
×
1100
                }
×
1101
                cont.apicConn.AddSubscriptionDn("uni/tn-"+cont.config.AciVrfTenant,
1✔
1102
                        subscribeMo)
1✔
1103
                cont.apicConn.AddSubscriptionDn(fmt.Sprintf("uni/tn-%s/out-%s",
1✔
1104
                        cont.config.AciVrfTenant, cont.config.AciL3Out),
1✔
1105
                        []string{"fvRsCons"})
1✔
1106
                vmmDn := fmt.Sprintf("comp/prov-%s/ctrlr-[%s]-%s/injcont",
1✔
1107
                        cont.env.VmmPolicy(), cont.config.AciVmmDomain,
1✔
1108
                        cont.config.AciVmmController)
1✔
1109
                // Before subscribing to vmm objects, add vmmInjectedLabel as a child after explicit APIC version check
1✔
1110
                // Since it is not supported for APIC versions < "5.0"
1✔
1111
                cont.addVmmInjectedLabel()
1✔
1112
                cont.apicConn.AddSyncDn(vmmDn,
1✔
1113
                        []string{"vmmInjectedHost", "vmmInjectedNs"})
1✔
1114

1✔
1115
                var tnTargetFilter string
1✔
1116
                if len(cont.config.AciVrfRelatedTenants) > 0 {
1✔
1117
                        for _, tn := range cont.config.AciVrfRelatedTenants {
×
1118
                                tnTargetFilter += fmt.Sprintf("tn-%s/|", tn)
×
1119
                        }
×
1120
                } else {
1✔
1121
                        tnTargetFilter += fmt.Sprintf("tn-%s/|tn-%s/",
1✔
1122
                                cont.config.AciPolicyTenant, cont.config.AciVrfTenant)
1✔
1123
                }
1✔
1124
                subnetTargetFilter := fmt.Sprintf("and(wcard(fvSubnet.dn,\"%s\"))",
1✔
1125
                        tnTargetFilter)
1✔
1126
                cont.apicConn.AddSubscriptionClass("fvSubnet",
1✔
1127
                        []string{"fvSubnet"}, subnetTargetFilter)
1✔
1128

1✔
1129
                cont.apicConn.SetSubscriptionHooks("fvSubnet",
1✔
1130
                        func(obj apicapi.ApicObject) bool {
1✔
1131
                                cont.SubnetChanged(obj, cont.config.AciVrfDn)
×
1132
                                return true
×
1133
                        },
×
1134
                        func(dn string) {
×
1135
                                cont.SubnetDeleted(dn)
×
1136
                        })
×
1137

1138
                cont.apicConn.AddSubscriptionClass("opflexODev",
1✔
1139
                        []string{"opflexODev"}, "")
1✔
1140

1✔
1141
                cont.apicConn.SetSubscriptionHooks("opflexODev",
1✔
1142
                        func(obj apicapi.ApicObject) bool {
1✔
1143
                                cont.opflexDeviceChanged(obj)
×
1144
                                return true
×
1145
                        },
×
1146
                        func(dn string) {
×
1147
                                cont.opflexDeviceDeleted(dn)
×
1148
                        })
×
1149

1150
                if !cont.config.DisableServiceVlanPreprovisioning && !strings.Contains(cont.config.Flavor, "openstack") {
2✔
1151
                        if cont.config.AEP == "" {
2✔
1152
                                cont.log.Error("AEP is missing in configuration, preprovisioning of service vlan will be disabled")
1✔
1153
                        } else {
1✔
1154
                                infraRtAttEntPFilter := fmt.Sprintf("and(wcard(infraRtAttEntP.dn,\"/attentp-%s/\"))", cont.config.AEP)
×
1155
                                cont.apicConn.AddSubscriptionClass("infraRtAttEntP",
×
1156
                                        []string{"infraRtAttEntP"}, infraRtAttEntPFilter)
×
1157

×
1158
                                // For bare metal, the infraRtAttEntP associated with an AEP will be empty.
×
1159
                                // We should not receive any updates for such cases.
×
1160
                                cont.apicConn.SetSubscriptionHooks("infraRtAttEntP",
×
1161
                                        func(obj apicapi.ApicObject) bool {
×
1162
                                                cont.infraRtAttEntPChanged(obj)
×
1163
                                                return true
×
1164
                                        },
×
1165
                                        func(dn string) {
×
1166
                                                cont.infraRtAttEntPDeleted(dn)
×
1167
                                        })
×
1168

1169
                                cont.apicConn.AddSubscriptionClass("vpcIf",
×
1170
                                        []string{"vpcIf"}, "")
×
1171

×
1172
                                cont.apicConn.SetSubscriptionHooks("vpcIf",
×
1173
                                        func(obj apicapi.ApicObject) bool {
×
1174
                                                cont.vpcIfChanged(obj)
×
1175
                                                return true
×
1176
                                        },
×
1177
                                        func(dn string) {
×
1178
                                                cont.vpcIfDeleted(dn)
×
1179
                                        })
×
1180
                        }
1181
                }
1182

1183
                cont.apicConn.VersionUpdateHook =
1✔
1184
                        func() {
1✔
1185
                                cont.initStaticServiceObjs()
×
1186
                        }
×
1187
        } else if cont.config.VmmLite {
1✔
1188
                cont.apicConn.VMMLiteSyncHook = func() {
×
1189
                        cont.syncAndCleanNadCache()
×
1190
                        cont.syncAndCleanNads()
×
1191
                }
×
1192
        }
1193
        go cont.apicConn.Run(stopCh)
1✔
1194
}
1195

1196
func (cont *AciController) syncNodeAciPods(stopCh <-chan struct{}, seconds time.Duration) {
1✔
1197
        cont.log.Debug("Go routine to periodically check the aci pod information in the opflexOdev of a node")
1✔
1198
        ticker := time.NewTicker(seconds * time.Second)
1✔
1199
        defer ticker.Stop()
1✔
1200

1✔
1201
        for {
2✔
1202
                select {
1✔
1203
                case <-ticker.C:
1✔
1204
                        if cont.config.EnableOpflexAgentReconnect {
1✔
1205
                                cont.checkChangeOfOpflexOdevAciPod()
×
1206
                        }
×
1207
                        if cont.config.AciMultipod {
1✔
1208
                                cont.checkChangeOfOdevAciPod()
×
1209
                        }
×
1210
                case <-stopCh:
1✔
1211
                        return
1✔
1212
                }
1213
        }
1214
}
1215

1216
func (cont *AciController) syncOpflexDevices(stopCh <-chan struct{}, seconds time.Duration) {
1✔
1217
        cont.log.Debug("Go routine to periodically delete old opflexdevices started")
1✔
1218
        ticker := time.NewTicker(seconds * time.Second)
1✔
1219
        defer ticker.Stop()
1✔
1220

1✔
1221
        for {
2✔
1222
                select {
1✔
1223
                case <-ticker.C:
1✔
1224
                        cont.deleteOldOpflexDevices()
1✔
1225
                case <-stopCh:
1✔
1226
                        return
1✔
1227
                }
1228
        }
1229
}
1230

1231
func (cont *AciController) syncDelayedEpSlices(stopCh <-chan struct{}, seconds time.Duration) {
1✔
1232
        cont.log.Debug("Go routine to periodically check and process the epslices having delay adding in service")
1✔
1233
        ticker := time.NewTicker(seconds * time.Second)
1✔
1234
        defer ticker.Stop()
1✔
1235

1✔
1236
        for {
2✔
1237
                select {
1✔
1238
                case <-ticker.C:
1✔
1239
                        cont.processDelayedEpSlices()
1✔
1240
                case <-stopCh:
1✔
1241
                        return
1✔
1242
                }
1243
        }
1244
}
1245

1246
func (cont *AciController) snatGlobalInfoSync(stopCh <-chan struct{}, seconds int) {
1✔
1247
        time.Sleep(time.Duration(seconds) * time.Second)
1✔
1248
        cont.log.Debug("Go routine to periodically sync globalinfo and nodeinfo started")
1✔
1249
        iteration := 0
1✔
1250
        for {
2✔
1251
                // To avoid noisy logs, only printing once in 5 minutes
1✔
1252
                if iteration%5 == 0 {
2✔
1253
                        cont.log.Debug("Syncing GlobalInfo with Node infos")
1✔
1254
                }
1✔
1255
                var nodeInfos []*nodeinfo.NodeInfo
1✔
1256
                cont.indexMutex.Lock()
1✔
1257
                cache.ListAll(cont.snatNodeInfoIndexer, labels.Everything(),
1✔
1258
                        func(nodeInfoObj interface{}) {
2✔
1259
                                nodeInfo := nodeInfoObj.(*nodeinfo.NodeInfo)
1✔
1260
                                nodeInfos = append(nodeInfos, nodeInfo)
1✔
1261
                        })
1✔
1262
                expectedmap := make(map[string]map[string]bool)
1✔
1263
                for _, glinfo := range cont.snatGlobalInfoCache {
2✔
1264
                        for nodename, entry := range glinfo {
2✔
1265
                                if _, found := expectedmap[nodename]; !found {
2✔
1266
                                        newentry := make(map[string]bool)
1✔
1267
                                        newentry[entry.SnatPolicyName] = true
1✔
1268
                                        expectedmap[nodename] = newentry
1✔
1269
                                } else {
2✔
1270
                                        currententry := expectedmap[nodename]
1✔
1271
                                        currententry[entry.SnatPolicyName] = true
1✔
1272
                                        expectedmap[nodename] = currententry
1✔
1273
                                }
1✔
1274
                        }
1275
                }
1276
                cont.indexMutex.Unlock()
1✔
1277

1✔
1278
                for _, value := range nodeInfos {
2✔
1279
                        marked := false
1✔
1280
                        policyNames := value.Spec.SnatPolicyNames
1✔
1281
                        nodeName := value.ObjectMeta.Name
1✔
1282
                        _, ok := expectedmap[nodeName]
1✔
1283
                        if !ok && len(policyNames) > 0 {
2✔
1284
                                cont.log.Info("Adding missing entry in snatglobalinfo for node: ", nodeName)
1✔
1285
                                cont.log.Debug("No snat policies found in snatglobalinfo")
1✔
1286
                                cont.log.Debug("Snatpolicy list according to nodeinfo: ", policyNames)
1✔
1287
                                marked = true
1✔
1288
                        } else if len(policyNames) != len(expectedmap[nodeName]) {
3✔
1289
                                cont.log.Info("Adding missing snatpolicy entry in snatglobalinfo for node: ", nodeName)
1✔
1290
                                cont.log.Debug("Snatpolicy list according to snatglobalinfo: ", expectedmap[nodeName])
1✔
1291
                                cont.log.Debug("Snatpolicy list according to nodeinfo: ", policyNames)
1✔
1292
                                marked = true
1✔
1293
                        } else {
2✔
1294
                                if len(policyNames) == 0 && len(expectedmap[nodeName]) == 0 {
1✔
1295
                                        // No snatpolicies present
×
1296
                                        continue
×
1297
                                }
1298
                                eq := reflect.DeepEqual(expectedmap[nodeName], policyNames)
1✔
1299
                                if !eq {
2✔
1300
                                        cont.log.Debug("Syncing inconsistent snatpolicy entry in snatglobalinfo for node: ", nodeName)
1✔
1301
                                        cont.log.Debug("Snatpolicy list according to snatglobalinfo: ", expectedmap[nodeName])
1✔
1302
                                        cont.log.Debug("Snatpolicy list according to nodeinfo: ", policyNames)
1✔
1303
                                        marked = true
1✔
1304
                                }
1✔
1305
                        }
1306
                        if marked {
2✔
1307
                                cont.log.Info("Nodeinfo and globalinfo out of sync for node: ", nodeName)
1✔
1308
                                nodeinfokey, err := cache.MetaNamespaceKeyFunc(value)
1✔
1309
                                if err != nil {
1✔
1310
                                        cont.log.Error("Not able to get key for node: ", nodeName)
×
1311
                                        continue
×
1312
                                }
1313
                                cont.log.Info("Queuing nodeinfokey for globalinfo sync: ", nodeinfokey)
1✔
1314
                                cont.queueNodeInfoUpdateByKey(nodeinfokey)
1✔
1315
                        } else if iteration%5 == 0 {
2✔
1316
                                cont.log.Info("Nodeinfo and globalinfo in sync for node: ", nodeName)
1✔
1317
                        }
1✔
1318
                }
1319
                time.Sleep(time.Duration(seconds) * time.Second)
1✔
1320
                iteration++
1✔
1321
        }
1322
}
1323

1324
func (cont *AciController) processSyncQueue(queue workqueue.RateLimitingInterface,
1325
        queueStop <-chan struct{}) {
1✔
1326
        go wait.Until(func() {
2✔
1327
                for {
2✔
1328
                        syncType, quit := queue.Get()
1✔
1329
                        if quit {
2✔
1330
                                break
1✔
1331
                        }
1332
                        var requeue bool
1✔
1333
                        if sType, ok := syncType.(string); ok {
2✔
1334
                                if f, ok := cont.syncProcessors[sType]; ok {
2✔
1335
                                        requeue = f()
1✔
1336
                                }
1✔
1337
                        }
1338
                        if requeue {
1✔
1339
                                queue.AddRateLimited(syncType)
×
1340
                        } else {
1✔
1341
                                queue.Forget(syncType)
1✔
1342
                        }
1✔
1343
                        queue.Done(syncType)
1✔
1344
                }
1345
        }, time.Second, queueStop)
1346
        <-queueStop
1✔
1347
        queue.ShutDown()
1✔
1348
}
1349

1350
func (cont *AciController) scheduleSyncGlobalInfo() {
1✔
1351
        cont.syncQueue.AddRateLimited("snatGlobalInfo")
1✔
1352
}
1✔
1353
func (cont *AciController) scheduleRdConfig() {
×
1354
        cont.syncQueue.AddRateLimited("rdConfig")
×
1355
}
×
1356
func (cont *AciController) scheduleCreateIstioCR() {
×
1357
        cont.syncQueue.AddRateLimited("istioCR")
×
1358
}
×
1359

1360
func (cont *AciController) addVmmInjectedLabel() {
1✔
1361
        if apicapi.ApicVersion >= "5.2" {
1✔
1362
                err := apicapi.AddMetaDataChild("vmmInjectedNs", "vmmInjectedLabel")
×
1363
                if err != nil {
×
1364
                        panic(err.Error())
×
1365
                }
1366
                err = apicapi.AddMetaDataChild("vmmInjectedSvc", "vmmInjectedLabel")
×
1367
                if err != nil {
×
1368
                        panic(err.Error())
×
1369
                }
1370
        }
1371
        if apicapi.ApicVersion >= "5.0" {
2✔
1372
                err := apicapi.AddMetaDataChild("vmmInjectedReplSet", "vmmInjectedLabel")
1✔
1373
                if err != nil {
1✔
1374
                        panic(err.Error())
×
1375
                }
1376
                err = apicapi.AddMetaDataChild("vmmInjectedContGrp", "vmmInjectedLabel")
1✔
1377
                if err != nil {
1✔
1378
                        panic(err.Error())
×
1379
                }
1380
                err = apicapi.AddMetaDataChild("vmmInjectedDepl", "vmmInjectedLabel")
1✔
1381
                if err != nil {
1✔
1382
                        panic(err.Error())
×
1383
                }
1384
        }
1385
}
1386

1387
func (cont *AciController) isCNOEnabled() bool {
1✔
1388
        return cont.config.ChainedMode || cont.config.VmmLite
1✔
1389
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc