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

noironetworks / aci-containers / 10307

09 Dec 2024 04:06PM CUT coverage: 69.085%. First build
10307

Pull #1468

travis-pro

akhilamohanan
update SnatGlobalInfo CR when uplink MAC address changes

When uplink MAC address changes, the SnatGlobalInfo was not getting
updated which was causing disruption in SNAT traffic

(cherry picked from commit e87b7a1cf)
Pull Request #1468: update SnatGlobalInfo CR when uplink MAC address changes

12 of 24 new or added lines in 3 files covered. (50.0%)

13227 of 19146 relevant lines covered (69.08%)

0.79 hits per line

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

67.48
/pkg/hostagent/snats.go
1
// Copyright 2019 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 WARRATIES 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
// Handlers for snat updates.
16

17
package hostagent
18

19
import (
20
        "bytes"
21
        "context"
22
        "encoding/json"
23
        "net"
24
        "os"
25
        "path/filepath"
26
        "reflect"
27
        "sort"
28
        "strings"
29

30
        snatglobal "github.com/noironetworks/aci-containers/pkg/snatglobalinfo/apis/aci.snat/v1"
31
        snatglobalclset "github.com/noironetworks/aci-containers/pkg/snatglobalinfo/clientset/versioned"
32
        snatpolicy "github.com/noironetworks/aci-containers/pkg/snatpolicy/apis/aci.snat/v1"
33
        snatpolicyclset "github.com/noironetworks/aci-containers/pkg/snatpolicy/clientset/versioned"
34
        "github.com/noironetworks/aci-containers/pkg/util"
35
        "github.com/sirupsen/logrus"
36
        appsv1 "k8s.io/api/apps/v1"
37
        v1 "k8s.io/api/core/v1"
38
        "k8s.io/apimachinery/pkg/api/meta"
39
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
40
        "k8s.io/apimachinery/pkg/labels"
41
        "k8s.io/apimachinery/pkg/runtime"
42
        "k8s.io/apimachinery/pkg/watch"
43
        "k8s.io/client-go/tools/cache"
44
        "k8s.io/kubernetes/pkg/controller"
45
)
46

47
// Filename used to create external service file on host
48
// example snat-external.service
49
const SnatService = "snat-external"
50

51
type ResourceType int
52

53
const (
54
        POD ResourceType = 1 << iota
55
        SERVICE
56
        DEPLOYMENT
57
        NAMESPACE
58
        CLUSTER
59
        INVALID
60
)
61

62
type OpflexPortRange struct {
63
        Start int `json:"start,omitempty"`
64
        End   int `json:"end,omitempty"`
65
}
66

67
// This structure is to write the  SnatFile
68
type OpflexSnatIp struct {
69
        Uuid          string                   `json:"uuid"`
70
        InterfaceName string                   `json:"interface-name,omitempty"`
71
        SnatIp        string                   `json:"snat-ip,omitempty"`
72
        InterfaceMac  string                   `json:"interface-mac,omitempty"`
73
        Local         bool                     `json:"local,omitempty"`
74
        DestIpAddress []string                 `json:"dest,omitempty"`
75
        PortRange     []OpflexPortRange        `json:"port-range,omitempty"`
76
        InterfaceVlan uint                     `json:"interface-vlan,omitempty"`
77
        Zone          uint                     `json:"zone,omitempty"`
78
        Remote        []OpflexSnatIpRemoteInfo `json:"remote,omitempty"`
79
}
80

81
// This Structure is to calculate remote Info
82
type OpflexSnatIpRemoteInfo struct {
83
        NodeIp     string            `json:"snat_ip,omitempty"`
84
        MacAddress string            `json:"mac,omitempty"`
85
        PortRange  []OpflexPortRange `json:"port-range,omitempty"`
86
        Refcount   int               `json:"ref,omitempty"`
87
}
88

89
type opflexSnatGlobalInfo struct {
90
        SnatIp         string
91
        MacAddress     string
92
        PortRange      []OpflexPortRange
93
        SnatIpUid      string
94
        SnatPolicyName string
95
}
96

97
type opflexSnatLocalInfo struct {
98
        Existing     bool                      //True when existing snat-uuids in ep file is to be maintained
99
        Snatpolicies map[ResourceType][]string //Each resource can represent multiple entries
100
        PlcyUuids    []string                  //sorted policy uuids
101
}
102

103
func (agent *HostAgent) initSnatGlobalInformerFromClient(
104
        snatClient *snatglobalclset.Clientset) {
×
105
        agent.initSnatGlobalInformerBase(
×
106
                &cache.ListWatch{
×
107
                        ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
×
108
                                obj, err := snatClient.AciV1().SnatGlobalInfos(metav1.NamespaceAll).List(context.TODO(), options)
×
109
                                if err != nil {
×
110
                                        agent.log.Fatalf("Failed to list SnatGlobalInfo during initialization of SnatGlobalInformer: %s", err)
×
111
                                }
×
112
                                return obj, err
×
113
                        },
114
                        WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
×
115
                                obj, err := snatClient.AciV1().SnatGlobalInfos(metav1.NamespaceAll).Watch(context.TODO(), options)
×
116
                                if err != nil {
×
117
                                        agent.log.Fatalf("Failed to watch SnatGlobalInfo during initialization of SnatGlobalInformer: %s", err)
×
118
                                }
×
119
                                return obj, err
×
120
                        },
121
                })
122
}
123

124
func (agent *HostAgent) initSnatPolicyInformerFromClient(
125
        snatClient *snatpolicyclset.Clientset) {
×
126
        agent.initSnatPolicyInformerBase(
×
127
                &cache.ListWatch{
×
128
                        ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
×
129
                                obj, err := snatClient.AciV1().SnatPolicies().List(context.TODO(), options)
×
130
                                if err != nil {
×
131
                                        agent.log.Fatalf("Failed to list SnatPolicies during initialization of SnatPolicyInformer: %s", err)
×
132
                                }
×
133
                                return obj, err
×
134
                        },
135
                        WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
×
136
                                obj, err := snatClient.AciV1().SnatPolicies().Watch(context.TODO(), options)
×
137
                                if err != nil {
×
138
                                        agent.log.Fatalf("Failed to watch SnatPolicies during initialization of SnatPolicyInformer: %s", err)
×
139
                                }
×
140
                                return obj, err
×
141
                        },
142
                })
143
}
144

145
func writeSnat(snatfile string, snat *OpflexSnatIp) (bool, error) {
1✔
146
        newdata, err := json.MarshalIndent(snat, "", "  ")
1✔
147
        if err != nil {
1✔
148
                return true, err
×
149
        }
×
150
        existingdata, err := os.ReadFile(snatfile)
1✔
151
        if err == nil && reflect.DeepEqual(existingdata, newdata) {
2✔
152
                return false, nil
1✔
153
        }
1✔
154

155
        err = os.WriteFile(snatfile, newdata, 0644)
1✔
156
        return true, err
1✔
157
}
158

159
func (agent *HostAgent) FormSnatFilePath(uuid string) string {
1✔
160
        return filepath.Join(agent.config.OpFlexSnatDir, uuid+".snat")
1✔
161
}
1✔
162

163
func SnatGlobalInfoLogger(log *logrus.Logger, snat *snatglobal.SnatGlobalInfo) *logrus.Entry {
1✔
164
        return log.WithFields(logrus.Fields{
1✔
165
                "namespace": snat.ObjectMeta.Namespace,
1✔
166
                "name":      snat.ObjectMeta.Name,
1✔
167
                "spec":      snat.Spec,
1✔
168
        })
1✔
169
}
1✔
170

171
func opflexSnatIpLogger(log *logrus.Logger, snatip *OpflexSnatIp) *logrus.Entry {
1✔
172
        return log.WithFields(logrus.Fields{
1✔
173
                "uuid":           snatip.Uuid,
1✔
174
                "snat_ip":        snatip.SnatIp,
1✔
175
                "mac_address":    snatip.InterfaceMac,
1✔
176
                "port_range":     snatip.PortRange,
1✔
177
                "local":          snatip.Local,
1✔
178
                "interface-name": snatip.InterfaceName,
1✔
179
                "interfcae-vlan": snatip.InterfaceVlan,
1✔
180
                "remote":         snatip.Remote,
1✔
181
        })
1✔
182
}
1✔
183

184
func (agent *HostAgent) initSnatGlobalInformerBase(listWatch *cache.ListWatch) {
1✔
185
        agent.snatGlobalInformer = cache.NewSharedIndexInformer(
1✔
186
                listWatch,
1✔
187
                &snatglobal.SnatGlobalInfo{},
1✔
188
                controller.NoResyncPeriodFunc(),
1✔
189
                cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
1✔
190
        )
1✔
191
        agent.snatGlobalInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
1✔
192
                AddFunc: func(obj interface{}) {
2✔
193
                        agent.snatGlobalInfoUpdate(obj)
1✔
194
                },
1✔
195
                UpdateFunc: func(_ interface{}, obj interface{}) {
1✔
196
                        agent.snatGlobalInfoUpdate(obj)
1✔
197
                },
1✔
198
                DeleteFunc: func(obj interface{}) {
1✔
199
                        agent.snatGlobalInfoDelete(obj)
1✔
200
                },
1✔
201
        })
202
        agent.log.Info("Initializing SnatGlobal Info Informers")
1✔
203
}
204

205
func (agent *HostAgent) initSnatPolicyInformerBase(listWatch *cache.ListWatch) {
1✔
206
        agent.snatPolicyInformer = cache.NewSharedIndexInformer(
1✔
207
                listWatch,
1✔
208
                &snatpolicy.SnatPolicy{}, controller.NoResyncPeriodFunc(),
1✔
209
                cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
1✔
210
        )
1✔
211
        agent.snatPolicyInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
1✔
212
                AddFunc: func(obj interface{}) {
2✔
213
                        agent.snatPolicyAdded(obj)
1✔
214
                },
1✔
215
                UpdateFunc: func(oldobj interface{}, newobj interface{}) {
1✔
216
                        agent.snatPolicyUpdated(oldobj, newobj)
1✔
217
                },
1✔
218
                DeleteFunc: func(obj interface{}) {
1✔
219
                        agent.snatPolicyDeleted(obj)
1✔
220
                },
1✔
221
        })
222
        agent.log.Infof("Initializing Snat Policy Informers")
1✔
223
}
224

225
func (agent *HostAgent) snatPolicyAdded(obj interface{}) {
1✔
226
        agent.indexMutex.Lock()
1✔
227
        defer agent.indexMutex.Unlock()
1✔
228
        agent.snatPolicyCacheMutex.Lock()
1✔
229
        defer agent.snatPolicyCacheMutex.Unlock()
1✔
230
        policyinfo := obj.(*snatpolicy.SnatPolicy)
1✔
231
        agent.log.Infof("Snat Policy Added: name=%s", policyinfo.ObjectMeta.Name)
1✔
232
        if policyinfo.Status.State != snatpolicy.Ready {
1✔
233
                return
×
234
        }
×
235
        agent.snatPolicyCache[policyinfo.ObjectMeta.Name] = policyinfo
1✔
236
        setDestIp(agent.snatPolicyCache[policyinfo.ObjectMeta.Name].Spec.DestIp)
1✔
237
        agent.handleSnatUpdate(policyinfo)
1✔
238
}
239

240
func (agent *HostAgent) snatPolicyUpdated(oldobj, newobj interface{}) {
1✔
241
        agent.indexMutex.Lock()
1✔
242
        defer agent.indexMutex.Unlock()
1✔
243
        agent.snatPolicyCacheMutex.Lock()
1✔
244
        defer agent.snatPolicyCacheMutex.Unlock()
1✔
245
        oldpolicyinfo := oldobj.(*snatpolicy.SnatPolicy)
1✔
246
        newpolicyinfo := newobj.(*snatpolicy.SnatPolicy)
1✔
247
        agent.log.Infof("Snat Policy Updated: name=%s, policy status=%s", newpolicyinfo.ObjectMeta.Name, newpolicyinfo.Status.State)
1✔
248
        if reflect.DeepEqual(oldpolicyinfo, newpolicyinfo) {
1✔
249
                return
×
250
        }
×
251
        //1. check if the local nodename is  present in globalinfo
252
        // 2. if it is not present then delete the policy from localInfo as the portinfo is not allocated  for node
253
        if newpolicyinfo.Status.State == snatpolicy.IpPortsExhausted {
2✔
254
                agent.log.Infof("Ports exhausted for snat policy: %s", newpolicyinfo.ObjectMeta.Name)
1✔
255
                return
1✔
256
        }
1✔
257
        if newpolicyinfo.Status.State != snatpolicy.Ready {
1✔
258
                return
×
259
        }
×
260
        agent.snatPolicyCache[newpolicyinfo.ObjectMeta.Name] = newpolicyinfo
1✔
261
        setDestIp(agent.snatPolicyCache[newpolicyinfo.ObjectMeta.Name].Spec.DestIp)
1✔
262
        // After Validation of SnatPolicy State will be set to Ready
1✔
263
        if newpolicyinfo.Status.State != oldpolicyinfo.Status.State {
1✔
264
                agent.handleSnatUpdate(newpolicyinfo)
×
265
                return
×
266
        }
×
267
        update := true
1✔
268
        if !reflect.DeepEqual(oldpolicyinfo.Spec.Selector,
1✔
269
                newpolicyinfo.Spec.Selector) {
1✔
270
                var poduids []string
×
271
                // delete all the pods matching the policy
×
272
                for uuid, res := range agent.snatPods[newpolicyinfo.ObjectMeta.Name] {
×
273
                        agent.deleteSnatLocalInfo(uuid, res, newpolicyinfo.ObjectMeta.Name)
×
274
                        poduids = append(poduids, uuid)
×
275
                }
×
276
                agent.updateEpFiles(poduids)
×
277
                agent.handleSnatUpdate(newpolicyinfo)
×
278
                var matchingpods []string
×
279
                for uuid := range agent.snatPods[newpolicyinfo.ObjectMeta.Name] {
×
280
                        matchingpods = append(matchingpods, uuid)
×
281
                }
×
282
                // Nodeinfo trigger handles if handlesnatUpdate don't match any pods
283
                // this trigger clears the globalinfo allocated for node
284
                if len(poduids) > 0 && len(matchingpods) == 0 {
×
285
                        agent.scheduleSyncNodeInfo()
×
286
                } else {
×
287
                        // Epfiles needs to be updated if there are any  pods matching with newlabel
×
288
                        agent.updateEpFiles(matchingpods)
×
289
                }
×
290
                update = false
×
291
        }
292
        // destination update can be ignored  if labels also changed
293
        if !reflect.DeepEqual(oldpolicyinfo.Spec.DestIp,
1✔
294
                newpolicyinfo.Spec.DestIp) && update {
2✔
295
                // updateEpFile
1✔
296
                // SyncSnatFile
1✔
297
                var poduids []string
1✔
298
                for uid := range agent.snatPods[newpolicyinfo.ObjectMeta.Name] {
2✔
299
                        poduids = append(poduids, uid)
1✔
300
                }
1✔
301
                // This EPfiles update based on destip chanes policy order is maintained
302
                agent.updateEpFiles(poduids)
1✔
303
                agent.scheduleSyncSnats()
1✔
304
        }
305
}
306

307
func (agent *HostAgent) snatPolicyDeleted(obj interface{}) {
1✔
308
        agent.indexMutex.Lock()
1✔
309
        defer agent.indexMutex.Unlock()
1✔
310
        agent.snatPolicyCacheMutex.Lock()
1✔
311
        defer agent.snatPolicyCacheMutex.Unlock()
1✔
312
        policyinfo, isSnatPolicy := obj.(*snatpolicy.SnatPolicy)
1✔
313
        if !isSnatPolicy {
1✔
314
                deletedState, ok := obj.(cache.DeletedFinalStateUnknown)
×
315
                if !ok {
×
316
                        agent.log.Error("Received unexpected object: ", obj)
×
317
                        return
×
318
                }
×
319
                policyinfo, ok = deletedState.Obj.(*snatpolicy.SnatPolicy)
×
320
                if !ok {
×
321
                        agent.log.Error("DeletedFinalStateUnknown contained non-Snatpolicy object: ", deletedState.Obj)
×
322
                        return
×
323
                }
×
324
        }
325
        agent.log.Infof("Snat Policy Deleted: name=%s", policyinfo.ObjectMeta.Name)
1✔
326
        agent.deletePolicy(policyinfo)
1✔
327
        delete(agent.snatPolicyCache, policyinfo.ObjectMeta.Name)
1✔
328
}
329

330
func (agent *HostAgent) handleSnatUpdate(policy *snatpolicy.SnatPolicy) {
1✔
331
        // First Parse the policy and check for applicability
1✔
332
        // list all the Pods based on labels and namespace
1✔
333
        agent.log.Debug("Handle snatUpdate: ", policy)
1✔
334
        _, err := cache.MetaNamespaceKeyFunc(policy)
1✔
335
        if err != nil {
1✔
336
                return
×
337
        }
×
338
        // 1.List the targets matching the policy based on policy config
339
        uids := make(map[ResourceType][]string)
1✔
340
        switch {
1✔
341
        case len(policy.Spec.SnatIp) == 0:
1✔
342
                //handle policy for service pods
1✔
343
                var services []*v1.Service
1✔
344
                var poduids []string
1✔
345
                selector := labels.SelectorFromSet(policy.Spec.Selector.Labels)
1✔
346
                cache.ListAll(agent.serviceInformer.GetIndexer(), selector,
1✔
347
                        func(servobj interface{}) {
2✔
348
                                services = append(services, servobj.(*v1.Service))
1✔
349
                        })
1✔
350
                // list the pods and apply the policy at service target
351
                for _, service := range services {
2✔
352
                        uids, _ := agent.getPodsMatchingObject(service, policy.ObjectMeta.Name)
1✔
353
                        poduids = append(poduids, uids...)
1✔
354
                        key, err := agent.MetaNamespaceUIDFunc(service)
1✔
355
                        if err == nil {
2✔
356
                                _, ok := agent.ReadSnatPolicyLabel(key)
1✔
357
                                if ok && len(policy.Spec.Selector.Labels) > 0 {
2✔
358
                                        agent.WriteSnatPolicyLabel(key, policy.ObjectMeta.Name, SERVICE)
1✔
359
                                }
1✔
360
                        }
361
                }
362
                uids[SERVICE] = poduids
1✔
363
        case reflect.DeepEqual(policy.Spec.Selector, snatpolicy.PodSelector{}):
×
364
                // This Policy will be applied at cluster level
×
365
                var poduids []string
×
366
                // handle policy for cluster
×
367
                for k := range agent.opflexEps {
×
368
                        poduids = append(poduids, k)
×
369
                }
×
370
                uids[CLUSTER] = poduids
×
371
        case len(policy.Spec.Selector.Labels) == 0:
1✔
372
                // This is namespace based policy
1✔
373
                var poduids []string
1✔
374
                cache.ListAllByNamespace(agent.podInformer.GetIndexer(), policy.Spec.Selector.Namespace, labels.Everything(),
1✔
375
                        func(podobj interface{}) {
2✔
376
                                pod := podobj.(*v1.Pod)
1✔
377
                                if pod.Spec.NodeName == agent.config.NodeName {
2✔
378
                                        poduids = append(poduids, string(pod.ObjectMeta.UID))
1✔
379
                                }
1✔
380
                        })
381
                uids[NAMESPACE] = poduids
1✔
382
        default:
1✔
383
                poduids, deppoduids, nspoduids :=
1✔
384
                        agent.getPodUidsMatchingLabel(policy.Spec.Selector.Namespace, policy.Spec.Selector.Labels, policy.ObjectMeta.Name)
1✔
385
                uids[POD] = poduids
1✔
386
                uids[DEPLOYMENT] = deppoduids
1✔
387
                uids[NAMESPACE] = nspoduids
1✔
388
        }
389
        succeededPodUids := agent.getPodUidsSucceeded()
1✔
390
        for res, poduids := range uids {
2✔
391
                if len(succeededPodUids) > 0 {
1✔
392
                        poduids = difference(poduids, succeededPodUids)
×
393
                }
×
394
                agent.applyPolicy(poduids, res, policy.GetName())
1✔
395
        }
396
}
397

398
func (agent *HostAgent) getPodUidsSucceeded() (poduids []string) {
1✔
399
        cache.ListAll(agent.nsInformer.GetIndexer(), labels.Everything(),
1✔
400
                func(nsobj interface{}) {
2✔
401
                        poduids = append(poduids, agent.getSucceededPodsUids(nsobj)...)
1✔
402
                })
1✔
403
        return
1✔
404
}
405

406
func (agent *HostAgent) getSucceededPodsUids(obj interface{}) (poduids []string) {
1✔
407
        ns, _ := obj.(*v1.Namespace)
1✔
408
        cache.ListAllByNamespace(agent.podInformer.GetIndexer(),
1✔
409
                ns.ObjectMeta.Name, labels.Everything(),
1✔
410
                func(podobj interface{}) {
2✔
411
                        pod := podobj.(*v1.Pod)
1✔
412
                        if pod.Spec.NodeName == agent.config.NodeName && pod.Status.Phase == v1.PodSucceeded {
1✔
413
                                poduids = append(poduids, string(pod.ObjectMeta.UID))
×
414
                        }
×
415
                })
416
        if len(poduids) != 0 {
1✔
417
                agent.log.Info("Matching succeeded pod uids: ", poduids)
×
418
        }
×
419
        return
1✔
420
}
421

422
func (agent *HostAgent) updateSnatPolicyLabels(obj interface{}, policyname string) (poduids []string) {
1✔
423
        uids, res := agent.getPodsMatchingObject(obj, policyname)
1✔
424
        if len(uids) > 0 {
2✔
425
                key, _ := agent.MetaNamespaceUIDFunc(obj)
1✔
426
                if _, ok := agent.ReadSnatPolicyLabel(key); ok {
2✔
427
                        agent.WriteSnatPolicyLabel(key, policyname, res)
1✔
428
                }
1✔
429
        }
430
        return uids
1✔
431
}
432

433
// Get all the pods matching the Policy Selector
434
func (agent *HostAgent) getPodUidsMatchingLabel(namespace string, label map[string]string, policyname string) (poduids []string,
435
        deppoduids []string, nspoduids []string) {
1✔
436
        selector := labels.SelectorFromSet(label)
1✔
437
        cache.ListAll(agent.podInformer.GetIndexer(), selector,
1✔
438
                func(podobj interface{}) {
2✔
439
                        pod := podobj.(*v1.Pod)
1✔
440
                        if pod.Spec.NodeName == agent.config.NodeName {
2✔
441
                                poduids = append(poduids, agent.updateSnatPolicyLabels(podobj, policyname)...)
1✔
442
                        }
1✔
443
                })
444
        cache.ListAll(agent.depInformer.GetIndexer(), selector,
1✔
445
                func(depobj interface{}) {
1✔
446
                        deppoduids = append(deppoduids, agent.updateSnatPolicyLabels(depobj, policyname)...)
×
447
                })
×
448
        cache.ListAll(agent.nsInformer.GetIndexer(), selector,
1✔
449
                func(nsobj interface{}) {
1✔
450
                        nspoduids = append(nspoduids, agent.updateSnatPolicyLabels(nsobj, policyname)...)
×
451
                })
×
452
        return
1✔
453
}
454

455
// Apply the Policy at Resource level
456
func (agent *HostAgent) applyPolicy(poduids []string, res ResourceType, snatPolicyName string) {
1✔
457
        nodeUpdate := false
1✔
458
        if len(poduids) == 0 {
2✔
459
                return
1✔
460
        }
1✔
461
        if _, ok := agent.snatPods[snatPolicyName]; !ok {
2✔
462
                agent.snatPods[snatPolicyName] = make(map[string]ResourceType)
1✔
463
                nodeUpdate = true
1✔
464
        }
1✔
465
        for _, uid := range poduids {
2✔
466
                _, ok := agent.opflexSnatLocalInfos[uid]
1✔
467
                if !ok {
2✔
468
                        var localinfo opflexSnatLocalInfo
1✔
469
                        localinfo.Snatpolicies = make(map[ResourceType][]string)
1✔
470
                        localinfo.Snatpolicies[res] = append(localinfo.Snatpolicies[res], snatPolicyName)
1✔
471
                        agent.opflexSnatLocalInfos[uid] = &localinfo
1✔
472
                        agent.snatPods[snatPolicyName][uid] |= res
1✔
473
                        agent.log.Debug("Apply policy res: ", agent.snatPods[snatPolicyName][uid])
1✔
474
                } else {
2✔
475
                        present := false
1✔
476
                        for _, name := range agent.opflexSnatLocalInfos[uid].Snatpolicies[res] {
2✔
477
                                if name == snatPolicyName {
2✔
478
                                        present = true
1✔
479
                                }
1✔
480
                        }
481
                        if !present {
2✔
482
                                agent.opflexSnatLocalInfos[uid].Snatpolicies[res] =
1✔
483
                                        append(agent.opflexSnatLocalInfos[uid].Snatpolicies[res], snatPolicyName)
1✔
484
                                agent.snatPods[snatPolicyName][uid] |= res
1✔
485
                                agent.log.Debug("Apply policy res: ", agent.snatPods[snatPolicyName][uid])
1✔
486
                        }
1✔
487
                }
488
        }
489
        if nodeUpdate {
2✔
490
                agent.log.Debug("Schedule the node Sync")
1✔
491
                agent.scheduleSyncNodeInfo()
1✔
492
        } else {
2✔
493
                // trigger update  the epfile
1✔
494
                agent.updateEpFiles(poduids)
1✔
495
        }
1✔
496
}
497

498
// Sync the NodeInfo
499
func (agent *HostAgent) syncSnatNodeInfo() bool {
1✔
500
        if !agent.syncEnabled || agent.config.ChainedMode {
1✔
501
                return false
×
502
        }
×
503
        snatPolicyNames := make(map[string]bool)
1✔
504
        agent.indexMutex.Lock()
1✔
505
        for key, val := range agent.snatPods {
2✔
506
                if len(val) > 0 {
2✔
507
                        snatPolicyNames[key] = true
1✔
508
                }
1✔
509
        }
510
        uplinkMacAddress := agent.config.UplinkMacAdress
1✔
511
        agent.indexMutex.Unlock()
1✔
512
        env := agent.env.(*K8sEnvironment)
1✔
513
        if env == nil {
1✔
514
                return false
×
515
        }
×
516
        // send nodeupdate for the policy names
517
        if !agent.InformNodeInfo(env.nodeInfo, snatPolicyNames, uplinkMacAddress) {
1✔
NEW
518
                agent.log.Debug("Failed to update retry: ", snatPolicyNames, " macAddress:", uplinkMacAddress)
×
519
                return true
×
520
        }
×
521
        agent.log.Debug("Updated Node Info: ", snatPolicyNames, " macAddress:", uplinkMacAddress)
1✔
522
        return false
1✔
523
}
524

525
func (agent *HostAgent) deletePolicy(policy *snatpolicy.SnatPolicy) {
1✔
526
        pods, ok := agent.snatPods[policy.GetName()]
1✔
527
        var poduids []string
1✔
528
        if !ok {
1✔
529
                return
×
530
        }
×
531
        for uuid, res := range pods {
2✔
532
                agent.deleteSnatLocalInfo(uuid, res, policy.GetName())
1✔
533
                poduids = append(poduids, uuid)
1✔
534
        }
1✔
535
        agent.updateEpFiles(poduids)
1✔
536
        delete(agent.snatPods, policy.GetName())
1✔
537
        agent.log.Infof("SnatPolicy deleted update Nodeinfo: %s", policy.GetName())
1✔
538
        agent.scheduleSyncNodeInfo()
1✔
539
        agent.DeleteMatchingSnatPolicyLabel(policy.GetName())
1✔
540
}
541

542
func (agent *HostAgent) deleteSnatLocalInfo(poduid string, res ResourceType, plcyname string) {
1✔
543
        localinfo, ok := agent.opflexSnatLocalInfos[poduid]
1✔
544
        if ok {
2✔
545
                i := uint(0)
1✔
546
                j := uint(0)
1✔
547
                // loop through all the resources matching the policy
1✔
548
                for i < uint(res) {
2✔
549
                        i = 1 << j
1✔
550
                        j++
1✔
551
                        if i&uint(res) == i {
2✔
552
                                length := len(localinfo.Snatpolicies[ResourceType(i)])
1✔
553
                                deletedcount := 0
1✔
554
                                for k := 0; k < length; k++ {
2✔
555
                                        l := k - deletedcount
1✔
556
                                        // delete the matching policy from  policy stack
1✔
557
                                        if plcyname == localinfo.Snatpolicies[ResourceType(i)][l] {
2✔
558
                                                agent.log.Infof("Delete the Snat Policy name from SnatLocalInfo: %s", plcyname)
1✔
559
                                                localinfo.Snatpolicies[ResourceType(i)] =
1✔
560
                                                        append(localinfo.Snatpolicies[ResourceType(i)][:l],
1✔
561
                                                                localinfo.Snatpolicies[ResourceType(i)][l+1:]...)
1✔
562
                                                deletedcount++
1✔
563
                                        }
1✔
564
                                }
565
                                agent.log.Debug("Opflex agent and localinfo: ", agent.opflexSnatLocalInfos[poduid], localinfo)
1✔
566
                                if len(localinfo.Snatpolicies[res]) == 0 {
2✔
567
                                        delete(localinfo.Snatpolicies, res)
1✔
568
                                }
1✔
569
                                if v, ok := agent.snatPods[plcyname]; ok {
2✔
570
                                        if _, ok := v[poduid]; ok {
2✔
571
                                                agent.snatPods[plcyname][poduid] &= ^(res) // clear the bit
1✔
572
                                                if agent.snatPods[plcyname][poduid] == 0 { // delete the pod if no resource is pointing for the policy
2✔
573
                                                        delete(agent.snatPods[plcyname], poduid)
1✔
574
                                                        if len(agent.snatPods[plcyname]) == 0 {
2✔
575
                                                                delete(agent.snatPods, plcyname)
1✔
576
                                                        }
1✔
577
                                                }
578
                                        }
579
                                }
580
                        }
581
                }
582
        }
583
}
584

585
func (agent *HostAgent) snatGlobalInfoUpdate(obj interface{}) {
1✔
586
        agent.indexMutex.Lock()
1✔
587
        defer agent.indexMutex.Unlock()
1✔
588
        snat := obj.(*snatglobal.SnatGlobalInfo)
1✔
589
        key, err := cache.MetaNamespaceKeyFunc(snat)
1✔
590
        if err != nil {
1✔
591
                SnatGlobalInfoLogger(agent.log, snat).
×
592
                        Error("Could not create key:" + err.Error())
×
593
                return
×
594
        }
×
595
        agent.log.Info("Snat Global Object Added/Updated: ", snat)
1✔
596
        agent.doUpdateSnatGlobalInfo(key)
1✔
597
}
598

599
func (agent *HostAgent) doUpdateSnatGlobalInfo(key string) {
1✔
600
        snatobj, exists, err :=
1✔
601
                agent.snatGlobalInformer.GetStore().GetByKey(key)
1✔
602
        if err != nil {
1✔
603
                agent.log.Error("Could not lookup snat for " +
×
604
                        key + ": " + err.Error())
×
605
                return
×
606
        }
×
607
        if !exists || snatobj == nil {
1✔
608
                return
×
609
        }
×
610
        snat := snatobj.(*snatglobal.SnatGlobalInfo)
1✔
611
        logger := SnatGlobalInfoLogger(agent.log, snat)
1✔
612
        agent.snaGlobalInfoChanged(snatobj, logger)
1✔
613
}
614

615
func fileExists(filename string) bool {
1✔
616
        info, err := os.Stat(filename)
1✔
617
        if os.IsNotExist(err) {
2✔
618
                return false
1✔
619
        }
1✔
620
        return !info.IsDir()
1✔
621
}
622

623
func (agent *HostAgent) snaGlobalInfoChanged(snatobj interface{}, logger *logrus.Entry) {
1✔
624
        agent.snatPolicyCacheMutex.RLock()
1✔
625
        defer agent.snatPolicyCacheMutex.RUnlock()
1✔
626
        snat := snatobj.(*snatglobal.SnatGlobalInfo)
1✔
627
        syncSnat := false
1✔
628
        updateLocalInfo := false
1✔
629
        if logger == nil {
1✔
630
                logger = agent.log.WithFields(logrus.Fields{})
×
631
        }
×
632
        logger.Debug("Snat Global info Changed...")
1✔
633
        globalInfo := snat.Spec.GlobalInfos
1✔
634
        // This case is possible when all the pods will be deleted from that node
1✔
635
        for nodename := range agent.opflexSnatGlobalInfos {
2✔
636
                if _, ok := globalInfo[nodename]; !ok {
1✔
637
                        delete(agent.opflexSnatGlobalInfos, nodename)
×
638
                        syncSnat = true
×
639
                }
×
640
        }
641
        for nodename, val := range globalInfo {
2✔
642
                var newglobalinfos []*opflexSnatGlobalInfo
1✔
643
                for _, v := range val {
2✔
644
                        portrange := make([]OpflexPortRange, 1)
1✔
645
                        portrange[0].Start = v.PortRanges[0].Start
1✔
646
                        portrange[0].End = v.PortRanges[0].End
1✔
647
                        nodeInfo := &opflexSnatGlobalInfo{
1✔
648
                                SnatIp:         v.SnatIp,
1✔
649
                                MacAddress:     v.MacAddress,
1✔
650
                                PortRange:      portrange,
1✔
651
                                SnatIpUid:      v.SnatIpUid,
1✔
652
                                SnatPolicyName: v.SnatPolicyName,
1✔
653
                        }
1✔
654
                        newglobalinfos = append(newglobalinfos, nodeInfo)
1✔
655
                }
1✔
656
                existing, ok := agent.opflexSnatGlobalInfos[nodename]
1✔
657
                if (ok && !reflect.DeepEqual(existing, newglobalinfos)) || !ok {
2✔
658
                        agent.opflexSnatGlobalInfos[nodename] = newglobalinfos
1✔
659
                        if nodename == agent.config.NodeName {
2✔
660
                                updateLocalInfo = true
1✔
661
                        }
1✔
662
                        syncSnat = true
1✔
663
                }
664
        }
665

666
        snatFileName := SnatService + ".service"
1✔
667
        filePath := filepath.Join(agent.config.OpFlexServiceDir, snatFileName)
1✔
668
        file_exists := fileExists(filePath)
1✔
669
        if len(agent.opflexSnatGlobalInfos) > 0 {
2✔
670
                // if more than one global infos, create snat ext file
1✔
671
                as := &opflexService{
1✔
672
                        Uuid:              SnatService,
1✔
673
                        DomainPolicySpace: agent.config.AciVrfTenant,
1✔
674
                        DomainName:        agent.config.AciVrf,
1✔
675
                        ServiceMode:       "loadbalancer",
1✔
676
                        ServiceMappings:   make([]opflexServiceMapping, 0),
1✔
677
                        InterfaceName:     agent.config.UplinkIface,
1✔
678
                        InterfaceVlan:     uint16(agent.config.ServiceVlan),
1✔
679
                        ServiceMac:        agent.config.UplinkMacAdress,
1✔
680
                        InterfaceIp:       agent.serviceEp.Ipv4.String(),
1✔
681
                }
1✔
682
                sm := &opflexServiceMapping{
1✔
683
                        Conntrack: true,
1✔
684
                }
1✔
685
                as.ServiceMappings = append(as.ServiceMappings, *sm)
1✔
686
                agent.opflexServices[SnatService] = as
1✔
687
                if !file_exists {
2✔
688
                        wrote, err := writeAs(filePath, as)
1✔
689
                        if err != nil {
1✔
690
                                agent.log.Debug("Unable to write snat ext service file:")
×
691
                        } else if wrote {
2✔
692
                                agent.log.Debug("Created snat ext service file")
1✔
693
                        }
1✔
694
                }
695
        } else {
×
696
                delete(agent.opflexServices, SnatService)
×
697
                // delete snat service file if no global infos exist
×
698
                if file_exists {
×
699
                        err := os.Remove(filePath)
×
700
                        if err != nil {
×
701
                                agent.log.Debug("Unable to delete snat ext service file")
×
702
                        } else {
×
703
                                agent.log.Debug("Deleted snat ext service file")
×
704
                        }
×
705
                }
706
        }
707
        if syncSnat {
2✔
708
                agent.scheduleSyncSnats()
1✔
709
        }
1✔
710
        if updateLocalInfo {
2✔
711
                var poduids []string
1✔
712
                for _, v := range agent.opflexSnatGlobalInfos[agent.config.NodeName] {
2✔
713
                        for uuid := range agent.snatPods[v.SnatPolicyName] {
2✔
714
                                poduids = append(poduids, uuid)
1✔
715
                        }
1✔
716
                }
717
                agent.log.Debug("Updating EpFile GlobalInfo Context: ", poduids)
1✔
718
                agent.updateEpFiles(poduids)
1✔
719
        }
720
}
721

722
func (agent *HostAgent) snatGlobalInfoDelete(obj interface{}) {
1✔
723
        agent.log.Debug("Snat Global Info Obj Delete")
1✔
724
        snat := obj.(*snatglobal.SnatGlobalInfo)
1✔
725
        globalInfo := snat.Spec.GlobalInfos
1✔
726
        agent.indexMutex.Lock()
1✔
727
        for nodename := range globalInfo {
2✔
728
                delete(agent.opflexSnatGlobalInfos, nodename)
1✔
729
        }
1✔
730
        agent.indexMutex.Unlock()
1✔
731
}
732

733
func (agent *HostAgent) syncSnat() bool {
1✔
734
        if !agent.syncEnabled || agent.config.ChainedMode {
1✔
735
                return false
×
736
        }
×
737
        agent.log.Debug("Syncing snats")
1✔
738
        agent.indexMutex.Lock()
1✔
739
        opflexSnatIps := make(map[string]*OpflexSnatIp)
1✔
740
        remoteinfo := make(map[string][]OpflexSnatIpRemoteInfo)
1✔
741
        // set the remote info for every snatIp
1✔
742
        for nodename, v := range agent.opflexSnatGlobalInfos {
2✔
743
                for _, ginfo := range v {
2✔
744
                        if nodename != agent.config.NodeName {
2✔
745
                                var remote OpflexSnatIpRemoteInfo
1✔
746
                                remote.MacAddress = ginfo.MacAddress
1✔
747
                                remote.PortRange = ginfo.PortRange
1✔
748
                                remoteinfo[ginfo.SnatIp] = append(remoteinfo[ginfo.SnatIp], remote)
1✔
749
                        }
1✔
750
                }
751
        }
752
        agent.log.Debug("Opflex SnatIp RemoteInfo map is: ", remoteinfo)
1✔
753
        // set the Opflex Snat IP information
1✔
754
        localportrange := make(map[string][]OpflexPortRange)
1✔
755
        ginfos, ok := agent.opflexSnatGlobalInfos[agent.config.NodeName]
1✔
756

1✔
757
        if ok {
2✔
758
                for _, ginfo := range ginfos {
2✔
759
                        localportrange[ginfo.SnatIp] = ginfo.PortRange
1✔
760
                }
1✔
761
        }
762

763
        for _, v := range agent.opflexSnatGlobalInfos {
2✔
764
                for _, ginfo := range v {
2✔
765
                        var snatinfo OpflexSnatIp
1✔
766
                        // set the local portrange
1✔
767
                        snatinfo.InterfaceName = agent.config.UplinkIface
1✔
768
                        snatinfo.InterfaceVlan = agent.config.ServiceVlan
1✔
769
                        snatinfo.InterfaceMac = agent.config.UplinkMacAdress
1✔
770
                        snatinfo.Local = false
1✔
771
                        if _, ok := localportrange[ginfo.SnatIp]; ok {
2✔
772
                                snatinfo.PortRange = localportrange[ginfo.SnatIp]
1✔
773
                                // need to sort the order
1✔
774
                                agent.snatPolicyCacheMutex.RLock()
1✔
775
                                if _, ok := agent.snatPolicyCache[ginfo.SnatPolicyName]; ok {
2✔
776
                                        if len(agent.snatPolicyCache[ginfo.SnatPolicyName].Spec.DestIp) == 0 {
1✔
777
                                                snatinfo.DestIpAddress = []string{"0.0.0.0/0"}
×
778
                                        } else {
1✔
779
                                                snatinfo.DestIpAddress =
1✔
780
                                                        agent.snatPolicyCache[ginfo.SnatPolicyName].Spec.DestIp
1✔
781
                                        }
1✔
782
                                }
783
                                agent.snatPolicyCacheMutex.RUnlock()
1✔
784
                                snatinfo.Local = true
1✔
785
                        }
786
                        snatinfo.SnatIp = ginfo.SnatIp
1✔
787
                        snatinfo.Uuid = ginfo.SnatIpUid
1✔
788
                        snatinfo.Zone = agent.config.Zone
1✔
789
                        snatinfo.Remote = remoteinfo[ginfo.SnatIp]
1✔
790
                        opflexSnatIps[ginfo.SnatIpUid] = &snatinfo
1✔
791
                        agent.log.Debug("Opflex Snat data IP: ", opflexSnatIps[ginfo.SnatIpUid])
1✔
792
                }
793
        }
794
        agent.indexMutex.Unlock()
1✔
795
        files, err := os.ReadDir(agent.config.OpFlexSnatDir)
1✔
796
        if err != nil {
1✔
797
                agent.log.WithFields(
×
798
                        logrus.Fields{"SnatDir: ": agent.config.OpFlexSnatDir},
×
799
                ).Error("Could not read directory " + err.Error())
×
800
                return true
×
801
        }
×
802
        seen := make(map[string]bool)
1✔
803
        for _, f := range files {
2✔
804
                uuid := f.Name()
1✔
805
                if strings.HasSuffix(uuid, ".snat") {
2✔
806
                        uuid = uuid[:len(uuid)-5]
1✔
807
                } else {
2✔
808
                        continue
1✔
809
                }
810

811
                snatfile := filepath.Join(agent.config.OpFlexSnatDir, f.Name())
1✔
812
                logger := agent.log.WithFields(
1✔
813
                        logrus.Fields{"Uuid": uuid})
1✔
814
                existing, ok := opflexSnatIps[uuid]
1✔
815
                if ok {
2✔
816
                        agent.log.Debugf("snatfile:%s\n", snatfile)
1✔
817
                        wrote, err := writeSnat(snatfile, existing)
1✔
818
                        if err != nil {
1✔
819
                                opflexSnatIpLogger(agent.log, existing).Error("Error writing snat file: ", err)
×
820
                        } else if wrote {
2✔
821
                                opflexSnatIpLogger(agent.log, existing).Info("Updated snat")
1✔
822
                        }
1✔
823
                        seen[uuid] = true
1✔
824
                } else {
×
825
                        logger.Info("Removing snat ", snatfile)
×
826
                        os.Remove(snatfile)
×
827
                }
×
828
        }
829
        for _, snat := range opflexSnatIps {
2✔
830
                if seen[snat.Uuid] {
2✔
831
                        continue
1✔
832
                }
833
                opflexSnatIpLogger(agent.log, snat).Info("Adding Snat")
1✔
834
                snatfile :=
1✔
835
                        agent.FormSnatFilePath(snat.Uuid)
1✔
836
                _, err = writeSnat(snatfile, snat)
1✔
837
                if err != nil {
1✔
838
                        opflexSnatIpLogger(agent.log, snat).
×
839
                                Error("Error writing snat file: ", err)
×
840
                }
×
841
        }
842
        agent.log.Debug("Finished snat sync")
1✔
843
        return false
1✔
844
}
845

846
// Get the Pods matching the Object selector
847
func (agent *HostAgent) getPodsMatchingObject(obj interface{}, policyname string) (poduids []string, res ResourceType) {
1✔
848
        metadata, err := meta.Accessor(obj)
1✔
849
        if err != nil {
1✔
850
                return
×
851
        }
×
852
        if !agent.isPolicyNameSpaceMatches(policyname, metadata.GetNamespace()) {
1✔
853
                return
×
854
        }
×
855
        switch obj := obj.(type) {
1✔
856
        case *v1.Pod:
1✔
857
                poduids = append(poduids, string(obj.ObjectMeta.UID))
1✔
858
                if len(poduids) != 0 {
2✔
859
                        agent.log.Info("Matching pod uids: ", poduids)
1✔
860
                }
1✔
861
        case *appsv1.Deployment:
×
862
                depkey, _ :=
×
863
                        cache.MetaNamespaceKeyFunc(obj)
×
864
                for _, podkey := range agent.depPods.GetPodForObj(depkey) {
×
865
                        podobj, exists, err := agent.podInformer.GetStore().GetByKey(podkey)
×
866
                        if err != nil {
×
867
                                agent.log.Error("Could not lookup pod: ", err)
×
868
                                continue
×
869
                        }
870
                        if !exists || podobj == nil {
×
871
                                agent.log.Error("Object doesn't exist yet ", podkey)
×
872
                                continue
×
873
                        }
874
                        poduids = append(poduids, string(podobj.(*v1.Pod).ObjectMeta.UID))
×
875
                }
876
                if len(poduids) != 0 {
×
877
                        agent.log.Info("Matching deployment pod uids: ", poduids)
×
878
                }
×
879
                res = DEPLOYMENT
×
880
        case *v1.Service:
1✔
881
                selector := labels.SelectorFromSet(obj.Spec.Selector)
1✔
882
                cache.ListAllByNamespace(agent.podInformer.GetIndexer(),
1✔
883
                        obj.ObjectMeta.Namespace, selector,
1✔
884
                        func(podobj interface{}) {
2✔
885
                                pod := podobj.(*v1.Pod)
1✔
886
                                if pod.Spec.NodeName == agent.config.NodeName {
2✔
887
                                        poduids = append(poduids, string(pod.ObjectMeta.UID))
1✔
888
                                }
1✔
889
                        })
890
                if len(poduids) != 0 {
2✔
891
                        agent.log.Info("Matching service pod uids: ", poduids)
1✔
892
                }
1✔
893
                res = SERVICE
1✔
894
        case *v1.Namespace:
×
895
                cache.ListAllByNamespace(agent.podInformer.GetIndexer(),
×
896
                        obj.ObjectMeta.Name, labels.Everything(),
×
897
                        func(podobj interface{}) {
×
898
                                pod := podobj.(*v1.Pod)
×
899
                                if pod.Spec.NodeName == agent.config.NodeName {
×
900
                                        poduids = append(poduids, string(pod.ObjectMeta.UID))
×
901
                                }
×
902
                        })
903
                if len(poduids) != 0 {
×
904
                        agent.log.Info("Matching namespace pod uids: ", poduids)
×
905
                }
×
906
                res = NAMESPACE
×
907
        default:
×
908
        }
909
        return
1✔
910
}
911

912
// Updates the EPFile with Snatuuid's
913
func (agent *HostAgent) updateEpFiles(poduids []string) {
1✔
914
        syncEp := false
1✔
915
        for _, uid := range poduids {
2✔
916
                localinfo, ok := agent.opflexSnatLocalInfos[uid]
1✔
917
                if !ok {
1✔
918
                        continue
×
919
                }
920
                var i uint = 1
1✔
921
                var pos uint = 0
1✔
922
                var policystack []string
1✔
923
                // 1. loop through all the resource hierarchy
1✔
924
                // 2. Compute the Policy Stack
1✔
925
                for ; i <= uint(CLUSTER); i = 1 << pos {
2✔
926
                        pos++
1✔
927
                        seen := make(map[string]bool)
1✔
928
                        policies, ok := localinfo.Snatpolicies[ResourceType(i)]
1✔
929
                        var sortedpolicies []string
1✔
930
                        if ok {
2✔
931
                                for _, name := range policies {
2✔
932
                                        if _, ok := seen[name]; !ok {
2✔
933
                                                seen[name] = true
1✔
934
                                                sortedpolicies = append(sortedpolicies, name)
1✔
935
                                        } else {
1✔
936
                                                continue
×
937
                                        }
938
                                }
939
                                sort.Slice(sortedpolicies,
1✔
940
                                        func(i, j int) bool {
2✔
941
                                                return agent.compare(sortedpolicies[i], sortedpolicies[j])
1✔
942
                                        })
1✔
943
                        }
944
                        policystack = append(policystack, sortedpolicies...)
1✔
945
                }
946
                var uids []string
1✔
947
                for _, name := range policystack {
2✔
948
                        for _, val := range agent.opflexSnatGlobalInfos[agent.config.NodeName] {
2✔
949
                                if val.SnatPolicyName == name {
2✔
950
                                        uids = append(uids, val.SnatIpUid)
1✔
951
                                }
1✔
952
                        }
953
                        if len(agent.snatPolicyCache[name].Spec.DestIp) == 0 {
1✔
954
                                break
×
955
                        }
956
                }
957
                if !reflect.DeepEqual(agent.opflexSnatLocalInfos[uid].PlcyUuids, uids) {
2✔
958
                        agent.log.Debug("Update EpFile: ", uids)
1✔
959
                        agent.opflexSnatLocalInfos[uid].Existing = false
1✔
960
                        agent.opflexSnatLocalInfos[uid].PlcyUuids = uids
1✔
961
                        if len(uids) == 0 {
2✔
962
                                delete(agent.opflexSnatLocalInfos, uid)
1✔
963
                        }
1✔
964
                        syncEp = true
1✔
965
                }
966
        }
967
        if syncEp {
2✔
968
                agent.scheduleSyncEps()
1✔
969
        }
1✔
970
        agent.scheduleSyncLocalInfo()
1✔
971
}
972

973
func (agent *HostAgent) compare(plcy1, plcy2 string) bool {
1✔
974
        sort := false
1✔
975
        for _, a := range agent.snatPolicyCache[plcy1].Spec.DestIp {
2✔
976
                ip_temp := net.ParseIP(a)
1✔
977
                if ip_temp != nil && ip_temp.To4() != nil {
1✔
978
                        a += "/32"
×
979
                }
×
980
                for _, b := range agent.snatPolicyCache[plcy2].Spec.DestIp {
2✔
981
                        ip_temp := net.ParseIP(b)
1✔
982
                        if ip_temp != nil && ip_temp.To4() != nil {
1✔
983
                                b += "/32"
×
984
                        }
×
985
                        // TODO need to handle if the order is reversed across the policies.
986
                        // order reversing is ideally a wrong config. may be we need to block at verfication level
987
                        if compareIps(a, b) {
2✔
988
                                sort = true
1✔
989
                        }
1✔
990
                }
991
        }
992
        return sort
1✔
993
}
994

995
func (agent *HostAgent) getMatchingServices(namespace string, label map[string]string) []*v1.Service {
×
996
        var services, matchingServices []*v1.Service
×
997
        cache.ListAllByNamespace(agent.serviceInformer.GetIndexer(), namespace, labels.Everything(),
×
998
                func(servobj interface{}) {
×
999
                        services = append(services, servobj.(*v1.Service))
×
1000
                })
×
1001
        for _, service := range services {
×
1002
                if service.Spec.Selector == nil {
×
1003
                        continue
×
1004
                }
1005
                svcSelector := labels.SelectorFromSet(service.Spec.Selector)
×
1006
                if svcSelector.Matches(labels.Set(label)) {
×
1007
                        matchingServices = append(matchingServices, service)
×
1008
                }
×
1009
        }
1010

1011
        return matchingServices
×
1012
}
1013

1014
// Must acquire snatPolicyCacheMutex.RLock
1015
func (agent *HostAgent) getMatchingSnatPolicy(obj interface{}) (snatPolicyNames map[string][]ResourceType) {
1✔
1016
        snatPolicyNames = make(map[string][]ResourceType)
1✔
1017
        _, err := agent.MetaNamespaceUIDFunc(obj)
1✔
1018
        if err != nil {
1✔
1019
                return
×
1020
        }
×
1021
        metadata, err := meta.Accessor(obj)
1✔
1022
        if err != nil {
1✔
1023
                return
×
1024
        }
×
1025
        namespace := metadata.GetNamespace()
1✔
1026
        label := metadata.GetLabels()
1✔
1027
        name := metadata.GetName()
1✔
1028
        res := getResourceType(obj)
1✔
1029
        for _, item := range agent.snatPolicyCache {
2✔
1030
                // check for empty policy selctor
1✔
1031
                if reflect.DeepEqual(item.Spec.Selector, snatpolicy.PodSelector{}) {
1✔
1032
                        snatPolicyNames[item.ObjectMeta.Name] =
×
1033
                                append(snatPolicyNames[item.ObjectMeta.Name], CLUSTER)
×
1034
                } else if len(item.Spec.Selector.Labels) == 0 &&
1✔
1035
                        item.Spec.Selector.Namespace == namespace { // check policy matches namespace
1✔
1036
                        if res == SERVICE {
×
1037
                                if len(item.Spec.SnatIp) == 0 {
×
1038
                                        snatPolicyNames[item.ObjectMeta.Name] =
×
1039
                                                append(snatPolicyNames[item.ObjectMeta.Name], SERVICE)
×
1040
                                }
×
1041
                        } else {
×
1042
                                if len(item.Spec.SnatIp) > 0 {
×
1043
                                        snatPolicyNames[item.ObjectMeta.Name] =
×
1044
                                                append(snatPolicyNames[item.ObjectMeta.Name], NAMESPACE)
×
1045
                                }
×
1046
                        }
1047
                } else { //Check Policy matches the labels on the Object
1✔
1048
                        if (item.Spec.Selector.Namespace != "" &&
1✔
1049
                                item.Spec.Selector.Namespace == namespace) ||
1✔
1050
                                (item.Spec.Selector.Namespace == "") {
2✔
1051
                                if util.MatchLabels(item.Spec.Selector.Labels, label) {
2✔
1052
                                        snatPolicyNames[item.ObjectMeta.Name] =
1✔
1053
                                                append(snatPolicyNames[item.ObjectMeta.Name], res)
1✔
1054
                                }
1✔
1055
                                if res == POD {
2✔
1056
                                        if len(item.Spec.SnatIp) == 0 {
1✔
1057
                                                matchingServices := agent.getMatchingServices(namespace, label)
×
1058
                                                agent.log.Debug("Matching services for pod ", name, " : ", matchingServices)
×
1059
                                                for _, matchingSvc := range matchingServices {
×
1060
                                                        if util.MatchLabels(item.Spec.Selector.Labels,
×
1061
                                                                matchingSvc.ObjectMeta.Labels) {
×
1062
                                                                snatPolicyNames[item.ObjectMeta.Name] =
×
1063
                                                                        append(snatPolicyNames[item.ObjectMeta.Name], SERVICE)
×
1064
                                                                break
×
1065
                                                        }
1066
                                                }
1067
                                        } else {
1✔
1068
                                                podKey, _ := cache.MetaNamespaceKeyFunc(obj)
1✔
1069
                                                for _, dpkey := range agent.depPods.GetObjForPod(podKey) {
2✔
1070
                                                        depobj, exists, err :=
1✔
1071
                                                                agent.depInformer.GetStore().GetByKey(dpkey)
1✔
1072
                                                        if err != nil {
1✔
1073
                                                                agent.log.Error("Could not lookup snat for " +
×
1074
                                                                        dpkey + ": " + err.Error())
×
1075
                                                                continue
×
1076
                                                        }
1077
                                                        if !exists || depobj == nil {
1✔
1078
                                                                continue
×
1079
                                                        }
1080
                                                        if util.MatchLabels(item.Spec.Selector.Labels,
1✔
1081
                                                                depobj.(*appsv1.Deployment).ObjectMeta.Labels) {
1✔
1082
                                                                snatPolicyNames[item.ObjectMeta.Name] =
×
1083
                                                                        append(snatPolicyNames[item.ObjectMeta.Name], DEPLOYMENT)
×
1084
                                                        }
×
1085
                                                }
1086
                                                nsobj, exists, err := agent.nsInformer.GetStore().GetByKey(namespace)
1✔
1087
                                                if err != nil {
1✔
1088
                                                        agent.log.Error("Could not lookup snat for " +
×
1089
                                                                namespace + ": " + err.Error())
×
1090
                                                        continue
×
1091
                                                }
1092
                                                if !exists || nsobj == nil {
1✔
1093
                                                        continue
×
1094
                                                }
1095
                                                if util.MatchLabels(item.Spec.Selector.Labels,
1✔
1096
                                                        nsobj.(*v1.Namespace).ObjectMeta.Labels) {
1✔
1097
                                                        snatPolicyNames[item.ObjectMeta.Name] =
×
1098
                                                                append(snatPolicyNames[item.ObjectMeta.Name], NAMESPACE)
×
1099
                                                }
×
1100
                                                // check for namespace match
1101
                                        }
1102
                                } else if res == DEPLOYMENT {
1✔
1103
                                        if len(item.Spec.SnatIp) == 0 {
×
1104
                                                matchingServices := agent.getMatchingServices(namespace, label)
×
1105
                                                agent.log.Debug("Matching services for deployment ", name, " : ", matchingServices)
×
1106
                                                for _, matchingSvc := range matchingServices {
×
1107
                                                        if util.MatchLabels(item.Spec.Selector.Labels,
×
1108
                                                                matchingSvc.ObjectMeta.Labels) {
×
1109
                                                                snatPolicyNames[item.ObjectMeta.Name] =
×
1110
                                                                        append(snatPolicyNames[item.ObjectMeta.Name], SERVICE)
×
1111
                                                                break
×
1112
                                                        }
1113
                                                }
1114
                                        } else {
×
1115
                                                dep := obj.(*appsv1.Deployment)
×
1116
                                                if dep.Spec.Selector != nil {
×
1117
                                                        var matchingPods []*v1.Pod
×
1118
                                                        depSelector, err := metav1.LabelSelectorAsSelector(dep.Spec.Selector)
×
1119
                                                        if err == nil {
×
1120
                                                                cache.ListAllByNamespace(agent.podInformer.GetIndexer(), namespace, depSelector,
×
1121
                                                                        func(podobj interface{}) {
×
1122
                                                                                matchingPods = append(matchingPods, podobj.(*v1.Pod))
×
1123
                                                                        })
×
1124
                                                                agent.log.Debug("Matching pods of deployment ", name, " : ", matchingPods)
×
1125
                                                                for _, po := range matchingPods {
×
1126
                                                                        if util.MatchLabels(item.Spec.Selector.Labels,
×
1127
                                                                                po.ObjectMeta.Labels) {
×
1128
                                                                                snatPolicyNames[item.ObjectMeta.Name] =
×
1129
                                                                                        append(snatPolicyNames[item.ObjectMeta.Name], POD)
×
1130
                                                                                break
×
1131
                                                                        }
1132
                                                                }
1133
                                                        } else {
×
1134
                                                                agent.log.Error(err.Error())
×
1135
                                                        }
×
1136
                                                }
1137

1138
                                                nsobj, exists, err := agent.nsInformer.GetStore().GetByKey(namespace)
×
1139
                                                if err != nil {
×
1140
                                                        agent.log.Error("Could not lookup snat for " +
×
1141
                                                                namespace + ": " + err.Error())
×
1142
                                                        continue
×
1143
                                                }
1144
                                                if !exists || nsobj == nil {
×
1145
                                                        continue
×
1146
                                                }
1147
                                                if util.MatchLabels(item.Spec.Selector.Labels,
×
1148
                                                        nsobj.(*v1.Namespace).ObjectMeta.Labels) {
×
1149
                                                        agent.log.Debug("Deployment namespace : ", nsobj.(*v1.Namespace).ObjectMeta.Name)
×
1150
                                                        snatPolicyNames[item.ObjectMeta.Name] =
×
1151
                                                                append(snatPolicyNames[item.ObjectMeta.Name], NAMESPACE)
×
1152
                                                }
×
1153
                                        }
1154
                                }
1155
                        }
1156
                }
1157
        }
1158
        return
1✔
1159
}
1160

1161
func (agent *HostAgent) isPresentInOpflexSnatLocalInfos(poduids []string, res ResourceType, name string) bool {
×
1162
        seen := true
×
1163
        for _, uid := range poduids {
×
1164
                localinfo, okUId := agent.opflexSnatLocalInfos[uid]
×
1165
                if !okUId {
×
1166
                        seen = false
×
1167
                        break
×
1168
                }
1169
                policies, okRes := localinfo.Snatpolicies[res]
×
1170
                if !okRes {
×
1171
                        seen = false
×
1172
                        break
×
1173
                }
1174
                found := false
×
1175
                for _, plcyname := range policies {
×
1176
                        if plcyname == name {
×
1177
                                found = true
×
1178
                                break
×
1179
                        }
1180
                }
1181
                if !found {
×
1182
                        seen = false
×
1183
                        break
×
1184
                }
1185
        }
1186
        return seen
×
1187
}
1188

1189
func (agent *HostAgent) handleObjectUpdateForSnat(obj interface{}) {
1✔
1190
        if getResourceType(obj) == POD {
2✔
1191
                if obj.(*v1.Pod).Status.Phase == v1.PodSucceeded {
1✔
1192
                        agent.handleObjectDeleteForSnat(obj)
×
1193
                        return
×
1194
                }
×
1195
        }
1196
        agent.snatPolicyCacheMutex.RLock()
1✔
1197
        defer agent.snatPolicyCacheMutex.RUnlock()
1✔
1198
        objKey, err := agent.MetaNamespaceUIDFunc(obj)
1✔
1199
        if err != nil {
1✔
1200
                agent.log.Error("Could not create snatUpdate object key:" + err.Error())
×
1201
                return
×
1202
        }
×
1203
        plcynames, ok := agent.ReadSnatPolicyLabel(objKey)
1✔
1204
        if !ok {
2✔
1205
                agent.WriteNewSnatPolicyLabel(objKey)
1✔
1206
        }
1✔
1207
        sync := false
1✔
1208
        if len(plcynames) == 0 {
2✔
1209
                polcies := agent.getMatchingSnatPolicy(obj)
1✔
1210
                for name, resources := range polcies {
2✔
1211
                        for _, res := range resources {
2✔
1212
                                poduids, _ := agent.getPodsMatchingObject(obj, name)
1✔
1213
                                if len(agent.snatPolicyCache[name].Spec.Selector.Labels) == 0 {
1✔
1214
                                        agent.applyPolicy(poduids, res, name)
×
1215
                                } else {
1✔
1216
                                        agent.applyPolicy(poduids, res, name)
1✔
1217
                                        agent.WriteSnatPolicyLabel(objKey, name, res)
1✔
1218
                                }
1✔
1219
                                if len(poduids) > 0 {
2✔
1220
                                        sync = true
1✔
1221
                                }
1✔
1222
                        }
1223
                }
1224
        } else {
1✔
1225
                var delpodlist []string
1✔
1226
                matchnames := agent.getMatchingSnatPolicy(obj)
1✔
1227
                agent.log.Info("HandleObject matching policies: ", matchnames)
1✔
1228
                seen := make(map[string]bool)
1✔
1229
                for name, res := range plcynames {
2✔
1230
                        poduids, _ := agent.getPodsMatchingObject(obj, name)
1✔
1231
                        if _, ok := matchnames[name]; !ok {
2✔
1232
                                for _, uid := range poduids {
2✔
1233
                                        agent.deleteSnatLocalInfo(uid, res, name)
1✔
1234
                                }
1✔
1235
                                delpodlist = append(delpodlist, poduids...)
1✔
1236
                                agent.DeleteSnatPolicyLabelEntry(objKey, name)
1✔
1237
                                seen[name] = true
1✔
1238
                        } else if agent.isPresentInOpflexSnatLocalInfos(poduids, res, name) {
×
1239
                                seen[name] = true
×
1240
                        }
×
1241
                }
1242
                if len(delpodlist) > 0 {
2✔
1243
                        agent.updateEpFiles(delpodlist)
1✔
1244
                        sync = true
1✔
1245
                }
1✔
1246
                for name, resources := range matchnames {
1✔
1247
                        if seen[name] {
×
1248
                                continue
×
1249
                        }
1250
                        for _, res := range resources {
×
1251
                                poduids, _ := agent.getPodsMatchingObject(obj, name)
×
1252
                                agent.applyPolicy(poduids, res, name)
×
1253
                                agent.WriteSnatPolicyLabel(objKey, name, res)
×
1254
                                sync = true
×
1255
                        }
×
1256
                }
1257
        }
1258
        if sync {
2✔
1259
                agent.scheduleSyncNodeInfo()
1✔
1260
        }
1✔
1261
}
1262

1263
func (agent *HostAgent) handleObjectDeleteForSnat(obj interface{}) {
1✔
1264
        objKey, err := agent.MetaNamespaceUIDFunc(obj)
1✔
1265
        if err != nil {
1✔
1266
                agent.log.Error("Could not create snatDelete object key:" + err.Error())
×
1267
                return
×
1268
        }
×
1269
        agent.snatPolicyCacheMutex.RLock()
1✔
1270
        plcynames := agent.getMatchingSnatPolicy(obj)
1✔
1271
        agent.snatPolicyCacheMutex.RUnlock()
1✔
1272
        var podidlist []string
1✔
1273
        sync := false
1✔
1274
        for name, resources := range plcynames {
2✔
1275
                agent.log.Infof("Handle snatpolicy as object deleted: %s, ObjectKey: %s", name, objKey)
1✔
1276
                agent.snatPolicyCacheMutex.RLock()
1✔
1277
                poduids, _ := agent.getPodsMatchingObject(obj, name)
1✔
1278
                agent.snatPolicyCacheMutex.RUnlock()
1✔
1279
                for _, uid := range poduids {
2✔
1280
                        if getResourceType(obj) == SERVICE {
2✔
1281
                                for _, res := range resources {
2✔
1282
                                        if res == SERVICE {
2✔
1283
                                                agent.deleteSnatLocalInfo(uid, res, name)
1✔
1284
                                                agent.log.Debug("Service deleted update the localInfo: ", name)
1✔
1285
                                        }
1✔
1286
                                }
1287
                        } else {
×
1288
                                delete(agent.opflexSnatLocalInfos, uid)
×
1289
                                delete(agent.snatPods[name], uid)
×
1290
                        }
×
1291
                }
1292
                podidlist = append(podidlist, poduids...)
1✔
1293
                sync = true
1✔
1294
        }
1295
        agent.DeleteSnatPolicyLabel(objKey)
1✔
1296
        // Delete any Policy entries present for POD
1✔
1297
        if getResourceType(obj) == POD {
2✔
1298
                uid := string(obj.(*v1.Pod).ObjectMeta.UID)
1✔
1299
                localinfo, ok := agent.opflexSnatLocalInfos[uid]
1✔
1300
                if ok {
1✔
1301
                        for _, policynames := range localinfo.Snatpolicies {
×
1302
                                for _, name := range policynames {
×
1303
                                        delete(agent.snatPods[name], uid)
×
1304
                                }
×
1305
                        }
1306
                        delete(agent.opflexSnatLocalInfos, uid)
×
1307
                        sync = true
×
1308
                }
1309
        }
1310
        if sync {
2✔
1311
                agent.scheduleSyncNodeInfo()
1✔
1312
                if getResourceType(obj) == SERVICE {
2✔
1313
                        agent.updateEpFiles(podidlist)
1✔
1314
                } else {
1✔
1315
                        agent.scheduleSyncEps()
×
1316
                        agent.scheduleSyncLocalInfo()
×
1317
                }
×
1318
        }
1319
}
1320

1321
func (agent *HostAgent) isPolicyNameSpaceMatches(policyName, namespace string) bool {
1✔
1322
        policy, ok := agent.snatPolicyCache[policyName]
1✔
1323
        if ok {
2✔
1324
                if len(policy.Spec.Selector.Namespace) == 0 || (len(policy.Spec.Selector.Namespace) > 0 &&
1✔
1325
                        policy.Spec.Selector.Namespace == namespace) {
2✔
1326
                        return true
1✔
1327
                }
1✔
1328
        }
1329
        return false
×
1330
}
1331

1332
func (agent *HostAgent) getSnatUuids(poduuid, epfile string) ([]string, error) {
1✔
1333
        localInfo := &opflexSnatLocalInfo{}
1✔
1334
        plcyUuids := []string{}
1✔
1335
        agent.indexMutex.Lock()
1✔
1336
        defer agent.indexMutex.Unlock()
1✔
1337
        val, check := agent.opflexSnatLocalInfos[poduuid]
1✔
1338
        if check {
2✔
1339
                if val.Existing {
1✔
1340
                        agent.log.Debug("Getting existing snat-uuids in ep file : ", epfile)
×
1341
                        agent.log.Debug("snat-uuids in opflexSnatLocalInfos : ", localInfo.PlcyUuids)
×
1342
                        currentEp, err := readEp(epfile)
×
1343
                        if err == nil && currentEp != nil {
×
1344
                                plcyUuids = currentEp.SnatUuid
×
1345
                                agent.log.Debug("snat-uuids in ep file : ", plcyUuids)
×
1346
                                return plcyUuids, nil
×
1347
                        }
×
1348
                }
1349
                err := util.DeepCopyObj(val, localInfo)
1✔
1350
                if err != nil {
1✔
1351
                        agent.log.Error(err.Error())
×
1352
                        return nil, err
×
1353
                }
×
1354
                plcyUuids = localInfo.PlcyUuids
1✔
1355
        }
1356
        return plcyUuids, nil
1✔
1357
}
1358

1359
func setDestIp(destIp []string) {
1✔
1360
        if len(destIp) > 0 {
2✔
1361
                sort.Slice(destIp, func(i, j int) bool {
2✔
1362
                        a := destIp[i]
1✔
1363
                        b := destIp[j]
1✔
1364
                        ip_temp := net.ParseIP(a)
1✔
1365
                        if ip_temp != nil && ip_temp.To4() != nil {
1✔
1366
                                a += "/32"
×
1367
                        }
×
1368
                        ip_temp = net.ParseIP(b)
1✔
1369
                        if ip_temp != nil && ip_temp.To4() != nil {
1✔
1370
                                b += "/32"
×
1371
                        }
×
1372
                        return compareIps(a, b)
1✔
1373
                })
1374
        }
1375
}
1376

1377
func compareIps(ipa, ipb string) bool {
1✔
1378
        ipB, ipnetB, _ := net.ParseCIDR(ipb)
1✔
1379
        _, ipnetA, _ := net.ParseCIDR(ipa)
1✔
1380
        if ipnetA.Contains(ipB) {
2✔
1381
                // if the Ipa contains the Ipb
1✔
1382
                //the above check can be true if example IP CIDR's are 10.10.0.0/16 10.10.0.0/24
1✔
1383
                // if ip's are equal check the masks
1✔
1384
                if ipnetA.IP.Equal(ipnetB.IP) {
2✔
1385
                        if bytes.Compare(ipnetA.Mask, ipnetB.Mask) > 0 {
2✔
1386
                                return true
1✔
1387
                        }
1✔
1388
                }
1389
                return false
1✔
1390
        }
1391
        return true
1✔
1392
}
1393

1394
func getResourceType(obj interface{}) ResourceType {
1✔
1395
        var res ResourceType
1✔
1396
        switch obj.(type) {
1✔
1397
        case *v1.Pod:
1✔
1398
                res = POD
1✔
1399
        case *appsv1.Deployment:
1✔
1400
                res = DEPLOYMENT
1✔
1401
        case *v1.Service:
1✔
1402
                res = SERVICE
1✔
1403
        case *v1.Namespace:
1✔
1404
                res = NAMESPACE
1✔
1405
        default:
×
1406
        }
1407
        return res
1✔
1408
}
1409

1410
type ExplicitKey string
1411

1412
func (agent *HostAgent) MetaNamespaceUIDFunc(obj interface{}) (string, error) {
1✔
1413
        if key, ok := obj.(ExplicitKey); ok {
1✔
1414
                return string(key), nil
×
1415
        }
×
1416
        meta, err := meta.Accessor(obj)
1✔
1417
        if err != nil {
1✔
1418
                return "", err
×
1419
        }
×
1420
        if len(meta.GetNamespace()) > 0 {
2✔
1421
                return meta.GetNamespace() + "/" + string(meta.GetUID()), nil
1✔
1422
        }
1✔
1423
        return string(meta.GetUID()), nil
1✔
1424
}
1425

1426
func difference(a, b []string) []string {
×
1427
        mb := make(map[string]struct{}, len(b))
×
1428
        for _, x := range b {
×
1429
                mb[x] = struct{}{}
×
1430
        }
×
1431
        var diff []string
×
1432
        for _, x := range a {
×
1433
                if _, found := mb[x]; !found {
×
1434
                        diff = append(diff, x)
×
1435
                }
×
1436
        }
1437
        return diff
×
1438
}
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

© 2025 Coveralls, Inc