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

noironetworks / aci-containers / 11290

06 Nov 2025 07:35AM UTC coverage: 64.838% (+0.2%) from 64.6%
11290

Pull #1620

travis-pro

burhan20
Fix mutilpe same vlan NAD after controller restart:
During scale testing, if there are multiple EPGs attached to an aaep with same vlan,
it will result in only one NAD for the same vlan EPGs.
However, after controller restart, one extra NAD was created for the same vlan.

The fix makes sures to check if there is any already present NAD with same vlan attached to same aaep in thr cluster
A new NAD will be created only if no such NAD is found
Pull Request #1620: Fix mutilpe same vlan NAD after controller restart:

0 of 67 new or added lines in 1 file covered. (0.0%)

100 existing lines in 2 files now uncovered.

13358 of 20602 relevant lines covered (64.84%)

0.74 hits per line

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

79.79
/pkg/controller/network_policy.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
// Handlers for network policy updates.  Generate ACI security groups
16
// based on Kubernetes network policies.
17

18
package controller
19

20
import (
21
        "bytes"
22
        "context"
23
        "fmt"
24
        "net"
25
        "os"
26
        "reflect"
27
        "slices"
28
        "sort"
29
        "strconv"
30
        "strings"
31

32
        "github.com/sirupsen/logrus"
33
        "github.com/yl2chen/cidranger"
34

35
        v1 "k8s.io/api/core/v1"
36
        v1net "k8s.io/api/networking/v1"
37
        "k8s.io/apimachinery/pkg/api/errors"
38
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
39
        "k8s.io/apimachinery/pkg/fields"
40
        "k8s.io/apimachinery/pkg/labels"
41
        "k8s.io/apimachinery/pkg/util/intstr"
42
        "k8s.io/client-go/kubernetes"
43
        "k8s.io/client-go/tools/cache"
44
        k8util "k8s.io/kubectl/pkg/util"
45

46
        "github.com/noironetworks/aci-containers/pkg/apicapi"
47
        hppv1 "github.com/noironetworks/aci-containers/pkg/hpp/apis/aci.hpp/v1"
48
        hppclset "github.com/noironetworks/aci-containers/pkg/hpp/clientset/versioned"
49
        "github.com/noironetworks/aci-containers/pkg/index"
50
        "github.com/noironetworks/aci-containers/pkg/ipam"
51
        "github.com/noironetworks/aci-containers/pkg/util"
52
        discovery "k8s.io/api/discovery/v1"
53
)
54

55
func (cont *AciController) initNetworkPolicyInformerFromClient(
56
        kubeClient kubernetes.Interface) {
×
57
        cont.initNetworkPolicyInformerBase(
×
58
                cache.NewListWatchFromClient(
×
59
                        kubeClient.NetworkingV1().RESTClient(), "networkpolicies",
×
60
                        metav1.NamespaceAll, fields.Everything()))
×
61
}
×
62

63
func (cont *AciController) initNetworkPolicyInformerBase(listWatch *cache.ListWatch) {
1✔
64
        cont.networkPolicyIndexer, cont.networkPolicyInformer =
1✔
65
                cache.NewIndexerInformer(
1✔
66
                        listWatch, &v1net.NetworkPolicy{}, 0,
1✔
67
                        cache.ResourceEventHandlerFuncs{
1✔
68
                                AddFunc: func(obj interface{}) {
2✔
69
                                        cont.networkPolicyAdded(obj)
1✔
70
                                },
1✔
71
                                UpdateFunc: func(oldobj interface{}, newobj interface{}) {
×
72
                                        cont.networkPolicyChanged(oldobj, newobj)
×
73
                                },
×
74
                                DeleteFunc: func(obj interface{}) {
1✔
75
                                        cont.networkPolicyDeleted(obj)
1✔
76
                                },
1✔
77
                        },
78
                        cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
79
                )
80
}
81

82
func (cont *AciController) peerPodSelector(np *v1net.NetworkPolicy,
83
        peers []v1net.NetworkPolicyPeer) []index.PodSelector {
1✔
84
        var ret []index.PodSelector
1✔
85
        for _, peer := range peers {
2✔
86
                podselector, err :=
1✔
87
                        metav1.LabelSelectorAsSelector(peer.PodSelector)
1✔
88
                if err != nil {
1✔
89
                        networkPolicyLogger(cont.log, np).
×
90
                                Error("Could not create selector: ", err)
×
91
                        continue
×
92
                }
93
                nsselector, err := metav1.
1✔
94
                        LabelSelectorAsSelector(peer.NamespaceSelector)
1✔
95
                if err != nil {
1✔
96
                        networkPolicyLogger(cont.log, np).
×
97
                                Error("Could not create selector: ", err)
×
98
                        continue
×
99
                }
100

101
                switch {
1✔
102
                case peer.PodSelector != nil && peer.NamespaceSelector != nil:
1✔
103
                        ret = append(ret, index.PodSelector{
1✔
104
                                NsSelector:  nsselector,
1✔
105
                                PodSelector: podselector,
1✔
106
                        })
1✔
107
                case peer.PodSelector != nil:
1✔
108
                        ret = append(ret, index.PodSelector{
1✔
109
                                Namespace:   &np.ObjectMeta.Namespace,
1✔
110
                                PodSelector: podselector,
1✔
111
                        })
1✔
112
                case peer.NamespaceSelector != nil:
1✔
113
                        ret = append(ret, index.PodSelector{
1✔
114
                                NsSelector:  nsselector,
1✔
115
                                PodSelector: labels.Everything(),
1✔
116
                        })
1✔
117
                }
118
        }
119
        return ret
1✔
120
}
121

122
func (cont *AciController) egressPodSelector(np *v1net.NetworkPolicy) []index.PodSelector {
1✔
123
        var ret []index.PodSelector
1✔
124

1✔
125
        for _, egress := range np.Spec.Egress {
2✔
126
                ret = append(ret, cont.peerPodSelector(np, egress.To)...)
1✔
127
        }
1✔
128

129
        return ret
1✔
130
}
131

132
func (cont *AciController) ingressPodSelector(np *v1net.NetworkPolicy) []index.PodSelector {
1✔
133
        var ret []index.PodSelector
1✔
134

1✔
135
        for _, ingress := range np.Spec.Ingress {
2✔
136
                ret = append(ret, cont.peerPodSelector(np, ingress.From)...)
1✔
137
        }
1✔
138

139
        return ret
1✔
140
}
141

142
func (cont *AciController) initNetPolPodIndex() {
1✔
143
        cont.netPolPods = index.NewPodSelectorIndex(
1✔
144
                cont.log,
1✔
145
                cont.podIndexer, cont.namespaceIndexer, cont.networkPolicyIndexer,
1✔
146
                cache.MetaNamespaceKeyFunc,
1✔
147
                func(obj interface{}) []index.PodSelector {
2✔
148
                        np := obj.(*v1net.NetworkPolicy)
1✔
149
                        return index.PodSelectorFromNsAndSelector(np.ObjectMeta.Namespace,
1✔
150
                                &np.Spec.PodSelector)
1✔
151
                },
1✔
152
        )
153
        cont.netPolPods.SetPodUpdateCallback(func(podkey string) {
2✔
154
                podobj, exists, err := cont.podIndexer.GetByKey(podkey)
1✔
155
                if exists && err == nil {
2✔
156
                        cont.queuePodUpdate(podobj.(*v1.Pod))
1✔
157
                }
1✔
158
        })
159

160
        cont.netPolIngressPods = index.NewPodSelectorIndex(
1✔
161
                cont.log,
1✔
162
                cont.podIndexer, cont.namespaceIndexer, cont.networkPolicyIndexer,
1✔
163
                cache.MetaNamespaceKeyFunc,
1✔
164
                func(obj interface{}) []index.PodSelector {
2✔
165
                        return cont.ingressPodSelector(obj.(*v1net.NetworkPolicy))
1✔
166
                },
1✔
167
        )
168
        cont.netPolEgressPods = index.NewPodSelectorIndex(
1✔
169
                cont.log,
1✔
170
                cont.podIndexer, cont.namespaceIndexer, cont.networkPolicyIndexer,
1✔
171
                cache.MetaNamespaceKeyFunc,
1✔
172
                func(obj interface{}) []index.PodSelector {
2✔
173
                        return cont.egressPodSelector(obj.(*v1net.NetworkPolicy))
1✔
174
                },
1✔
175
        )
176
        npupdate := func(npkey string) {
2✔
177
                npobj, exists, err := cont.networkPolicyIndexer.GetByKey(npkey)
1✔
178
                if exists && err == nil {
2✔
179
                        cont.queueNetPolUpdate(npobj.(*v1net.NetworkPolicy))
1✔
180
                }
1✔
181
        }
182
        nphash := func(pod *v1.Pod) string {
2✔
183
                return pod.Status.PodIP
1✔
184
        }
1✔
185

186
        remipupdate := func(pod *v1.Pod, deleted bool) {
2✔
187
                cont.queueRemoteIpConUpdate(pod, deleted)
1✔
188
        }
1✔
189

190
        cont.netPolIngressPods.SetObjUpdateCallback(npupdate)
1✔
191
        cont.netPolIngressPods.SetRemIpUpdateCallback(remipupdate)
1✔
192
        cont.netPolIngressPods.SetPodHashFunc(nphash)
1✔
193
        cont.netPolEgressPods.SetObjUpdateCallback(npupdate)
1✔
194
        cont.netPolEgressPods.SetRemIpUpdateCallback(remipupdate)
1✔
195
        cont.netPolEgressPods.SetPodHashFunc(nphash)
1✔
196
}
197

198
func (cont *AciController) staticNetPolObjs() apicapi.ApicSlice {
1✔
199
        hppIngress :=
1✔
200
                apicapi.NewHostprotPol(cont.config.AciPolicyTenant,
1✔
201
                        cont.aciNameForKey("np", "static-ingress"))
1✔
202
        {
2✔
203
                ingressSubj := apicapi.NewHostprotSubj(hppIngress.GetDn(), "ingress")
1✔
204
                if !cont.configuredPodNetworkIps.V6.Empty() {
2✔
205
                        outbound := apicapi.NewHostprotRule(ingressSubj.GetDn(),
1✔
206
                                "allow-all-reflexive-v6")
1✔
207
                        outbound.SetAttr("direction", "ingress")
1✔
208
                        outbound.SetAttr("ethertype", "ipv6")
1✔
209
                        ingressSubj.AddChild(outbound)
1✔
210
                }
1✔
211
                if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
212
                        outbound := apicapi.NewHostprotRule(ingressSubj.GetDn(),
1✔
213
                                "allow-all-reflexive")
1✔
214
                        outbound.SetAttr("direction", "ingress")
1✔
215
                        outbound.SetAttr("ethertype", "ipv4")
1✔
216
                        ingressSubj.AddChild(outbound)
1✔
217
                }
1✔
218
                hppIngress.AddChild(ingressSubj)
1✔
219
        }
220

221
        hppEgress :=
1✔
222
                apicapi.NewHostprotPol(cont.config.AciPolicyTenant,
1✔
223
                        cont.aciNameForKey("np", "static-egress"))
1✔
224
        {
2✔
225
                egressSubj := apicapi.NewHostprotSubj(hppEgress.GetDn(), "egress")
1✔
226
                if !cont.configuredPodNetworkIps.V6.Empty() {
2✔
227
                        outbound := apicapi.NewHostprotRule(egressSubj.GetDn(),
1✔
228
                                "allow-all-reflexive-v6")
1✔
229
                        outbound.SetAttr("direction", "egress")
1✔
230
                        outbound.SetAttr("ethertype", "ipv6")
1✔
231
                        egressSubj.AddChild(outbound)
1✔
232
                }
1✔
233
                if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
234
                        outbound := apicapi.NewHostprotRule(egressSubj.GetDn(),
1✔
235
                                "allow-all-reflexive")
1✔
236
                        outbound.SetAttr("direction", "egress")
1✔
237
                        outbound.SetAttr("ethertype", "ipv4")
1✔
238
                        egressSubj.AddChild(outbound)
1✔
239
                }
1✔
240
                hppEgress.AddChild(egressSubj)
1✔
241
        }
242

243
        hppDiscovery :=
1✔
244
                apicapi.NewHostprotPol(cont.config.AciPolicyTenant,
1✔
245
                        cont.aciNameForKey("np", "static-discovery"))
1✔
246
        {
2✔
247
                discSubj := apicapi.NewHostprotSubj(hppDiscovery.GetDn(), "discovery")
1✔
248
                discDn := discSubj.GetDn()
1✔
249
                {
2✔
250
                        arpin := apicapi.NewHostprotRule(discDn, "arp-ingress")
1✔
251
                        arpin.SetAttr("direction", "ingress")
1✔
252
                        arpin.SetAttr("ethertype", "arp")
1✔
253
                        arpin.SetAttr("connTrack", "normal")
1✔
254
                        discSubj.AddChild(arpin)
1✔
255
                }
1✔
256
                {
1✔
257
                        arpout := apicapi.NewHostprotRule(discDn, "arp-egress")
1✔
258
                        arpout.SetAttr("direction", "egress")
1✔
259
                        arpout.SetAttr("ethertype", "arp")
1✔
260
                        arpout.SetAttr("connTrack", "normal")
1✔
261
                        discSubj.AddChild(arpout)
1✔
262
                }
1✔
263
                if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
264
                        icmpin := apicapi.NewHostprotRule(discDn, "icmp-ingress")
1✔
265
                        icmpin.SetAttr("direction", "ingress")
1✔
266
                        icmpin.SetAttr("ethertype", "ipv4")
1✔
267
                        icmpin.SetAttr("protocol", "icmp")
1✔
268
                        icmpin.SetAttr("connTrack", "normal")
1✔
269
                        discSubj.AddChild(icmpin)
1✔
270
                }
1✔
271

272
                if !cont.configuredPodNetworkIps.V6.Empty() {
2✔
273
                        icmpin := apicapi.NewHostprotRule(discDn, "icmpv6-ingress")
1✔
274
                        icmpin.SetAttr("direction", "ingress")
1✔
275
                        icmpin.SetAttr("ethertype", "ipv6")
1✔
276
                        icmpin.SetAttr("protocol", "icmpv6")
1✔
277
                        icmpin.SetAttr("connTrack", "normal")
1✔
278
                        discSubj.AddChild(icmpin)
1✔
279
                }
1✔
280
                if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
281
                        icmpout := apicapi.NewHostprotRule(discDn, "icmp-egress")
1✔
282
                        icmpout.SetAttr("direction", "egress")
1✔
283
                        icmpout.SetAttr("ethertype", "ipv4")
1✔
284
                        icmpout.SetAttr("protocol", "icmp")
1✔
285
                        icmpout.SetAttr("connTrack", "normal")
1✔
286
                        discSubj.AddChild(icmpout)
1✔
287
                }
1✔
288

289
                if !cont.configuredPodNetworkIps.V6.Empty() {
2✔
290
                        icmpout := apicapi.NewHostprotRule(discDn, "icmpv6-egress")
1✔
291
                        icmpout.SetAttr("direction", "egress")
1✔
292
                        icmpout.SetAttr("ethertype", "ipv6")
1✔
293
                        icmpout.SetAttr("protocol", "icmpv6")
1✔
294
                        icmpout.SetAttr("connTrack", "normal")
1✔
295
                        discSubj.AddChild(icmpout)
1✔
296
                }
1✔
297

298
                hppDiscovery.AddChild(discSubj)
1✔
299
        }
300

301
        return apicapi.ApicSlice{hppIngress, hppEgress, hppDiscovery}
1✔
302
}
303

304
func (cont *AciController) getHppClient() (hppclset.Interface, bool) {
1✔
305
        env := cont.env.(*K8sEnvironment)
1✔
306
        hppcl := env.hppClient
1✔
307
        if hppcl == nil {
2✔
308
                cont.log.Error("hpp client not found")
1✔
309
                return nil, false
1✔
310
        }
1✔
311
        return hppcl, true
1✔
312
}
313

314
func (cont *AciController) validateHppCr(hpp *hppv1.HostprotPol) bool {
1✔
315
        allowedProtocols := map[string]bool{
1✔
316
                "tcp":         true,
1✔
317
                "udp":         true,
1✔
318
                "icmp":        true,
1✔
319
                "icmpv6":      true,
1✔
320
                "unspecified": true,
1✔
321
        }
1✔
322

1✔
323
        for _, subj := range hpp.Spec.HostprotSubj {
2✔
324
                for _, rule := range subj.HostprotRule {
2✔
325
                        if rule.Protocol != "" {
2✔
326
                                if !allowedProtocols[rule.Protocol] {
1✔
327
                                        cont.log.Error("unknown protocol value: ", rule.Protocol, ", hostprotPol CR: ", hpp)
×
328
                                        return false
×
329
                                }
×
330
                        }
331
                }
332
        }
333
        return true
1✔
334
}
335

336
func (cont *AciController) createHostprotPol(hpp *hppv1.HostprotPol, ns string) bool {
1✔
337
        if !cont.validateHppCr(hpp) {
1✔
338
                return false
×
339
        }
×
340
        hppcl, ok := cont.getHppClient()
1✔
341
        if !ok {
2✔
342
                return false
1✔
343
        }
1✔
344

345
        cont.log.Debug("Creating HPP CR: ", hpp)
1✔
346
        _, err := hppcl.AciV1().HostprotPols(ns).Create(context.TODO(), hpp, metav1.CreateOptions{})
1✔
347
        if err != nil {
1✔
348
                cont.log.Error("Error creating HPP CR: ", err)
×
349
                return false
×
350
        }
×
351

352
        return true
1✔
353
}
354

355
func (cont *AciController) updateHostprotPol(hpp *hppv1.HostprotPol, ns string) bool {
1✔
356
        if !cont.validateHppCr(hpp) {
1✔
357
                cont.deleteHostprotPol(hpp.Name, hpp.Namespace)
×
358
                return false
×
359
        }
×
360
        hppcl, ok := cont.getHppClient()
1✔
361
        if !ok {
2✔
362
                return false
1✔
363
        }
1✔
364

365
        cont.log.Debug("Updating HPP CR: ", hpp)
1✔
366
        _, err := hppcl.AciV1().HostprotPols(ns).Update(context.TODO(), hpp, metav1.UpdateOptions{})
1✔
367
        if err != nil {
1✔
368
                cont.log.Error("Error updating HPP CR: ", err)
×
369
                return false
×
370
        }
×
371

372
        return true
1✔
373
}
374

375
func (cont *AciController) deleteAllHostprotPol() error {
1✔
376
        sysNs := os.Getenv("SYSTEM_NAMESPACE")
1✔
377
        hppcl, ok := cont.getHppClient()
1✔
378
        if !ok {
1✔
379
                cont.log.Error("Failed to delete HostprotPol CRs")
×
380
                return fmt.Errorf("HppClient not initialized")
×
381
        }
×
382

383
        cont.log.Debug("Deleting all HostprotPol CRs")
1✔
384
        err := hppcl.AciV1().HostprotPols(sysNs).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
1✔
385
        if err != nil {
1✔
386
                cont.log.Error("Failed to delete HostprotPol CRs: ", err)
×
387
        }
×
388
        return err
1✔
389
}
390

391
func (cont *AciController) deleteHostprotPol(hppName string, ns string) bool {
1✔
392
        hppcl, ok := cont.getHppClient()
1✔
393
        if !ok {
2✔
394
                return false
1✔
395
        }
1✔
396

397
        cont.log.Debug("Deleting HPP CR: ", hppName)
1✔
398
        err := hppcl.AciV1().HostprotPols(ns).Delete(context.TODO(), hppName, metav1.DeleteOptions{})
1✔
399
        if err != nil {
1✔
400
                cont.log.Error("Error deleting HPP CR: ", err)
×
401
                return false
×
402
        }
×
403

404
        return true
1✔
405
}
406

407
func (cont *AciController) getHostprotPol(hppName string, ns string) (*hppv1.HostprotPol, error) {
1✔
408
        hppcl, ok := cont.getHppClient()
1✔
409
        if !ok {
2✔
410
                return nil, fmt.Errorf("hpp client not found")
1✔
411
        }
1✔
412

413
        hpp, err := hppcl.AciV1().HostprotPols(ns).Get(context.TODO(), hppName, metav1.GetOptions{})
1✔
414
        if err != nil {
2✔
415
                return nil, err
1✔
416
        }
1✔
417
        cont.log.Debug("HPP CR found: ", hpp)
1✔
418
        return hpp, nil
1✔
419
}
420

421
func (cont *AciController) getHostprotRemoteIpContainer(name, ns string) (*hppv1.HostprotRemoteIpContainer, error) {
1✔
422
        hppcl, ok := cont.getHppClient()
1✔
423
        if !ok {
2✔
424
                return nil, fmt.Errorf("hpp client not found")
1✔
425
        }
1✔
426

427
        hpp, err := hppcl.AciV1().HostprotRemoteIpContainers(ns).Get(context.TODO(), name, metav1.GetOptions{})
1✔
428
        if err != nil {
2✔
429
                cont.log.Error("Error getting HostprotRemoteIpContainers CR: ", err)
1✔
430
                return nil, err
1✔
431
        }
1✔
432
        cont.log.Debug("HostprotRemoteIpContainers CR found: ", hpp)
1✔
433
        return hpp, nil
1✔
434
}
435

436
func (cont *AciController) createHostprotRemoteIpContainer(hppIpCont *hppv1.HostprotRemoteIpContainer, ns string) bool {
1✔
437
        hppcl, ok := cont.getHppClient()
1✔
438
        if !ok {
2✔
439
                return false
1✔
440
        }
1✔
441

442
        cont.log.Debug("Creating HostprotRemoteIpContainer CR: ", hppIpCont)
1✔
443
        _, err := hppcl.AciV1().HostprotRemoteIpContainers(ns).Create(context.TODO(), hppIpCont, metav1.CreateOptions{})
1✔
444
        if err != nil {
1✔
445
                cont.log.Error("Error creating HostprotRemoteIpContainer CR: ", err)
×
446
                return false
×
447
        }
×
448

449
        return true
1✔
450
}
451

452
func (cont *AciController) updateHostprotRemoteIpContainer(hppIpCont *hppv1.HostprotRemoteIpContainer, ns string) bool {
1✔
453
        hppcl, ok := cont.getHppClient()
1✔
454
        if !ok {
2✔
455
                return false
1✔
456
        }
1✔
457

458
        cont.log.Debug("Updating HostprotRemoteIpContainer CR: ", hppIpCont)
1✔
459
        _, err := hppcl.AciV1().HostprotRemoteIpContainers(ns).Update(context.TODO(), hppIpCont, metav1.UpdateOptions{})
1✔
460
        if err != nil {
1✔
461
                cont.log.Error("Error updating HostprotRemoteIpContainer CR: ", err)
×
462
                return false
×
463
        }
×
464

465
        return true
1✔
466
}
467

468
func (cont *AciController) deleteAllHostprotRemoteIpContainers() error {
1✔
469
        sysNs := os.Getenv("SYSTEM_NAMESPACE")
1✔
470
        hppcl, ok := cont.getHppClient()
1✔
471
        if !ok {
1✔
472
                cont.log.Error("Failed to delete HostprotRemoteIpContainer CRs")
×
473
                return fmt.Errorf("HppClient not initialized")
×
474
        }
×
475

476
        cont.log.Debug("Deleting all HostprotRemoteIpContainer CRs")
1✔
477
        err := hppcl.AciV1().HostprotRemoteIpContainers(sysNs).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
1✔
478
        if err != nil {
1✔
479
                cont.log.Error("Failed to delete HostprotRemoteIpContainer CRs: ", err)
×
480
        }
×
481
        return err
1✔
482
}
483

484
func (cont *AciController) deleteHostprotRemoteIpContainer(hppIpContName string, ns string) bool {
1✔
485
        hppcl, ok := cont.getHppClient()
1✔
486
        if !ok {
2✔
487
                return false
1✔
488
        }
1✔
489

490
        cont.log.Debug("Deleting HostprotRemoteIpContainer CR: ", hppIpContName)
1✔
491
        err := hppcl.AciV1().HostprotRemoteIpContainers(ns).Delete(context.TODO(), hppIpContName, metav1.DeleteOptions{})
1✔
492
        if err != nil {
1✔
493
                cont.log.Error("Error deleting HostprotRemoteIpContainer CR: ", err)
×
494
                return false
×
495
        }
×
496

497
        return true
1✔
498
}
499

500
func (cont *AciController) listHostprotPol(ns string) (*hppv1.HostprotPolList, error) {
1✔
501
        hppcl, ok := cont.getHppClient()
1✔
502
        if !ok {
1✔
503
                return nil, fmt.Errorf("hpp client not found")
×
504
        }
×
505

506
        hpps, err := hppcl.AciV1().HostprotPols(ns).List(context.TODO(), metav1.ListOptions{})
1✔
507
        if err != nil {
2✔
508
                cont.log.Error("Error listing HPP CR: ", err)
1✔
509
                return nil, err
1✔
510
        }
1✔
511
        return hpps, nil
×
512
}
513

514
func (cont *AciController) listHostprotRemoteIpContainers(ns string) (*hppv1.HostprotRemoteIpContainerList, error) {
1✔
515
        hppcl, ok := cont.getHppClient()
1✔
516
        if !ok {
1✔
517
                return nil, fmt.Errorf("hpp client not found")
×
518
        }
×
519

520
        hpRemoteIpConts, err := hppcl.AciV1().HostprotRemoteIpContainers(ns).List(context.TODO(), metav1.ListOptions{})
1✔
521
        if err != nil {
2✔
522
                cont.log.Error("Error getting HostprotRemoteIpContainers CRs: ", err)
1✔
523
                return nil, err
1✔
524
        }
1✔
525
        return hpRemoteIpConts, nil
×
526
}
527

528
func (cont *AciController) createStaticNetPolCrs() bool {
1✔
529
        ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
530

1✔
531
        createPol := func(labelKey, subjName, direction string, rules []hppv1.HostprotRule) bool {
2✔
532
                hppName := strings.ReplaceAll(labelKey, "_", "-")
1✔
533
                if _, err := cont.getHostprotPol(hppName, ns); errors.IsNotFound(err) {
2✔
534
                        hpp := &hppv1.HostprotPol{
1✔
535
                                ObjectMeta: metav1.ObjectMeta{
1✔
536
                                        Name:      hppName,
1✔
537
                                        Namespace: ns,
1✔
538
                                },
1✔
539
                                Spec: hppv1.HostprotPolSpec{
1✔
540
                                        Name:            labelKey,
1✔
541
                                        NetworkPolicies: []string{labelKey},
1✔
542
                                        HostprotSubj: []hppv1.HostprotSubj{
1✔
543
                                                {
1✔
544
                                                        Name:         subjName,
1✔
545
                                                        HostprotRule: rules,
1✔
546
                                                },
1✔
547
                                        },
1✔
548
                                },
1✔
549
                        }
1✔
550
                        if !cont.createHostprotPol(hpp, ns) {
1✔
551
                                return false
×
552
                        }
×
553
                }
554
                return true
1✔
555
        }
556

557
        if !createPol(cont.aciNameForKey("np", "static-ingress"), "ingress", "ingress", cont.getHostprotRules("ingress")) {
1✔
558
                return false
×
559
        }
×
560
        if !createPol(cont.aciNameForKey("np", "static-egress"), "egress", "egress", cont.getHostprotRules("egress")) {
1✔
561
                return false
×
562
        }
×
563
        if !createPol(cont.aciNameForKey("np", "static-discovery"), "discovery", "discovery", cont.getDiscoveryRules()) {
1✔
564
                return false
×
565
        }
×
566

567
        return true
1✔
568
}
569

570
func (cont *AciController) getHostprotRules(direction string) []hppv1.HostprotRule {
1✔
571
        var rules []hppv1.HostprotRule
1✔
572
        outbound := hppv1.HostprotRule{
1✔
573
                ConnTrack: "reflexive",
1✔
574
                Protocol:  "unspecified",
1✔
575
                FromPort:  "unspecified",
1✔
576
                ToPort:    "unspecified",
1✔
577
                Direction: direction,
1✔
578
        }
1✔
579

1✔
580
        if !cont.configuredPodNetworkIps.V6.Empty() {
1✔
581
                outbound.Name = "allow-all-reflexive-v6"
×
582
                outbound.Ethertype = "ipv6"
×
583
                rules = append(rules, outbound)
×
584
        }
×
585
        if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
586
                outbound.Name = "allow-all-reflexive"
1✔
587
                outbound.Ethertype = "ipv4"
1✔
588
                rules = append(rules, outbound)
1✔
589
        }
1✔
590

591
        return rules
1✔
592
}
593

594
func (cont *AciController) getDiscoveryRules() []hppv1.HostprotRule {
1✔
595
        rules := []hppv1.HostprotRule{
1✔
596
                {
1✔
597
                        Name:      "arp-ingress",
1✔
598
                        Direction: "ingress",
1✔
599
                        Ethertype: "arp",
1✔
600
                        ConnTrack: "normal",
1✔
601
                },
1✔
602
                {
1✔
603
                        Name:      "arp-egress",
1✔
604
                        Direction: "egress",
1✔
605
                        Ethertype: "arp",
1✔
606
                        ConnTrack: "normal",
1✔
607
                },
1✔
608
        }
1✔
609

1✔
610
        if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
611
                rules = append(rules,
1✔
612
                        hppv1.HostprotRule{
1✔
613
                                Name:      "icmp-ingress",
1✔
614
                                Direction: "ingress",
1✔
615
                                Ethertype: "ipv4",
1✔
616
                                Protocol:  "icmp",
1✔
617
                                ConnTrack: "normal",
1✔
618
                        },
1✔
619
                        hppv1.HostprotRule{
1✔
620
                                Name:      "icmp-egress",
1✔
621
                                Direction: "egress",
1✔
622
                                Ethertype: "ipv4",
1✔
623
                                Protocol:  "icmp",
1✔
624
                                ConnTrack: "normal",
1✔
625
                        },
1✔
626
                )
1✔
627
        }
1✔
628

629
        if !cont.configuredPodNetworkIps.V6.Empty() {
1✔
630
                rules = append(rules,
×
631
                        hppv1.HostprotRule{
×
632
                                Name:      "icmpv6-ingress",
×
633
                                Direction: "ingress",
×
634
                                Ethertype: "ipv6",
×
635
                                Protocol:  "icmpv6",
×
636
                                ConnTrack: "normal",
×
637
                        },
×
638
                        hppv1.HostprotRule{
×
639
                                Name:      "icmpv6-egress",
×
640
                                Direction: "egress",
×
641
                                Ethertype: "ipv6",
×
642
                                Protocol:  "icmpv6",
×
643
                                ConnTrack: "normal",
×
644
                        },
×
645
                )
×
646
        }
×
647

648
        return rules
1✔
649
}
650

651
func (cont *AciController) cleanStaleHppCrs() {
1✔
652
        sysNs := os.Getenv("SYSTEM_NAMESPACE")
1✔
653
        npNames := make(map[string]struct{})
1✔
654

1✔
655
        namespaces, err := cont.listNamespaces()
1✔
656
        if err != nil {
1✔
657
                cont.log.Error("Error listing namespaces: ", err)
×
658
                return
×
659
        }
×
660

661
        for _, ns := range namespaces.Items {
1✔
662
                netpols, err := cont.listNetworkPolicies(ns.Name)
×
663
                if err != nil {
×
664
                        cont.log.Error("Error listing network policies in namespace ", ns.Name, ": ", err)
×
665
                        continue
×
666
                }
667
                for _, np := range netpols.Items {
×
668
                        nsName := np.ObjectMeta.Namespace + "/" + np.ObjectMeta.Name
×
669
                        npNames[nsName] = struct{}{}
×
670
                }
×
671
        }
672

673
        hpps, err := cont.listHostprotPol(sysNs)
1✔
674
        if err != nil {
2✔
675
                cont.log.Error("Error listing HostprotPols: ", err)
1✔
676
                return
1✔
677
        }
1✔
678

679
        for _, hpp := range hpps.Items {
×
680
                for _, npName := range hpp.Spec.NetworkPolicies {
×
681
                        if _, exists := npNames[npName]; !exists {
×
682
                                if !cont.deleteHostprotPol(hpp.ObjectMeta.Name, sysNs) {
×
683
                                        cont.log.Error("Error deleting stale HostprotPol: ", hpp.ObjectMeta.Name)
×
684
                                }
×
685
                        }
686
                }
687
        }
688
}
689

690
func (cont *AciController) cleanStaleHostprotRemoteIpContainers() {
1✔
691
        sysNs := os.Getenv("SYSTEM_NAMESPACE")
1✔
692
        nsNames := make(map[string]struct{})
1✔
693

1✔
694
        namespaces, err := cont.listNamespaces()
1✔
695
        if err != nil {
1✔
696
                cont.log.Error("Error listing namespaces: ", err)
×
697
                return
×
698
        }
×
699

700
        for _, ns := range namespaces.Items {
1✔
701
                nsNames[ns.Name] = struct{}{}
×
702
        }
×
703

704
        hpRemIpConts, err := cont.listHostprotRemoteIpContainers(sysNs)
1✔
705
        if err != nil {
2✔
706
                cont.log.Error("Error listing HostprotRemoteIpContainers: ", err)
1✔
707
                return
1✔
708
        }
1✔
709

710
        for _, hpRemIpCont := range hpRemIpConts.Items {
×
711
                if _, exists := nsNames[hpRemIpCont.ObjectMeta.Name]; !exists {
×
712
                        if !cont.deleteHostprotRemoteIpContainer(hpRemIpCont.ObjectMeta.Name, sysNs) {
×
713
                                cont.log.Error("Error deleting stale HostprotRemoteIpContainer: ", hpRemIpCont.ObjectMeta.Name)
×
714
                        }
×
715
                }
716
        }
717
}
718

719
func (cont *AciController) initStaticNetPolObjs() {
1✔
720
        if cont.config.EnableHppDirect {
2✔
721
                cont.cleanStaleHostprotRemoteIpContainers()
1✔
722
                cont.cleanStaleHppCrs()
1✔
723

1✔
724
                if !cont.createStaticNetPolCrs() {
1✔
725
                        cont.log.Error("Error creating static HPP CRs")
×
726
                }
×
727
                return
1✔
728
        } else {
1✔
729
                cont.deleteAllHostprotPol()
1✔
730
                cont.deleteAllHostprotRemoteIpContainers()
1✔
731
        }
1✔
732

733
        cont.apicConn.WriteApicObjects(cont.config.AciPrefix+"_np_static", cont.staticNetPolObjs())
1✔
734
}
735

736
func networkPolicyLogger(log *logrus.Logger,
737
        np *v1net.NetworkPolicy) *logrus.Entry {
1✔
738
        return log.WithFields(logrus.Fields{
1✔
739
                "namespace": np.ObjectMeta.Namespace,
1✔
740
                "name":      np.ObjectMeta.Name,
1✔
741
        })
1✔
742
}
1✔
743

744
func (cont *AciController) queueNetPolUpdateByKey(key string) {
1✔
745
        cont.netPolQueue.Add(key)
1✔
746
}
1✔
747

748
func (cont *AciController) queueRemoteIpConUpdate(pod *v1.Pod, deleted bool) {
1✔
749
        cont.hppMutex.Lock()
1✔
750
        update := cont.updateNsRemoteIpCont(pod, deleted)
1✔
751
        if update {
2✔
752
                podns := pod.ObjectMeta.Namespace
1✔
753
                cont.remIpContQueue.Add(podns)
1✔
754
        }
1✔
755
        cont.hppMutex.Unlock()
1✔
756
}
757

758
func (cont *AciController) queueNetPolUpdate(netpol *v1net.NetworkPolicy) {
1✔
759
        key, err := cache.MetaNamespaceKeyFunc(netpol)
1✔
760
        if err != nil {
1✔
761
                networkPolicyLogger(cont.log, netpol).
×
762
                        Error("Could not create network policy key: ", err)
×
763
                return
×
764
        }
×
765
        cont.netPolQueue.Add(key)
1✔
766
}
767

768
func (cont *AciController) peerMatchesPod(npNs string,
769
        peer *v1net.NetworkPolicyPeer, pod *v1.Pod, podNs *v1.Namespace) bool {
1✔
770
        if peer.PodSelector != nil && npNs == pod.ObjectMeta.Namespace {
2✔
771
                selector, err :=
1✔
772
                        metav1.LabelSelectorAsSelector(peer.PodSelector)
1✔
773
                if err != nil {
1✔
774
                        cont.log.Error("Could not parse pod selector: ", err)
×
775
                } else {
1✔
776
                        return selector.Matches(labels.Set(pod.ObjectMeta.Labels))
1✔
777
                }
1✔
778
        }
779
        if peer.NamespaceSelector != nil {
2✔
780
                selector, err :=
1✔
781
                        metav1.LabelSelectorAsSelector(peer.NamespaceSelector)
1✔
782
                if err != nil {
1✔
783
                        cont.log.Error("Could not parse namespace selector: ", err)
×
784
                } else {
1✔
785
                        match := selector.Matches(labels.Set(podNs.ObjectMeta.Labels))
1✔
786
                        if match && peer.PodSelector != nil {
2✔
787
                                podSelector, err :=
1✔
788
                                        metav1.LabelSelectorAsSelector(peer.PodSelector)
1✔
789
                                if err != nil {
1✔
790
                                        cont.log.Error("Could not parse pod selector: ", err)
×
791
                                } else {
1✔
792
                                        return podSelector.Matches(labels.Set(pod.ObjectMeta.Labels))
1✔
793
                                }
1✔
794
                        }
795
                        return match
1✔
796
                }
797
        }
798
        return false
×
799
}
800

801
func ipsForPod(pod *v1.Pod) []string {
1✔
802
        var ips []string
1✔
803
        podIPsField := reflect.ValueOf(pod.Status).FieldByName("PodIPs")
1✔
804
        if podIPsField.IsValid() {
2✔
805
                if len(pod.Status.PodIPs) > 0 {
1✔
806
                        for _, ip := range pod.Status.PodIPs {
×
807
                                ips = append(ips, ip.IP)
×
808
                        }
×
809
                        return ips
×
810
                }
811
        }
812
        if pod.Status.PodIP != "" {
2✔
813
                return []string{pod.Status.PodIP}
1✔
814
        }
1✔
815
        return nil
1✔
816
}
817

818
func ipBlockToSubnets(ipblock *v1net.IPBlock) ([]string, error) {
1✔
819
        _, nw, err := net.ParseCIDR(ipblock.CIDR)
1✔
820
        if err != nil {
1✔
821
                return nil, err
×
822
        }
×
823
        ips := ipam.New()
1✔
824
        ips.AddSubnet(nw)
1✔
825
        for _, except := range ipblock.Except {
2✔
826
                _, nw, err = net.ParseCIDR(except)
1✔
827
                if err != nil {
1✔
828
                        return nil, err
×
829
                }
×
830
                ips.RemoveSubnet(nw)
1✔
831
        }
832
        var subnets []string
1✔
833
        for _, r := range ips.FreeList {
2✔
834
                ipnets := ipam.Range2Cidr(r.Start, r.End)
1✔
835
                for _, n := range ipnets {
2✔
836
                        subnets = append(subnets, n.String())
1✔
837
                }
1✔
838
        }
839
        return subnets, nil
1✔
840
}
841

842
func parseCIDR(sub string) *net.IPNet {
1✔
843
        _, netw, err := net.ParseCIDR(sub)
1✔
844
        if err == nil {
2✔
845
                return netw
1✔
846
        }
1✔
847
        ip := net.ParseIP(sub)
1✔
848
        if ip == nil {
1✔
849
                return nil
×
850
        }
×
851
        var mask net.IPMask
1✔
852
        if ip.To4() != nil {
2✔
853
                mask = net.CIDRMask(32, 32)
1✔
854
        } else if ip.To16() != nil {
3✔
855
                mask = net.CIDRMask(128, 128)
1✔
856
        } else {
1✔
857
                return nil
×
858
        }
×
859
        return &net.IPNet{
1✔
860
                IP:   ip,
1✔
861
                Mask: mask,
1✔
862
        }
1✔
863
}
864

865
func netEqual(a, b net.IPNet) bool {
1✔
866
        return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask)
1✔
867
}
1✔
868

869
func (cont *AciController) updateIpIndexEntry(index cidranger.Ranger,
870
        subnetStr string, key string, add bool) bool {
1✔
871
        cidr := parseCIDR(subnetStr)
1✔
872
        if cidr == nil {
1✔
873
                cont.log.WithFields(logrus.Fields{
×
874
                        "subnet": subnetStr,
×
875
                        "netpol": key,
×
876
                }).Warning("Invalid subnet or IP")
×
877
                return false
×
878
        }
×
879

880
        entries, err := index.CoveredNetworks(*cidr)
1✔
881
        if err != nil {
1✔
882
                cont.log.Error("Corrupted subnet index: ", err)
×
883
                return false
×
884
        }
×
885
        if add {
2✔
886
                for _, entryObj := range entries {
2✔
887
                        if netEqual(entryObj.Network(), *cidr) {
2✔
888
                                entry := entryObj.(*ipIndexEntry)
1✔
889
                                existing := entry.keys[key]
1✔
890
                                entry.keys[key] = true
1✔
891
                                return !existing
1✔
892
                        }
1✔
893
                }
894

895
                entry := &ipIndexEntry{
1✔
896
                        ipNet: *cidr,
1✔
897
                        keys: map[string]bool{
1✔
898
                                key: true,
1✔
899
                        },
1✔
900
                }
1✔
901
                index.Insert(entry)
1✔
902
                return true
1✔
903
        } else {
1✔
904
                var existing bool
1✔
905
                for _, entryObj := range entries {
2✔
906
                        entry := entryObj.(*ipIndexEntry)
1✔
907
                        if entry.keys[key] {
2✔
908
                                existing = true
1✔
909
                                delete(entry.keys, key)
1✔
910
                        }
1✔
911
                        if len(entry.keys) == 0 {
2✔
912
                                index.Remove(entry.Network())
1✔
913
                        }
1✔
914
                }
915
                return existing
1✔
916
        }
917
}
918

919
func (cont *AciController) updateIpIndex(index cidranger.Ranger,
920
        oldSubnets map[string]bool, newSubnets map[string]bool, key string) {
1✔
921
        for subStr := range oldSubnets {
2✔
922
                if newSubnets[subStr] {
2✔
923
                        continue
1✔
924
                }
925
                cont.updateIpIndexEntry(index, subStr, key, false)
1✔
926
        }
927
        for subStr := range newSubnets {
2✔
928
                if oldSubnets[subStr] {
2✔
929
                        continue
1✔
930
                }
931
                cont.updateIpIndexEntry(index, subStr, key, true)
1✔
932
        }
933
}
934

935
func (cont *AciController) updateTargetPortIndex(service bool, key string,
936
        oldPorts map[string]targetPort, newPorts map[string]targetPort) {
1✔
937
        for portkey := range oldPorts {
2✔
938
                if _, ok := newPorts[portkey]; ok {
1✔
939
                        continue
×
940
                }
941

942
                entry, ok := cont.targetPortIndex[portkey]
1✔
943
                if !ok {
1✔
944
                        continue
×
945
                }
946

947
                if service {
1✔
948
                        delete(entry.serviceKeys, key)
×
949
                } else {
1✔
950
                        delete(entry.networkPolicyKeys, key)
1✔
951
                }
1✔
952
                if len(entry.serviceKeys) == 0 && len(entry.networkPolicyKeys) == 0 {
2✔
953
                        delete(cont.targetPortIndex, portkey)
1✔
954
                }
1✔
955
        }
956
        for portkey, port := range newPorts {
2✔
957
                if _, ok := oldPorts[portkey]; ok {
1✔
958
                        continue
×
959
                }
960
                entry := cont.targetPortIndex[portkey]
1✔
961
                if entry == nil {
2✔
962
                        entry = &portIndexEntry{
1✔
963
                                port:              port,
1✔
964
                                serviceKeys:       make(map[string]bool),
1✔
965
                                networkPolicyKeys: make(map[string]bool),
1✔
966
                        }
1✔
967
                        cont.targetPortIndex[portkey] = entry
1✔
968
                } else {
2✔
969
                        entry.port.ports = port.ports
1✔
970
                }
1✔
971

972
                if service {
2✔
973
                        entry.serviceKeys[key] = true
1✔
974
                } else {
2✔
975
                        entry.networkPolicyKeys[key] = true
1✔
976
                }
1✔
977
        }
978
}
979

980
func (cont *AciController) getPortNumsFromPortName(podKeys []string, portName string) []int {
1✔
981
        var ports []int
1✔
982
        portmap := make(map[int]bool)
1✔
983
        for _, podkey := range podKeys {
2✔
984
                podobj, exists, err := cont.podIndexer.GetByKey(podkey)
1✔
985
                if exists && err == nil {
2✔
986
                        pod := podobj.(*v1.Pod)
1✔
987
                        port, err := k8util.LookupContainerPortNumberByName(*pod, portName)
1✔
988
                        if err != nil {
1✔
989
                                continue
×
990
                        }
991
                        if _, ok := portmap[int(port)]; !ok {
2✔
992
                                ports = append(ports, int(port))
1✔
993
                                portmap[int(port)] = true
1✔
994
                        }
1✔
995
                }
996
        }
997
        if len(ports) == 0 {
2✔
998
                cont.log.Infof("No matching portnumbers for portname %s: ", portName)
1✔
999
        }
1✔
1000
        cont.log.Debug("PortName: ", portName, "Mapping port numbers: ", ports)
1✔
1001
        return ports
1✔
1002
}
1003

1004
// get a map of target ports for egress rules that have no "To" clause
1005
func (cont *AciController) getNetPolTargetPorts(np *v1net.NetworkPolicy) map[string]targetPort {
1✔
1006
        ports := make(map[string]targetPort)
1✔
1007
        for _, egress := range np.Spec.Egress {
2✔
1008
                if len(egress.To) != 0 && !isNamedPortPresenInNp(np) {
2✔
1009
                        continue
1✔
1010
                }
1011
                for _, port := range egress.Ports {
2✔
1012
                        if port.Port == nil {
1✔
1013
                                continue
×
1014
                        }
1015
                        proto := v1.ProtocolTCP
1✔
1016
                        if port.Protocol != nil {
2✔
1017
                                proto = *port.Protocol
1✔
1018
                        }
1✔
1019
                        npKey, _ := cache.MetaNamespaceKeyFunc(np)
1✔
1020
                        var key string
1✔
1021
                        var portnums []int
1✔
1022
                        if port.Port.Type == intstr.Int {
2✔
1023
                                key = portProto(&proto) + "-num-" + port.Port.String()
1✔
1024
                                portnums = append(portnums, port.Port.IntValue())
1✔
1025
                        } else {
2✔
1026
                                if len(egress.To) != 0 {
2✔
1027
                                        // TODO optimize this code instead going through all matching pods every time
1✔
1028
                                        podKeys := cont.netPolEgressPods.GetPodForObj(npKey)
1✔
1029
                                        portnums = cont.getPortNumsFromPortName(podKeys, port.Port.String())
1✔
1030
                                } else {
2✔
1031
                                        ctrNmpEntry, ok := cont.ctrPortNameCache[port.Port.String()]
1✔
1032
                                        if ok {
2✔
1033
                                                for key := range ctrNmpEntry.ctrNmpToPods {
2✔
1034
                                                        val := strings.Split(key, "-")
1✔
1035
                                                        if len(val) != 2 {
1✔
1036
                                                                continue
×
1037
                                                        }
1038
                                                        if val[0] == portProto(&proto) {
2✔
1039
                                                                port, _ := strconv.Atoi(val[1])
1✔
1040
                                                                portnums = append(portnums, port)
1✔
1041
                                                        }
1✔
1042
                                                }
1043
                                        }
1044
                                }
1045
                                if len(portnums) == 0 {
2✔
1046
                                        continue
1✔
1047
                                }
1048
                                key = portProto(&proto) + "-name-" + port.Port.String()
1✔
1049
                        }
1050
                        ports[key] = targetPort{
1✔
1051
                                proto: proto,
1✔
1052
                                ports: portnums,
1✔
1053
                        }
1✔
1054
                }
1055
        }
1056
        return ports
1✔
1057
}
1058

1059
type peerRemoteInfo struct {
1060
        remotePods   []*v1.Pod
1061
        podSelectors []*metav1.LabelSelector
1062
}
1063

1064
func (cont *AciController) getPeerRemoteSubnets(peers []v1net.NetworkPolicyPeer,
1065
        namespace string, peerPods []*v1.Pod, peerNs map[string]*v1.Namespace,
1066
        logger *logrus.Entry) ([]string, []string, peerRemoteInfo, map[string]bool, []string) {
1✔
1067
        var remoteSubnets []string
1✔
1068
        var peerremote peerRemoteInfo
1✔
1069
        subnetMap := make(map[string]bool)
1✔
1070
        var peerNsList []string
1✔
1071
        var ipBlockSubs []string
1✔
1072
        if len(peers) > 0 {
2✔
1073
                // only applies to matching pods
1✔
1074
                for _, pod := range peerPods {
2✔
1075
                        for peerIx, peer := range peers {
2✔
1076
                                if ns, ok := peerNs[pod.ObjectMeta.Namespace]; ok &&
1✔
1077
                                        cont.peerMatchesPod(namespace,
1✔
1078
                                                &peers[peerIx], pod, ns) {
2✔
1079
                                        podIps := ipsForPod(pod)
1✔
1080
                                        for _, ip := range podIps {
2✔
1081
                                                if _, exists := subnetMap[ip]; !exists {
2✔
1082
                                                        subnetMap[ip] = true
1✔
1083
                                                        if cont.config.EnableHppDirect {
2✔
1084
                                                                peerremote.remotePods = append(peerremote.remotePods, pod)
1✔
1085
                                                                if !slices.Contains(peerNsList, pod.ObjectMeta.Namespace) {
2✔
1086
                                                                        peerNsList = append(peerNsList, pod.ObjectMeta.Namespace)
1✔
1087
                                                                }
1✔
1088
                                                        }
1089
                                                        remoteSubnets = append(remoteSubnets, ip)
1✔
1090
                                                }
1091
                                        }
1092
                                }
1093
                                if cont.config.EnableHppDirect && peer.PodSelector != nil {
2✔
1094
                                        if !cont.isPodSelectorPresent(peerremote.podSelectors, peer.PodSelector) {
2✔
1095
                                                peerremote.podSelectors = append(peerremote.podSelectors, peer.PodSelector)
1✔
1096
                                        }
1✔
1097
                                }
1098
                        }
1099
                }
1100

1101
                for _, peer := range peers {
2✔
1102
                        if peer.IPBlock == nil {
2✔
1103
                                continue
1✔
1104
                        }
1105
                        subs, err := ipBlockToSubnets(peer.IPBlock)
1✔
1106
                        if err != nil {
1✔
1107
                                logger.Warning("Invalid IPBlock in network policy rule: ", err)
×
1108
                        } else {
1✔
1109
                                for _, subnet := range subs {
2✔
1110
                                        subnetMap[subnet] = true
1✔
1111
                                }
1✔
1112
                                remoteSubnets = append(remoteSubnets, subs...)
1✔
1113
                                ipBlockSubs = append(ipBlockSubs, subs...)
1✔
1114
                        }
1115
                }
1116
        }
1117
        sort.Strings(remoteSubnets)
1✔
1118
        return remoteSubnets, peerNsList, peerremote, subnetMap, ipBlockSubs
1✔
1119
}
1120

1121
func (cont *AciController) ipInPodSubnet(ip net.IP) bool {
×
1122
        for _, podsubnet := range cont.config.PodSubnet {
×
1123
                _, subnet, err := net.ParseCIDR(podsubnet)
×
1124
                if err == nil && subnet != nil {
×
1125
                        if subnet.Contains(ip) {
×
1126
                                return true
×
1127
                        }
×
1128
                }
1129
        }
1130
        return false
×
1131
}
1132

1133
func (cont *AciController) buildNetPolSubjRule(subj apicapi.ApicObject, ruleName,
1134
        direction, ethertype, proto, port string, remoteSubnets []string,
1135
        addPodSubnetAsRemIp bool) {
1✔
1136
        rule := apicapi.NewHostprotRule(subj.GetDn(), ruleName)
1✔
1137
        rule.SetAttr("direction", direction)
1✔
1138
        rule.SetAttr("ethertype", ethertype)
1✔
1139
        if proto != "" {
2✔
1140
                rule.SetAttr("protocol", proto)
1✔
1141
        }
1✔
1142

1143
        if addPodSubnetAsRemIp {
1✔
1144
                for _, podsubnet := range cont.config.PodSubnet {
×
1145
                        _, subnet, err := net.ParseCIDR(podsubnet)
×
1146
                        if err == nil && subnet != nil {
×
1147
                                if (ethertype == "ipv4" && subnet.IP.To4() != nil) || (ethertype == "ipv6" && subnet.IP.To4() == nil) {
×
1148
                                        rule.AddChild(apicapi.NewHostprotRemoteIp(rule.GetDn(), podsubnet))
×
1149
                                }
×
1150
                        }
1151
                }
1152
        }
1153
        for _, subnetStr := range remoteSubnets {
2✔
1154
                _, subnet, err := net.ParseCIDR(subnetStr)
1✔
1155
                if err == nil && subnet != nil {
2✔
1156
                        // subnetStr is a valid CIDR notation, check its IP version and add the subnet to the rule
1✔
1157
                        if (ethertype == "ipv4" && subnet.IP.To4() != nil) || (ethertype == "ipv6" && subnet.IP.To4() == nil) {
2✔
1158
                                rule.AddChild(apicapi.NewHostprotRemoteIp(rule.GetDn(), subnetStr))
1✔
1159
                        }
1✔
1160
                } else if ip := net.ParseIP(subnetStr); ip != nil {
2✔
1161
                        if addPodSubnetAsRemIp && cont.ipInPodSubnet(ip) {
1✔
1162
                                continue
×
1163
                        }
1164
                        if ethertype == "ipv6" && (ip.To16() != nil && ip.To4() == nil) || ethertype == "ipv4" && ip.To4() != nil {
2✔
1165
                                rule.AddChild(apicapi.NewHostprotRemoteIp(rule.GetDn(), subnetStr))
1✔
1166
                        }
1✔
1167
                }
1168
        }
1169
        if port != "" {
2✔
1170
                rule.SetAttr("toPort", port)
1✔
1171
        }
1✔
1172

1173
        subj.AddChild(rule)
1✔
1174
}
1175

1176
func (cont *AciController) isPodSelectorPresent(podSelectors []*metav1.LabelSelector,
1177
        podSelector *metav1.LabelSelector) bool {
1✔
1178

1✔
1179
        present := false
1✔
1180
        for _, selector := range podSelectors {
1✔
1181
                if reflect.DeepEqual(selector, podSelector) {
×
1182
                        present = true
×
1183
                        break
×
1184
                }
1185
        }
1186
        return present
1✔
1187
}
1188

1189
func (cont *AciController) buildLocalNetPolSubjRule(subj *hppv1.HostprotSubj, ruleName,
1190
        direction, ethertype, proto, port string, remoteNs []string,
1191
        podSelectors []*metav1.LabelSelector, remoteSubnets []string) {
1✔
1192
        rule := hppv1.HostprotRule{
1✔
1193
                ConnTrack: "reflexive",
1✔
1194
                Direction: "ingress",
1✔
1195
                Ethertype: "undefined",
1✔
1196
                Protocol:  "unspecified",
1✔
1197
                FromPort:  "unspecified",
1✔
1198
                ToPort:    "unspecified",
1✔
1199
        }
1✔
1200
        rule.Direction = direction
1✔
1201
        rule.Ethertype = ethertype
1✔
1202
        if proto != "" {
2✔
1203
                rule.Protocol = proto
1✔
1204
        }
1✔
1205
        rule.Name = ruleName
1✔
1206

1✔
1207
        rule.RsRemoteIpContainer = remoteNs
1✔
1208
        var remoteSubnetsCidr []hppv1.HostprotRemoteIp
1✔
1209
        for _, subnetStr := range remoteSubnets {
2✔
1210
                _, subnet, err := net.ParseCIDR(subnetStr)
1✔
1211
                if err == nil && subnet != nil {
2✔
1212
                        if (ethertype == "ipv4" && subnet.IP.To4() != nil) || (ethertype == "ipv6" && subnet.IP.To4() == nil) {
2✔
1213
                                remIpObj := hppv1.HostprotRemoteIp{
1✔
1214
                                        Addr: subnetStr,
1✔
1215
                                }
1✔
1216
                                remoteSubnetsCidr = append(remoteSubnetsCidr, remIpObj)
1✔
1217
                        }
1✔
1218
                }
1219
        }
1220
        if len(remoteSubnetsCidr) > 0 {
2✔
1221
                rule.HostprotRemoteIp = remoteSubnetsCidr
1✔
1222
        }
1✔
1223

1224
        var filterContainers []hppv1.HostprotFilterContainer
1✔
1225
        for _, podSelector := range podSelectors {
2✔
1226
                filterContainer := hppv1.HostprotFilterContainer{}
1✔
1227
                for key, val := range podSelector.MatchLabels {
2✔
1228
                        filter := hppv1.HostprotFilter{
1✔
1229
                                Key: key,
1✔
1230
                        }
1✔
1231
                        filter.Values = append(filter.Values, val)
1✔
1232
                        filter.Operator = "Equals"
1✔
1233
                        filterContainer.HostprotFilter = append(filterContainer.HostprotFilter, filter)
1✔
1234
                }
1✔
1235
                for _, expressions := range podSelector.MatchExpressions {
2✔
1236
                        filter := hppv1.HostprotFilter{
1✔
1237
                                Key:      expressions.Key,
1✔
1238
                                Values:   expressions.Values,
1✔
1239
                                Operator: string(expressions.Operator),
1✔
1240
                        }
1✔
1241
                        filterContainer.HostprotFilter = append(filterContainer.HostprotFilter, filter)
1✔
1242
                }
1✔
1243
                filterContainers = append(filterContainers, filterContainer)
1✔
1244
        }
1245

1246
        if len(filterContainers) > 0 {
2✔
1247
                rule.HostprotFilterContainer = filterContainers
1✔
1248
        }
1✔
1249

1250
        if port != "" {
2✔
1251
                rule.ToPort = port
1✔
1252
        }
1✔
1253

1254
        cont.log.Debug(direction)
1✔
1255
        if len(remoteSubnets) != 0 && direction == "egress" {
2✔
1256
                cont.log.Debug("HostprotServiceRemoteIps")
1✔
1257
                rule.HostprotServiceRemoteIps = remoteSubnets
1✔
1258
        }
1✔
1259

1260
        subj.HostprotRule = append(subj.HostprotRule, rule)
1✔
1261
}
1262

1263
func (cont *AciController) buildNetPolSubjRules(ruleName string,
1264
        subj apicapi.ApicObject, direction string, peers []v1net.NetworkPolicyPeer,
1265
        remoteSubnets []string, ports []v1net.NetworkPolicyPort,
1266
        logger *logrus.Entry, npKey string, np *v1net.NetworkPolicy,
1267
        addPodSubnetAsRemIp bool) {
1✔
1268
        if len(peers) > 0 && len(remoteSubnets) == 0 {
2✔
1269
                // nonempty From matches no pods or IPBlocks; don't
1✔
1270
                // create the rule
1✔
1271
                return
1✔
1272
        }
1✔
1273
        if len(ports) == 0 {
2✔
1274
                if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
1275
                        prefix := fmt.Sprintf("%s-ipv4", ruleName)
1✔
1276
                        policyRuleName := util.AciNameForKey(prefix, "", np.Name)
1✔
1277
                        cont.buildNetPolSubjRule(subj, policyRuleName, direction,
1✔
1278
                                "ipv4", "", "", remoteSubnets, addPodSubnetAsRemIp)
1✔
1279
                }
1✔
1280
                if !cont.configuredPodNetworkIps.V6.Empty() {
2✔
1281
                        prefix := fmt.Sprintf("%s-ipv6", ruleName)
1✔
1282
                        policyRuleName := util.AciNameForKey(prefix, "", np.Name)
1✔
1283
                        cont.buildNetPolSubjRule(subj, policyRuleName, direction,
1✔
1284
                                "ipv6", "", "", remoteSubnets, addPodSubnetAsRemIp)
1✔
1285
                }
1✔
1286
        } else {
1✔
1287
                for j := range ports {
2✔
1288
                        proto := portProto(ports[j].Protocol)
1✔
1289
                        var portList []string
1✔
1290

1✔
1291
                        if ports[j].Port != nil {
2✔
1292
                                if ports[j].Port.Type == intstr.Int {
2✔
1293
                                        portList = append(portList, ports[j].Port.String())
1✔
1294
                                } else {
2✔
1295
                                        var portnums []int
1✔
1296
                                        if direction == "egress" {
2✔
1297
                                                portnums = append(portnums, cont.getPortNums(&ports[j])...)
1✔
1298
                                        } else {
2✔
1299
                                                // TODO need to handle empty Pod Selector
1✔
1300
                                                if reflect.DeepEqual(np.Spec.PodSelector, metav1.LabelSelector{}) {
1✔
1301
                                                        logger.Warning("Empty PodSelctor for NamedPort is not supported in ingress direction"+
×
1302
                                                                "port in network policy: ", ports[j].Port.String())
×
1303
                                                        continue
×
1304
                                                }
1305
                                                podKeys := cont.netPolPods.GetPodForObj(npKey)
1✔
1306
                                                portnums = cont.getPortNumsFromPortName(podKeys, ports[j].Port.String())
1✔
1307
                                        }
1308
                                        if len(portnums) == 0 {
2✔
1309
                                                logger.Warning("There is no matching  ports in ingress/egress direction "+
1✔
1310
                                                        "port in network policy: ", ports[j].Port.String())
1✔
1311
                                                continue
1✔
1312
                                        }
1313
                                        for _, portnum := range portnums {
2✔
1314
                                                portList = append(portList, strconv.Itoa(portnum))
1✔
1315
                                        }
1✔
1316
                                }
1317
                        }
1318
                        for i, port := range portList {
2✔
1319
                                if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
1320
                                        prefix := fmt.Sprintf("%s_%d-ipv4", ruleName, j+i)
1✔
1321
                                        policyRuleName := util.AciNameForKey(prefix, "", np.Name)
1✔
1322
                                        cont.buildNetPolSubjRule(subj, policyRuleName, direction,
1✔
1323
                                                "ipv4", proto, port, remoteSubnets, addPodSubnetAsRemIp)
1✔
1324
                                }
1✔
1325
                                if !cont.configuredPodNetworkIps.V6.Empty() {
2✔
1326
                                        prefix := fmt.Sprintf("%s_%d-ipv6", ruleName, j+i)
1✔
1327
                                        policyRuleName := util.AciNameForKey(prefix, "", np.Name)
1✔
1328
                                        cont.buildNetPolSubjRule(subj, policyRuleName, direction,
1✔
1329
                                                "ipv6", proto, port, remoteSubnets, addPodSubnetAsRemIp)
1✔
1330
                                }
1✔
1331
                        }
1332
                        if len(portList) == 0 && proto != "" {
2✔
1333
                                if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
1334
                                        prefix := fmt.Sprintf("%s_%d-ipv4", ruleName, j)
1✔
1335
                                        policyRuleName := util.AciNameForKey(prefix, "", np.Name)
1✔
1336
                                        cont.buildNetPolSubjRule(subj, policyRuleName, direction,
1✔
1337
                                                "ipv4", proto, "", remoteSubnets, addPodSubnetAsRemIp)
1✔
1338
                                }
1✔
1339
                                if !cont.configuredPodNetworkIps.V6.Empty() {
1✔
1340
                                        prefix := fmt.Sprintf("%s_%d-ipv6", ruleName, j)
×
1341
                                        policyRuleName := util.AciNameForKey(prefix, "", np.Name)
×
1342
                                        cont.buildNetPolSubjRule(subj, policyRuleName, direction,
×
1343
                                                "ipv6", proto, "", remoteSubnets, addPodSubnetAsRemIp)
×
1344
                                }
×
1345
                        }
1346
                }
1347
        }
1348
}
1349

1350
func (cont *AciController) buildLocalNetPolSubjRules(ruleName string,
1351
        subj *hppv1.HostprotSubj, direction string, peerNs []string,
1352
        podSelector []*metav1.LabelSelector, ports []v1net.NetworkPolicyPort,
1353
        logger *logrus.Entry, npKey string, np *v1net.NetworkPolicy, peerIpBlock []string) {
1✔
1354
        if len(ports) == 0 {
2✔
1355
                if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
1356
                        cont.buildLocalNetPolSubjRule(subj, ruleName+"-ipv4", direction,
1✔
1357
                                "ipv4", "", "", peerNs, podSelector, peerIpBlock)
1✔
1358
                }
1✔
1359
                if !cont.configuredPodNetworkIps.V6.Empty() {
1✔
1360
                        cont.buildLocalNetPolSubjRule(subj, ruleName+"-ipv6", direction,
×
1361
                                "ipv6", "", "", peerNs, podSelector, peerIpBlock)
×
1362
                }
×
1363
        } else {
1✔
1364
                for j := range ports {
2✔
1365
                        proto := portProto(ports[j].Protocol)
1✔
1366
                        var portList []string
1✔
1367

1✔
1368
                        if ports[j].Port != nil {
2✔
1369
                                if ports[j].Port.Type == intstr.Int {
2✔
1370
                                        portList = append(portList, ports[j].Port.String())
1✔
1371
                                } else {
1✔
1372
                                        var portnums []int
×
1373
                                        if direction == "egress" {
×
1374
                                                portnums = append(portnums, cont.getPortNums(&ports[j])...)
×
1375
                                        } else {
×
1376
                                                // TODO need to handle empty Pod Selector
×
1377
                                                if reflect.DeepEqual(np.Spec.PodSelector, metav1.LabelSelector{}) {
×
1378
                                                        logger.Warning("Empty PodSelctor for NamedPort is not supported in ingress direction"+
×
1379
                                                                "port in network policy: ", ports[j].Port.String())
×
1380
                                                        continue
×
1381
                                                }
1382
                                                podKeys := cont.netPolPods.GetPodForObj(npKey)
×
1383
                                                portnums = cont.getPortNumsFromPortName(podKeys, ports[j].Port.String())
×
1384
                                        }
1385
                                        if len(portnums) == 0 {
×
1386
                                                logger.Warning("There is no matching  ports in ingress/egress direction "+
×
1387
                                                        "port in network policy: ", ports[j].Port.String())
×
1388
                                                continue
×
1389
                                        }
1390
                                        for _, portnum := range portnums {
×
1391
                                                portList = append(portList, strconv.Itoa(portnum))
×
1392
                                        }
×
1393
                                }
1394
                        }
1395
                        for i, port := range portList {
2✔
1396
                                if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
1397
                                        cont.buildLocalNetPolSubjRule(subj, ruleName+"_"+strconv.Itoa(i+j)+"-ipv4", direction,
1✔
1398
                                                "ipv4", proto, port, peerNs, podSelector, peerIpBlock)
1✔
1399
                                }
1✔
1400
                                if !cont.configuredPodNetworkIps.V6.Empty() {
1✔
1401
                                        cont.buildLocalNetPolSubjRule(subj, ruleName+"_"+strconv.Itoa(i+j)+"-ipv6", direction,
×
1402
                                                "ipv6", proto, port, peerNs, podSelector, peerIpBlock)
×
1403
                                }
×
1404
                        }
1405
                        if len(portList) == 0 && proto != "" {
1✔
1406
                                if !cont.configuredPodNetworkIps.V4.Empty() {
×
1407
                                        cont.buildLocalNetPolSubjRule(subj, ruleName+"_"+strconv.Itoa(j)+"-ipv4", direction,
×
1408
                                                "ipv4", proto, "", peerNs, podSelector, peerIpBlock)
×
1409
                                }
×
1410
                                if !cont.configuredPodNetworkIps.V6.Empty() {
×
1411
                                        cont.buildLocalNetPolSubjRule(subj, ruleName+"_"+strconv.Itoa(j)+"-ipv6", direction,
×
1412
                                                "ipv6", proto, "", peerNs, podSelector, peerIpBlock)
×
1413
                                }
×
1414
                        }
1415
                }
1416
        }
1417
}
1418

1419
func (cont *AciController) getPortNums(port *v1net.NetworkPolicyPort) []int {
1✔
1420
        portkey := portKey(port)
1✔
1421
        cont.indexMutex.Lock()
1✔
1422
        defer cont.indexMutex.Unlock()
1✔
1423
        cont.log.Debug("PortKey1: ", portkey)
1✔
1424
        entry := cont.targetPortIndex[portkey]
1✔
1425
        var length int
1✔
1426
        if entry == nil || len(entry.port.ports) == 0 {
2✔
1427
                return []int{}
1✔
1428
        }
1✔
1429
        length = len(entry.port.ports)
1✔
1430
        ports := make([]int, length)
1✔
1431
        copy(ports, entry.port.ports)
1✔
1432
        return ports
1✔
1433
}
1434
func portProto(protocol *v1.Protocol) string {
1✔
1435
        proto := "tcp"
1✔
1436
        if protocol != nil && *protocol == v1.ProtocolUDP {
2✔
1437
                proto = "udp"
1✔
1438
        } else if protocol != nil && *protocol == v1.ProtocolSCTP {
3✔
1439
                proto = "sctp"
1✔
1440
        }
1✔
1441
        return proto
1✔
1442
}
1443

1444
func portKey(p *v1net.NetworkPolicyPort) string {
1✔
1445
        portType := ""
1✔
1446
        port := ""
1✔
1447
        if p != nil && p.Port != nil {
2✔
1448
                if p.Port.Type == intstr.Int {
2✔
1449
                        portType = "num"
1✔
1450
                } else {
2✔
1451
                        portType = "name"
1✔
1452
                }
1✔
1453
                port = p.Port.String()
1✔
1454
                return portProto(p.Protocol) + "-" + portType + "-" + port
1✔
1455
        }
1456
        return ""
1✔
1457
}
1458

1459
func checkEndpoints(subnetIndex cidranger.Ranger,
1460
        addresses []v1.EndpointAddress) bool {
1✔
1461
        for _, addr := range addresses {
2✔
1462
                ip := net.ParseIP(addr.IP)
1✔
1463
                if ip == nil {
1✔
1464
                        return false
×
1465
                }
×
1466
                contains, err := subnetIndex.Contains(ip)
1✔
1467
                if err != nil || !contains {
2✔
1468
                        return false
1✔
1469
                }
1✔
1470
        }
1471

1472
        return true
1✔
1473
}
1474
func checkEndpointslices(subnetIndex cidranger.Ranger,
1475
        addresses []string) bool {
1✔
1476
        for _, addr := range addresses {
2✔
1477
                ip := net.ParseIP(addr)
1✔
1478
                if ip == nil {
1✔
1479
                        return false
×
1480
                }
×
1481
                contains, err := subnetIndex.Contains(ip)
1✔
1482
                if err != nil || !contains {
2✔
1483
                        return false
1✔
1484
                }
1✔
1485
        }
1486
        return true
1✔
1487
}
1488

1489
type portRemoteSubnet struct {
1490
        port           *v1net.NetworkPolicyPort
1491
        subnetMap      map[string]bool
1492
        hasNamedTarget bool
1493
}
1494

1495
func updatePortRemoteSubnets(portRemoteSubs map[string]*portRemoteSubnet,
1496
        portkey string, port *v1net.NetworkPolicyPort, subnetMap map[string]bool,
1497
        hasNamedTarget bool) {
1✔
1498
        if prs, ok := portRemoteSubs[portkey]; ok {
1✔
1499
                for s := range subnetMap {
×
1500
                        prs.subnetMap[s] = true
×
1501
                }
×
1502
                prs.hasNamedTarget = hasNamedTarget || prs.hasNamedTarget
×
1503
        } else {
1✔
1504
                portRemoteSubs[portkey] = &portRemoteSubnet{
1✔
1505
                        port:           port,
1✔
1506
                        subnetMap:      subnetMap,
1✔
1507
                        hasNamedTarget: hasNamedTarget,
1✔
1508
                }
1✔
1509
        }
1✔
1510
}
1511

1512
func portServiceAugmentKey(proto, port string) string {
1✔
1513
        return proto + "-" + port
1✔
1514
}
1✔
1515

1516
type portServiceAugment struct {
1517
        proto string
1518
        port  string
1519
        ipMap map[string]bool
1520
}
1521

1522
func updateServiceAugment(portAugments map[string]*portServiceAugment, proto, port, ip string) {
1✔
1523
        key := portServiceAugmentKey(proto, port)
1✔
1524
        if psa, ok := portAugments[key]; ok {
1✔
1525
                psa.ipMap[ip] = true
×
1526
        } else {
1✔
1527
                portAugments[key] = &portServiceAugment{
1✔
1528
                        proto: proto,
1✔
1529
                        port:  port,
1✔
1530
                        ipMap: map[string]bool{ip: true},
1✔
1531
                }
1✔
1532
        }
1✔
1533
}
1534

1535
func updateServiceAugmentForService(portAugments map[string]*portServiceAugment,
1536
        proto, port string, service *v1.Service) {
1✔
1537
        if service.Spec.ClusterIP != "" {
2✔
1538
                updateServiceAugment(portAugments,
1✔
1539
                        proto, port, service.Spec.ClusterIP)
1✔
1540
        }
1✔
1541
        for _, ig := range service.Status.LoadBalancer.Ingress {
1✔
1542
                if ig.IP == "" {
×
1543
                        continue
×
1544
                }
1545
                updateServiceAugment(portAugments,
×
1546
                        proto, port, ig.IP)
×
1547
        }
1548
}
1549

1550
// build service augment by matching peers against the endpoints ip
1551
// index
1552
func (cont *AciController) getServiceAugmentBySubnet(
1553
        prs *portRemoteSubnet, portAugments map[string]*portServiceAugment,
1554
        logger *logrus.Entry) {
1✔
1555
        matchedServices := make(map[string]bool)
1✔
1556
        subnetIndex := cidranger.NewPCTrieRanger()
1✔
1557

1✔
1558
        // find candidate service endpoints objects that include
1✔
1559
        // endpoints selected by the egress rule
1✔
1560
        cont.indexMutex.Lock()
1✔
1561
        for sub := range prs.subnetMap {
2✔
1562
                cidr := parseCIDR(sub)
1✔
1563
                if cidr == nil {
1✔
1564
                        continue
×
1565
                }
1566
                subnetIndex.Insert(cidranger.NewBasicRangerEntry(*cidr))
1✔
1567

1✔
1568
                entries, err := cont.endpointsIpIndex.CoveredNetworks(*cidr)
1✔
1569
                if err != nil {
1✔
1570
                        logger.Error("endpointsIpIndex corrupted: ", err)
×
1571
                        continue
×
1572
                }
1573
                for _, entry := range entries {
2✔
1574
                        e := entry.(*ipIndexEntry)
1✔
1575
                        for servicekey := range e.keys {
2✔
1576
                                matchedServices[servicekey] = true
1✔
1577
                        }
1✔
1578
                }
1579
        }
1580
        cont.indexMutex.Unlock()
1✔
1581

1✔
1582
        // if all endpoints are selected by egress rule, allow egress
1✔
1583
        // to the service cluster IP as well as to the endpoints
1✔
1584
        // themselves
1✔
1585
        for servicekey := range matchedServices {
2✔
1586
                serviceobj, _, err := cont.serviceIndexer.GetByKey(servicekey)
1✔
1587
                if err != nil {
1✔
1588
                        logger.Error("Could not lookup service for "+
×
1589
                                servicekey+": ", err.Error())
×
1590
                        continue
×
1591
                }
1592
                if serviceobj == nil {
1✔
1593
                        continue
×
1594
                }
1595
                service := serviceobj.(*v1.Service)
1✔
1596
                cont.serviceEndPoints.SetNpServiceAugmentForService(servicekey, service,
1✔
1597
                        prs, portAugments, subnetIndex, logger)
1✔
1598
        }
1599
}
1600

1601
// build service augment by matching against services with a given
1602
// target port
1603
func (cont *AciController) getServiceAugmentByPort(
1604
        prs *portRemoteSubnet, portAugments map[string]*portServiceAugment,
1605
        logger *logrus.Entry) {
1✔
1606
        // nil port means it matches against all ports.  If we're here, it
1✔
1607
        // means this is a rule that matches all ports with all
1✔
1608
        // destinations, so there's no need to augment anything.
1✔
1609
        if prs.port == nil ||
1✔
1610
                prs.port.Port == nil {
2✔
1611
                return
1✔
1612
        }
1✔
1613

1614
        portkey := portKey(prs.port)
1✔
1615
        cont.indexMutex.Lock()
1✔
1616
        entries := make(map[string]*portIndexEntry)
1✔
1617
        entry := cont.targetPortIndex[portkey]
1✔
1618
        if entry != nil && prs.port.Port.Type == intstr.String {
2✔
1619
                for _, port := range entry.port.ports {
2✔
1620
                        portstring := strconv.Itoa(port)
1✔
1621
                        key := portProto(prs.port.Protocol) + "-" + "num" + "-" + portstring
1✔
1622
                        portEntry := cont.targetPortIndex[key]
1✔
1623
                        if portEntry != nil {
2✔
1624
                                entries[portstring] = portEntry
1✔
1625
                        }
1✔
1626
                }
1627
        } else if entry != nil {
2✔
1628
                if len(entry.port.ports) > 0 {
2✔
1629
                        entries[strconv.Itoa(entry.port.ports[0])] = entry
1✔
1630
                }
1✔
1631
        }
1632
        for key, portentry := range entries {
2✔
1633
                for servicekey := range portentry.serviceKeys {
2✔
1634
                        serviceobj, _, err := cont.serviceIndexer.GetByKey(servicekey)
1✔
1635
                        if err != nil {
1✔
1636
                                logger.Error("Could not lookup service for "+
×
1637
                                        servicekey+": ", err.Error())
×
1638
                                continue
×
1639
                        }
1640
                        if serviceobj == nil {
1✔
1641
                                continue
×
1642
                        }
1643
                        service := serviceobj.(*v1.Service)
1✔
1644

1✔
1645
                        for _, svcPort := range service.Spec.Ports {
2✔
1646
                                if svcPort.Protocol != *prs.port.Protocol ||
1✔
1647
                                        svcPort.TargetPort.String() !=
1✔
1648
                                                key {
1✔
1649
                                        continue
×
1650
                                }
1651
                                proto := portProto(&svcPort.Protocol)
1✔
1652
                                port := strconv.Itoa(int(svcPort.Port))
1✔
1653

1✔
1654
                                updateServiceAugmentForService(portAugments,
1✔
1655
                                        proto, port, service)
1✔
1656

1✔
1657
                                logger.WithFields(logrus.Fields{
1✔
1658
                                        "proto":   proto,
1✔
1659
                                        "port":    port,
1✔
1660
                                        "service": servicekey,
1✔
1661
                                }).Debug("Allowing egress for service by port")
1✔
1662
                        }
1663
                }
1664
        }
1665
        cont.indexMutex.Unlock()
1✔
1666
}
1667

1668
// The egress NetworkPolicy API were designed with the iptables
1669
// implementation in mind and don't contemplate that the layer 4 load
1670
// balancer could happen separately from the policy.  In particular,
1671
// it expects load balancer operations to be applied before the policy
1672
// is applied in both directions, so network policies would apply only
1673
// to pods and not to service IPs. This presents a problem for egress
1674
// policies on ACI since the security groups are applied before load
1675
// balancer operations when egressing, and after when ingressing.
1676
//
1677
// To solve this problem, we use some indexes to discover situations
1678
// when an egress policy covers all the endpoints associated with a
1679
// particular service, and automatically add a rule that allows egress
1680
// to the corresponding service cluster IP and ports.
1681
//
1682
// Note that this differs slightly from the behavior you'd see if you
1683
// applied the load balancer rule first: If the egress policy allows
1684
// access to a subset of the allowed IPs you'd see random failures
1685
// depending on which destination is chosen, while with this approach
1686
// it's all or nothing.  This should not impact any correctly-written
1687
// network policies.
1688
//
1689
// To do this, we work first from the set of pods and subnets matches
1690
// by the egress policy.  We use this to find using the
1691
// endpointsIpIndex all services that contain at least one of the
1692
// matched pods or subnets.  For each of these candidate services, we
1693
// find service ports for which _all_ referenced endpoints are allowed
1694
// by the egress policy.  Note that a service will have the service
1695
// port and the target port; the NetworkPolicy (confusingly) refers to
1696
// the target port.
1697
//
1698
// Once confirmed matches are found, we augment the egress policy with
1699
// extra rules to allow egress to the service IPs and service ports.
1700
//
1701
// As a special case, for rules that match everything, we also have a
1702
// backup index that works through ports which should allow more
1703
// efficient matching when allowing egress to all.
1704
func (cont *AciController) buildServiceAugment(subj apicapi.ApicObject,
1705
        localsubj *hppv1.HostprotSubj,
1706
        portRemoteSubs map[string]*portRemoteSubnet, logger *logrus.Entry) {
1✔
1707
        portAugments := make(map[string]*portServiceAugment)
1✔
1708
        for _, prs := range portRemoteSubs {
2✔
1709
                // TODO ipv6
1✔
1710
                if prs.subnetMap["0.0.0.0/0"] {
2✔
1711
                        cont.getServiceAugmentByPort(prs, portAugments, logger)
1✔
1712
                } else {
2✔
1713
                        cont.getServiceAugmentBySubnet(prs, portAugments, logger)
1✔
1714
                }
1✔
1715
        }
1716
        for _, augment := range portAugments {
2✔
1717
                var remoteIpsv4 []string
1✔
1718
                var remoteIpsv6 []string
1✔
1719
                for ipstr := range augment.ipMap {
2✔
1720
                        ip := net.ParseIP(ipstr)
1✔
1721
                        if ip == nil {
1✔
1722
                                continue
×
1723
                        } else if ip.To4() != nil {
2✔
1724
                                remoteIpsv4 = append(remoteIpsv4, ipstr)
1✔
1725
                        } else if ip.To16() != nil {
3✔
1726
                                remoteIpsv6 = append(remoteIpsv6, ipstr)
1✔
1727
                        }
1✔
1728
                }
1729
                cont.log.Debug("Service Augment: ", augment)
1✔
1730
                if !cont.config.EnableHppDirect && subj != nil {
2✔
1731
                        if len(remoteIpsv4) > 0 {
2✔
1732
                                serviceName := fmt.Sprintf("service_%s_%s-ipv4", augment.proto, augment.port)
1✔
1733
                                cont.buildNetPolSubjRule(subj,
1✔
1734
                                        serviceName,
1✔
1735
                                        "egress", "ipv4", augment.proto, augment.port, remoteIpsv4, false)
1✔
1736
                        }
1✔
1737
                        if len(remoteIpsv6) > 0 {
2✔
1738
                                serviceName := fmt.Sprintf("service_%s_%s-ipv6", augment.proto, augment.port)
1✔
1739
                                cont.buildNetPolSubjRule(subj,
1✔
1740
                                        serviceName,
1✔
1741
                                        "egress", "ipv6", augment.proto, augment.port, remoteIpsv6, false)
1✔
1742
                        }
1✔
1743
                } else if cont.config.EnableHppDirect && localsubj != nil {
×
1744
                        if len(remoteIpsv4) > 0 {
×
1745
                                cont.buildLocalNetPolSubjRule(localsubj,
×
1746
                                        "service_"+augment.proto+"_"+augment.port,
×
1747
                                        "egress", "ipv4", augment.proto, augment.port, nil, nil, remoteIpsv4)
×
1748
                        }
×
1749
                        if len(remoteIpsv6) > 0 {
×
1750
                                cont.buildLocalNetPolSubjRule(localsubj,
×
1751
                                        "service_"+augment.proto+"_"+augment.port,
×
1752
                                        "egress", "ipv6", augment.proto, augment.port, nil, nil, remoteIpsv6)
×
1753
                        }
×
1754
                }
1755
        }
1756
}
1757

1758
func isAllowAllForAllNamespaces(peers []v1net.NetworkPolicyPeer) bool {
1✔
1759
        addPodSubnetAsRemIp := false
1✔
1760
        if peers != nil && len(peers) > 0 {
2✔
1761
                var emptyPodSel, emptyNsSel bool
1✔
1762
                emptyPodSel = true
1✔
1763
                for _, peer := range peers {
2✔
1764
                        // namespaceSelector: {}
1✔
1765
                        if peer.NamespaceSelector != nil && peer.NamespaceSelector.MatchLabels == nil && peer.NamespaceSelector.MatchExpressions == nil {
1✔
1766
                                emptyNsSel = true
×
1767
                        }
×
1768
                        // podSelector has some fields
1769
                        if peer.PodSelector != nil && (peer.PodSelector.MatchLabels != nil || peer.PodSelector.MatchExpressions != nil) {
2✔
1770
                                emptyPodSel = false
1✔
1771
                        }
1✔
1772
                }
1773
                if emptyNsSel && emptyPodSel {
1✔
1774
                        addPodSubnetAsRemIp = true
×
1775
                }
×
1776
        }
1777
        return addPodSubnetAsRemIp
1✔
1778
}
1779

1780
func (cont *AciController) handleRemIpContUpdate(ns string) bool {
1✔
1781
        cont.hppMutex.Lock()
1✔
1782
        defer cont.hppMutex.Unlock()
1✔
1783

1✔
1784
        sysNs := os.Getenv("SYSTEM_NAMESPACE")
1✔
1785
        aobj, err := cont.getHostprotRemoteIpContainer(ns, sysNs)
1✔
1786
        isUpdate := err == nil
1✔
1787

1✔
1788
        if err != nil && !errors.IsNotFound(err) {
1✔
1789
                cont.log.Error("Error getting HostprotRemoteIpContainers CR: ", err)
×
1790
                return true
×
1791
        }
×
1792

1793
        if !isUpdate {
2✔
1794
                aobj = &hppv1.HostprotRemoteIpContainer{
1✔
1795
                        ObjectMeta: metav1.ObjectMeta{
1✔
1796
                                Name:      ns,
1✔
1797
                                Namespace: sysNs,
1✔
1798
                        },
1✔
1799
                        Spec: hppv1.HostprotRemoteIpContainerSpec{
1✔
1800
                                Name:             ns,
1✔
1801
                                HostprotRemoteIp: []hppv1.HostprotRemoteIp{},
1✔
1802
                        },
1✔
1803
                }
1✔
1804
        } else {
1✔
1805
                cont.log.Debug("HostprotRemoteIpContainers CR already exists: ", aobj)
×
1806
        }
×
1807

1808
        remIpCont, exists := cont.nsRemoteIpCont[ns]
1✔
1809
        if !exists {
2✔
1810
                if isUpdate {
1✔
1811
                        if !cont.deleteHostprotRemoteIpContainer(ns, sysNs) {
×
1812
                                return true
×
1813
                        }
×
1814
                } else {
1✔
1815
                        cont.log.Error("Couldn't find the ns in nsRemoteIpCont cache: ", ns)
1✔
1816
                        return false
1✔
1817
                }
1✔
1818
        }
1819

1820
        aobj.Spec.HostprotRemoteIp = buildHostprotRemoteIpList(remIpCont)
1✔
1821

1✔
1822
        if isUpdate {
1✔
1823
                if !cont.updateHostprotRemoteIpContainer(aobj, sysNs) {
×
1824
                        return true
×
1825
                }
×
1826
        } else {
1✔
1827
                if !cont.createHostprotRemoteIpContainer(aobj, sysNs) {
1✔
1828
                        return true
×
1829
                }
×
1830
        }
1831

1832
        return false
1✔
1833
}
1834

1835
func buildHostprotRemoteIpList(remIpConts map[string]remoteIpCont) []hppv1.HostprotRemoteIp {
1✔
1836
        hostprotRemoteIpList := []hppv1.HostprotRemoteIp{}
1✔
1837

1✔
1838
        for _, remIpCont := range remIpConts {
2✔
1839
                for ip, labels := range remIpCont {
2✔
1840
                        remIpObj := hppv1.HostprotRemoteIp{
1✔
1841
                                Addr: ip,
1✔
1842
                        }
1✔
1843
                        for key, val := range labels {
2✔
1844
                                remIpObj.HppEpLabel = append(remIpObj.HppEpLabel, hppv1.HppEpLabel{
1✔
1845
                                        Key:   key,
1✔
1846
                                        Value: val,
1✔
1847
                                })
1✔
1848
                        }
1✔
1849
                        hostprotRemoteIpList = append(hostprotRemoteIpList, remIpObj)
1✔
1850
                }
1851
        }
1852

1853
        return hostprotRemoteIpList
1✔
1854
}
1855

1856
func (cont *AciController) deleteHppCr(np *v1net.NetworkPolicy) bool {
1✔
1857
        key, err := cache.MetaNamespaceKeyFunc(np)
1✔
1858
        logger := networkPolicyLogger(cont.log, np)
1✔
1859
        if err != nil {
1✔
1860
                logger.Error("Could not create network policy key: ", err)
×
1861
                return false
×
1862
        }
×
1863
        hash, err := util.CreateHashFromNetPol(np)
1✔
1864
        if err != nil {
1✔
1865
                logger.Error("Could not create hash from network policy: ", err)
×
1866
                return false
×
1867
        }
×
1868
        labelKey := cont.aciNameForKey("np", hash)
1✔
1869
        ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
1870
        hppName := strings.ReplaceAll(labelKey, "_", "-")
1✔
1871
        hpp, _ := cont.getHostprotPol(hppName, ns)
1✔
1872
        if hpp == nil {
2✔
1873
                logger.Error("Could not find hostprotPol: ", hppName)
1✔
1874
                return false
1✔
1875
        }
1✔
1876
        netPols := hpp.Spec.NetworkPolicies
1✔
1877
        newNetPols := make([]string, 0)
1✔
1878
        for _, npName := range netPols {
2✔
1879
                if npName != key {
2✔
1880
                        newNetPols = append(newNetPols, npName)
1✔
1881
                }
1✔
1882
        }
1883

1884
        hpp.Spec.NetworkPolicies = newNetPols
1✔
1885

1✔
1886
        if len(newNetPols) > 0 {
2✔
1887
                return cont.updateHostprotPol(hpp, ns)
1✔
1888
        } else {
2✔
1889
                return cont.deleteHostprotPol(hppName, ns)
1✔
1890
        }
1✔
1891
}
1892

1893
func (cont *AciController) updateNodeIpsHostprotRemoteIpContainer(nodeIps map[string]bool) {
1✔
1894
        ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
1895
        name := "nodeips"
1✔
1896

1✔
1897
        aobj, err := cont.getHostprotRemoteIpContainer(name, ns)
1✔
1898
        isUpdate := err == nil
1✔
1899

1✔
1900
        if err != nil && !errors.IsNotFound(err) {
1✔
1901
                cont.log.Error("Error getting HostprotRemoteIpContainers CR: ", err)
×
1902
                return
×
1903
        }
×
1904

1905
        if !isUpdate {
2✔
1906
                aobj = &hppv1.HostprotRemoteIpContainer{
1✔
1907
                        ObjectMeta: metav1.ObjectMeta{
1✔
1908
                                Name:      name,
1✔
1909
                                Namespace: ns,
1✔
1910
                        },
1✔
1911
                        Spec: hppv1.HostprotRemoteIpContainerSpec{
1✔
1912
                                Name:             name,
1✔
1913
                                HostprotRemoteIp: []hppv1.HostprotRemoteIp{},
1✔
1914
                        },
1✔
1915
                }
1✔
1916
        } else {
2✔
1917
                cont.log.Debug("HostprotRemoteIpContainers CR already exists: ", aobj)
1✔
1918
        }
1✔
1919

1920
        existingIps := make(map[string]bool)
1✔
1921
        for _, ip := range aobj.Spec.HostprotRemoteIp {
2✔
1922
                existingIps[ip.Addr] = true
1✔
1923
        }
1✔
1924

1925
        for ip := range nodeIps {
2✔
1926
                if !existingIps[ip] {
2✔
1927
                        aobj.Spec.HostprotRemoteIp = append(aobj.Spec.HostprotRemoteIp, hppv1.HostprotRemoteIp{Addr: ip})
1✔
1928
                }
1✔
1929
        }
1930

1931
        if isUpdate {
2✔
1932
                cont.updateHostprotRemoteIpContainer(aobj, ns)
1✔
1933
        } else {
2✔
1934
                cont.createHostprotRemoteIpContainer(aobj, ns)
1✔
1935
        }
1✔
1936
}
1937

1938
func (cont *AciController) deleteNodeIpsHostprotRemoteIpContainer(nodeIps map[string]bool) {
1✔
1939
        ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
1940
        name := "nodeips"
1✔
1941

1✔
1942
        aobj, _ := cont.getHostprotRemoteIpContainer(name, ns)
1✔
1943
        if aobj == nil {
1✔
1944
                return
×
1945
        }
×
1946

1947
        newHostprotRemoteIps := aobj.Spec.HostprotRemoteIp[:0]
1✔
1948
        for _, hostprotRemoteIp := range aobj.Spec.HostprotRemoteIp {
2✔
1949
                if len(nodeIps) > 0 && !nodeIps[hostprotRemoteIp.Addr] {
2✔
1950
                        newHostprotRemoteIps = append(newHostprotRemoteIps, hostprotRemoteIp)
1✔
1951
                }
1✔
1952
        }
1953

1954
        aobj.Spec.HostprotRemoteIp = newHostprotRemoteIps
1✔
1955

1✔
1956
        if len(newHostprotRemoteIps) > 0 {
2✔
1957
                cont.updateHostprotRemoteIpContainer(aobj, ns)
1✔
1958
        } else {
2✔
1959
                cont.deleteHostprotRemoteIpContainer(name, ns)
1✔
1960
        }
1✔
1961
}
1962

1963
func (cont *AciController) updateNodeHostprotRemoteIpContainer(name string, nodeIps map[string]bool) {
1✔
1964
        ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
1965

1✔
1966
        aobj, err := cont.getHostprotRemoteIpContainer(name, ns)
1✔
1967
        isUpdate := err == nil
1✔
1968

1✔
1969
        if err != nil && !errors.IsNotFound(err) {
1✔
1970
                cont.log.Error("Error getting HostprotRemoteIpContainers CR: ", err)
×
1971
                return
×
1972
        }
×
1973

1974
        if !isUpdate {
2✔
1975
                aobj = &hppv1.HostprotRemoteIpContainer{
1✔
1976
                        ObjectMeta: metav1.ObjectMeta{
1✔
1977
                                Name:      name,
1✔
1978
                                Namespace: ns,
1✔
1979
                        },
1✔
1980
                        Spec: hppv1.HostprotRemoteIpContainerSpec{
1✔
1981
                                Name:             name,
1✔
1982
                                HostprotRemoteIp: []hppv1.HostprotRemoteIp{},
1✔
1983
                        },
1✔
1984
                }
1✔
1985
        } else {
2✔
1986
                cont.log.Debug("HostprotRemoteIpContainers CR already exists: ", aobj)
1✔
1987
        }
1✔
1988

1989
        aobj.Spec.HostprotRemoteIp = make([]hppv1.HostprotRemoteIp, 0, len(nodeIps))
1✔
1990
        for ip := range nodeIps {
2✔
1991
                aobj.Spec.HostprotRemoteIp = append(aobj.Spec.HostprotRemoteIp, hppv1.HostprotRemoteIp{Addr: ip})
1✔
1992
        }
1✔
1993

1994
        if isUpdate {
2✔
1995
                cont.updateHostprotRemoteIpContainer(aobj, ns)
1✔
1996
        } else {
2✔
1997
                cont.createHostprotRemoteIpContainer(aobj, ns)
1✔
1998
        }
1✔
1999
}
2000

2001
func (cont *AciController) deleteNodeHostprotRemoteIpContainer(name string) {
1✔
2002
        ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
2003

1✔
2004
        if _, err := cont.getHostprotRemoteIpContainer(name, ns); err == nil {
2✔
2005
                cont.deleteHostprotRemoteIpContainer(name, ns)
1✔
2006
        }
1✔
2007
}
2008

2009
func (cont *AciController) createNodeHostProtPol(name, nodeName string, nodeIps map[string]bool) {
1✔
2010
        ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
2011
        hppName := strings.ReplaceAll(name, "_", "-")
1✔
2012

1✔
2013
        hpp, err := cont.getHostprotPol(hppName, ns)
1✔
2014
        isUpdate := hpp != nil && err == nil
1✔
2015

1✔
2016
        if err != nil && !errors.IsNotFound(err) {
1✔
2017
                cont.log.Error("Error getting HPP CR: ", err)
×
2018
                return
×
2019
        }
×
2020

2021
        if !isUpdate {
1✔
2022
                hpp = &hppv1.HostprotPol{
×
2023
                        ObjectMeta: metav1.ObjectMeta{
×
2024
                                Name:      hppName,
×
2025
                                Namespace: ns,
×
2026
                        },
×
2027
                        Spec: hppv1.HostprotPolSpec{
×
2028
                                Name:            name,
×
2029
                                NetworkPolicies: []string{name},
×
2030
                                HostprotSubj:    []hppv1.HostprotSubj{},
×
2031
                        },
×
2032
                }
×
2033
        } else {
1✔
2034
                cont.log.Debug("HPP CR already exists: ", hpp)
1✔
2035
                hpp.Spec.HostprotSubj = []hppv1.HostprotSubj{}
1✔
2036
        }
1✔
2037

2038
        if len(nodeIps) > 0 {
2✔
2039
                cont.updateNodeHostprotRemoteIpContainer(nodeName, nodeIps)
1✔
2040
                cont.updateNodeIpsHostprotRemoteIpContainer(nodeIps)
1✔
2041

1✔
2042
                hostprotSubj := hppv1.HostprotSubj{
1✔
2043
                        Name: "local-node",
1✔
2044
                        HostprotRule: []hppv1.HostprotRule{
1✔
2045
                                {
1✔
2046
                                        Name:                "allow-all-egress",
1✔
2047
                                        Direction:           "egress",
1✔
2048
                                        Ethertype:           "ipv4",
1✔
2049
                                        ConnTrack:           "normal",
1✔
2050
                                        RsRemoteIpContainer: []string{nodeName},
1✔
2051
                                },
1✔
2052
                                {
1✔
2053
                                        Name:                "allow-all-ingress",
1✔
2054
                                        Direction:           "ingress",
1✔
2055
                                        Ethertype:           "ipv4",
1✔
2056
                                        ConnTrack:           "normal",
1✔
2057
                                        RsRemoteIpContainer: []string{nodeName},
1✔
2058
                                },
1✔
2059
                        },
1✔
2060
                }
1✔
2061

1✔
2062
                hpp.Spec.HostprotSubj = append(hpp.Spec.HostprotSubj, hostprotSubj)
1✔
2063
        } else {
2✔
2064
                cont.deleteNodeHostprotRemoteIpContainer(nodeName)
1✔
2065
                cont.deleteNodeIpsHostprotRemoteIpContainer(nodeIps)
1✔
2066
        }
1✔
2067

2068
        if isUpdate {
2✔
2069
                cont.updateHostprotPol(hpp, ns)
1✔
2070
        } else {
1✔
2071
                cont.createHostprotPol(hpp, ns)
×
2072
        }
×
2073
}
2074

2075
func (cont *AciController) handleNetPolUpdate(np *v1net.NetworkPolicy) bool {
1✔
2076
        if cont.isCNOEnabled() {
1✔
2077
                return false
×
2078
        }
×
2079
        key, err := cache.MetaNamespaceKeyFunc(np)
1✔
2080
        logger := networkPolicyLogger(cont.log, np)
1✔
2081
        if err != nil {
1✔
2082
                logger.Error("Could not create network policy key: ", err)
×
2083
                return false
×
2084
        }
×
2085

2086
        peerPodKeys := cont.netPolIngressPods.GetPodForObj(key)
1✔
2087
        peerPodKeys =
1✔
2088
                append(peerPodKeys, cont.netPolEgressPods.GetPodForObj(key)...)
1✔
2089
        var peerPods []*v1.Pod
1✔
2090
        peerNs := make(map[string]*v1.Namespace)
1✔
2091
        for _, podkey := range peerPodKeys {
2✔
2092
                podobj, exists, err := cont.podIndexer.GetByKey(podkey)
1✔
2093
                if exists && err == nil {
2✔
2094
                        pod := podobj.(*v1.Pod)
1✔
2095
                        if _, nsok := peerNs[pod.ObjectMeta.Namespace]; !nsok {
2✔
2096
                                nsobj, exists, err :=
1✔
2097
                                        cont.namespaceIndexer.GetByKey(pod.ObjectMeta.Namespace)
1✔
2098
                                if !exists || err != nil {
1✔
2099
                                        continue
×
2100
                                }
2101
                                peerNs[pod.ObjectMeta.Namespace] = nsobj.(*v1.Namespace)
1✔
2102
                        }
2103
                        peerPods = append(peerPods, pod)
1✔
2104
                }
2105
        }
2106
        ptypeset := make(map[v1net.PolicyType]bool)
1✔
2107
        for _, t := range np.Spec.PolicyTypes {
2✔
2108
                ptypeset[t] = true
1✔
2109
        }
1✔
2110
        var labelKey string
1✔
2111

1✔
2112
        if !cont.config.EnableHppDirect {
2✔
2113
                if cont.config.HppOptimization {
2✔
2114
                        hash, err := util.CreateHashFromNetPol(np)
1✔
2115
                        if err != nil {
1✔
2116
                                logger.Error("Could not create hash from network policy: ", err)
×
2117
                                return false
×
2118
                        }
×
2119
                        labelKey = cont.aciNameForKey("np", hash)
1✔
2120
                } else {
1✔
2121
                        labelKey = cont.aciNameForKey("np", key)
1✔
2122
                }
1✔
2123
                hpp := apicapi.NewHostprotPol(cont.config.AciPolicyTenant, labelKey)
1✔
2124
                // Generate ingress policies
1✔
2125
                if np.Spec.PolicyTypes == nil || ptypeset[v1net.PolicyTypeIngress] {
2✔
2126
                        subjIngress :=
1✔
2127
                                apicapi.NewHostprotSubj(hpp.GetDn(), "networkpolicy-ingress")
1✔
2128

1✔
2129
                        for i, ingress := range np.Spec.Ingress {
2✔
2130
                                addPodSubnetAsRemIp := isAllowAllForAllNamespaces(ingress.From)
1✔
2131
                                remoteSubnets, _, _, _, _ := cont.getPeerRemoteSubnets(ingress.From,
1✔
2132
                                        np.Namespace, peerPods, peerNs, logger)
1✔
2133
                                cont.buildNetPolSubjRules(strconv.Itoa(i), subjIngress,
1✔
2134
                                        "ingress", ingress.From, remoteSubnets, ingress.Ports, logger, key, np, addPodSubnetAsRemIp)
1✔
2135
                        }
1✔
2136
                        hpp.AddChild(subjIngress)
1✔
2137
                }
2138
                // Generate egress policies
2139
                if np.Spec.PolicyTypes == nil || ptypeset[v1net.PolicyTypeEgress] {
2✔
2140
                        subjEgress :=
1✔
2141
                                apicapi.NewHostprotSubj(hpp.GetDn(), "networkpolicy-egress")
1✔
2142

1✔
2143
                        portRemoteSubs := make(map[string]*portRemoteSubnet)
1✔
2144

1✔
2145
                        for i, egress := range np.Spec.Egress {
2✔
2146
                                addPodSubnetAsRemIp := isAllowAllForAllNamespaces(egress.To)
1✔
2147
                                remoteSubnets, _, _, subnetMap, _ := cont.getPeerRemoteSubnets(egress.To,
1✔
2148
                                        np.Namespace, peerPods, peerNs, logger)
1✔
2149
                                cont.buildNetPolSubjRules(strconv.Itoa(i), subjEgress,
1✔
2150
                                        "egress", egress.To, remoteSubnets, egress.Ports, logger, key, np, addPodSubnetAsRemIp)
1✔
2151

1✔
2152
                                // creating a rule to egress to all on a given port needs
1✔
2153
                                // to enable access to any service IPs/ports that have
1✔
2154
                                // that port as their target port.
1✔
2155
                                if len(egress.To) == 0 {
2✔
2156
                                        subnetMap = map[string]bool{
1✔
2157
                                                "0.0.0.0/0": true,
1✔
2158
                                        }
1✔
2159
                                }
1✔
2160
                                for idx := range egress.Ports {
2✔
2161
                                        port := egress.Ports[idx]
1✔
2162
                                        portkey := portKey(&port)
1✔
2163
                                        updatePortRemoteSubnets(portRemoteSubs, portkey, &port, subnetMap,
1✔
2164
                                                port.Port != nil && port.Port.Type == intstr.Int)
1✔
2165
                                }
1✔
2166
                                if len(egress.Ports) == 0 {
2✔
2167
                                        updatePortRemoteSubnets(portRemoteSubs, "", nil, subnetMap,
1✔
2168
                                                false)
1✔
2169
                                }
1✔
2170
                        }
2171
                        cont.buildServiceAugment(subjEgress, nil, portRemoteSubs, logger)
1✔
2172
                        hpp.AddChild(subjEgress)
1✔
2173
                }
2174
                if cont.config.HppOptimization {
2✔
2175
                        cont.addToHppCache(labelKey, key, apicapi.ApicSlice{hpp}, &hppv1.HostprotPol{})
1✔
2176
                }
1✔
2177
                cont.apicConn.WriteApicObjects(labelKey, apicapi.ApicSlice{hpp})
1✔
2178
        } else {
1✔
2179
                hash, err := util.CreateHashFromNetPol(np)
1✔
2180
                if err != nil {
1✔
2181
                        logger.Error("Could not create hash from network policy: ", err)
×
2182
                        return false
×
2183
                }
×
2184
                labelKey = cont.aciNameForKey("np", hash)
1✔
2185
                ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
2186
                hppName := strings.ReplaceAll(labelKey, "_", "-")
1✔
2187
                hpp, err := cont.getHostprotPol(hppName, ns)
1✔
2188
                isUpdate := err == nil
1✔
2189

1✔
2190
                if err != nil && !errors.IsNotFound(err) {
1✔
2191
                        logger.Error("Error getting HPP CR: ", err)
×
2192
                        return false
×
2193
                }
×
2194

2195
                if isUpdate {
1✔
2196
                        logger.Debug("HPP CR already exists: ", hpp)
×
2197
                        if !slices.Contains(hpp.Spec.NetworkPolicies, key) {
×
2198
                                hpp.Spec.NetworkPolicies = append(hpp.Spec.NetworkPolicies, key)
×
2199
                        }
×
2200
                        hpp.Spec.HostprotSubj = nil
×
2201
                } else {
1✔
2202
                        hpp = &hppv1.HostprotPol{
1✔
2203
                                ObjectMeta: metav1.ObjectMeta{
1✔
2204
                                        Name:      hppName,
1✔
2205
                                        Namespace: ns,
1✔
2206
                                },
1✔
2207
                                Spec: hppv1.HostprotPolSpec{
1✔
2208
                                        Name:            labelKey,
1✔
2209
                                        NetworkPolicies: []string{key},
1✔
2210
                                        HostprotSubj:    nil,
1✔
2211
                                },
1✔
2212
                        }
1✔
2213
                }
1✔
2214

2215
                // Generate ingress policies
2216
                if np.Spec.PolicyTypes == nil || ptypeset[v1net.PolicyTypeIngress] {
2✔
2217
                        subjIngress := &hppv1.HostprotSubj{
1✔
2218
                                Name:         "networkpolicy-ingress",
1✔
2219
                                HostprotRule: []hppv1.HostprotRule{},
1✔
2220
                        }
1✔
2221

1✔
2222
                        for i, ingress := range np.Spec.Ingress {
2✔
2223
                                remoteSubnets, peerNsList, peerremote, _, peerIpBlock := cont.getPeerRemoteSubnets(ingress.From,
1✔
2224
                                        np.Namespace, peerPods, peerNs, logger)
1✔
2225
                                if isAllowAllForAllNamespaces(ingress.From) {
1✔
2226
                                        peerNsList = append(peerNsList, "nodeips")
×
2227
                                }
×
2228
                                if !(len(ingress.From) > 0 && len(remoteSubnets) == 0) {
2✔
2229
                                        cont.buildLocalNetPolSubjRules(strconv.Itoa(i), subjIngress,
1✔
2230
                                                "ingress", peerNsList, peerremote.podSelectors, ingress.Ports,
1✔
2231
                                                logger, key, np, peerIpBlock)
1✔
2232
                                }
1✔
2233
                        }
2234
                        hpp.Spec.HostprotSubj = append(hpp.Spec.HostprotSubj, *subjIngress)
1✔
2235
                }
2236

2237
                if np.Spec.PolicyTypes == nil || ptypeset[v1net.PolicyTypeEgress] {
2✔
2238
                        subjEgress := &hppv1.HostprotSubj{
1✔
2239
                                Name:         "networkpolicy-egress",
1✔
2240
                                HostprotRule: []hppv1.HostprotRule{},
1✔
2241
                        }
1✔
2242

1✔
2243
                        portRemoteSubs := make(map[string]*portRemoteSubnet)
1✔
2244

1✔
2245
                        for i, egress := range np.Spec.Egress {
2✔
2246
                                remoteSubnets, peerNsList, peerremote, subnetMap, peerIpBlock := cont.getPeerRemoteSubnets(egress.To,
1✔
2247
                                        np.Namespace, peerPods, peerNs, logger)
1✔
2248
                                if isAllowAllForAllNamespaces(egress.To) {
1✔
2249
                                        peerNsList = append(peerNsList, "nodeips")
×
2250
                                }
×
2251
                                if !(len(egress.To) > 0 && len(remoteSubnets) == 0) {
2✔
2252
                                        cont.buildLocalNetPolSubjRules(strconv.Itoa(i), subjEgress,
1✔
2253
                                                "egress", peerNsList, peerremote.podSelectors, egress.Ports, logger, key, np, peerIpBlock)
1✔
2254
                                }
1✔
2255

2256
                                if len(egress.To) == 0 {
2✔
2257
                                        subnetMap = map[string]bool{"0.0.0.0/0": true}
1✔
2258
                                }
1✔
2259
                                for idx := range egress.Ports {
2✔
2260
                                        port := egress.Ports[idx]
1✔
2261
                                        portkey := portKey(&port)
1✔
2262
                                        updatePortRemoteSubnets(portRemoteSubs, portkey, &port, subnetMap,
1✔
2263
                                                port.Port != nil && port.Port.Type == intstr.Int)
1✔
2264
                                }
1✔
2265
                                if len(egress.Ports) == 0 {
1✔
2266
                                        updatePortRemoteSubnets(portRemoteSubs, "", nil, subnetMap,
×
2267
                                                false)
×
2268
                                }
×
2269
                        }
2270
                        cont.buildServiceAugment(nil, subjEgress, portRemoteSubs, logger)
1✔
2271
                        hpp.Spec.HostprotSubj = append(hpp.Spec.HostprotSubj, *subjEgress)
1✔
2272
                }
2273

2274
                cont.addToHppCache(labelKey, key, apicapi.ApicSlice{}, hpp)
1✔
2275

1✔
2276
                if isUpdate {
1✔
2277
                        cont.updateHostprotPol(hpp, ns)
×
2278
                } else {
1✔
2279
                        cont.createHostprotPol(hpp, ns)
1✔
2280
                }
1✔
2281
        }
2282
        return false
1✔
2283
}
2284

2285
func (cont *AciController) updateNsRemoteIpCont(pod *v1.Pod, deleted bool) bool {
1✔
2286
        podips := ipsForPod(pod)
1✔
2287
        podns := pod.ObjectMeta.Namespace
1✔
2288
        podname := pod.ObjectMeta.Name
1✔
2289
        podlabels := pod.ObjectMeta.Labels
1✔
2290
        remipconts, ok := cont.nsRemoteIpCont[podns]
1✔
2291

1✔
2292
        if deleted {
2✔
2293
                if !ok {
2✔
2294
                        return true
1✔
2295
                }
1✔
2296

2297
                present := false
1✔
2298
                if remipcont, remipcontok := remipconts[podname]; remipcontok {
1✔
2299
                        for _, ip := range podips {
×
2300
                                if _, ipok := remipcont[ip]; ipok {
×
2301
                                        delete(remipcont, ip)
×
2302
                                        present = true
×
2303
                                }
×
2304
                        }
2305
                        if len(remipcont) < 1 {
×
2306
                                delete(remipconts, podname)
×
2307
                        }
×
2308
                }
2309

2310
                if len(remipconts) < 1 {
1✔
2311
                        delete(cont.nsRemoteIpCont, podns)
×
2312
                        cont.apicConn.ClearApicObjects(cont.aciNameForKey("hostprot-ns-", podns))
×
2313
                        return false
×
2314
                }
×
2315

2316
                if !present {
2✔
2317
                        return false
1✔
2318
                }
1✔
2319
        } else {
1✔
2320
                if !ok {
2✔
2321
                        remipconts = make(remoteIpConts)
1✔
2322
                        cont.nsRemoteIpCont[podns] = remipconts
1✔
2323
                }
1✔
2324

2325
                remipcont, remipcontok := remipconts[podname]
1✔
2326
                if !remipcontok {
2✔
2327
                        remipcont = make(remoteIpCont)
1✔
2328
                }
1✔
2329
                for _, ip := range podips {
2✔
2330
                        remipcont[ip] = podlabels
1✔
2331
                }
1✔
2332
                remipconts[podname] = remipcont
1✔
2333
        }
2334

2335
        return true
1✔
2336
}
2337

2338
func (cont *AciController) addToHppCache(labelKey, key string, hpp apicapi.ApicSlice, hppcr *hppv1.HostprotPol) {
1✔
2339
        cont.indexMutex.Lock()
1✔
2340
        hppRef, ok := cont.hppRef[labelKey]
1✔
2341
        if ok {
2✔
2342
                var found bool
1✔
2343
                for _, npkey := range hppRef.Npkeys {
2✔
2344
                        if npkey == key {
2✔
2345
                                found = true
1✔
2346
                                break
1✔
2347
                        }
2348
                }
2349
                if !found {
1✔
2350
                        hppRef.RefCount++
×
2351
                        hppRef.Npkeys = append(hppRef.Npkeys, key)
×
2352
                }
×
2353
                hppRef.HppObj = hpp
1✔
2354
                hppRef.HppCr = *hppcr
1✔
2355
                cont.hppRef[labelKey] = hppRef
1✔
2356
        } else {
1✔
2357
                var newHppRef hppReference
1✔
2358
                newHppRef.RefCount++
1✔
2359
                newHppRef.HppObj = hpp
1✔
2360
                newHppRef.HppCr = *hppcr
1✔
2361
                newHppRef.Npkeys = append(newHppRef.Npkeys, key)
1✔
2362
                cont.hppRef[labelKey] = newHppRef
1✔
2363
        }
1✔
2364
        cont.indexMutex.Unlock()
1✔
2365
}
2366

2367
func (cont *AciController) removeFromHppCache(np *v1net.NetworkPolicy, key string) (string, bool) {
1✔
2368
        var labelKey string
1✔
2369
        var noRef bool
1✔
2370
        hash, err := util.CreateHashFromNetPol(np)
1✔
2371
        if err != nil {
1✔
2372
                cont.log.Error("Could not create hash from network policy: ", err)
×
2373
                cont.log.Error("Failed to remove np from hpp cache")
×
2374
                return labelKey, noRef
×
2375
        }
×
2376
        labelKey = cont.aciNameForKey("np", hash)
1✔
2377
        cont.indexMutex.Lock()
1✔
2378
        hppRef, ok := cont.hppRef[labelKey]
1✔
2379
        if ok {
2✔
2380
                for i, npkey := range hppRef.Npkeys {
2✔
2381
                        if npkey == key {
2✔
2382
                                hppRef.Npkeys = append(hppRef.Npkeys[:i], hppRef.Npkeys[i+1:]...)
1✔
2383
                                hppRef.RefCount--
1✔
2384
                                break
1✔
2385
                        }
2386
                }
2387
                if hppRef.RefCount > 0 {
1✔
2388
                        cont.hppRef[labelKey] = hppRef
×
2389
                } else {
1✔
2390
                        delete(cont.hppRef, labelKey)
1✔
2391
                        noRef = true
1✔
2392
                }
1✔
2393
        }
2394
        cont.indexMutex.Unlock()
1✔
2395
        return labelKey, noRef
1✔
2396
}
2397

2398
func getNetworkPolicyEgressIpBlocks(np *v1net.NetworkPolicy) map[string]bool {
1✔
2399
        subnets := make(map[string]bool)
1✔
2400
        for _, egress := range np.Spec.Egress {
2✔
2401
                for _, to := range egress.To {
2✔
2402
                        if to.IPBlock != nil && to.IPBlock.CIDR != "" {
2✔
2403
                                subnets[to.IPBlock.CIDR] = true
1✔
2404
                        }
1✔
2405
                }
2406
        }
2407
        return subnets
1✔
2408
}
2409

2410
func (cont *AciController) networkPolicyAdded(obj interface{}) {
1✔
2411
        np := obj.(*v1net.NetworkPolicy)
1✔
2412
        npkey, err := cache.MetaNamespaceKeyFunc(np)
1✔
2413
        if err != nil {
1✔
2414
                networkPolicyLogger(cont.log, np).
×
2415
                        Error("Could not create network policy key: ", err)
×
2416
                return
×
2417
        }
×
2418
        if cont.isCNOEnabled() {
1✔
2419
                return
×
2420
        }
×
2421
        cont.netPolPods.UpdateSelectorObj(obj)
1✔
2422
        cont.netPolIngressPods.UpdateSelectorObj(obj)
1✔
2423
        cont.netPolEgressPods.UpdateSelectorObj(obj)
1✔
2424
        cont.indexMutex.Lock()
1✔
2425
        subnets := getNetworkPolicyEgressIpBlocks(np)
1✔
2426
        cont.updateIpIndex(cont.netPolSubnetIndex, nil, subnets, npkey)
1✔
2427

1✔
2428
        ports := cont.getNetPolTargetPorts(np)
1✔
2429
        cont.updateTargetPortIndex(false, npkey, nil, ports)
1✔
2430
        if isNamedPortPresenInNp(np) {
2✔
2431
                cont.nmPortNp[npkey] = true
1✔
2432
        }
1✔
2433
        cont.indexMutex.Unlock()
1✔
2434
        cont.queueNetPolUpdateByKey(npkey)
1✔
2435
}
2436

2437
func (cont *AciController) networkPolicyChanged(oldobj interface{},
2438
        newobj interface{}) {
×
2439
        oldnp := oldobj.(*v1net.NetworkPolicy)
×
2440
        newnp := newobj.(*v1net.NetworkPolicy)
×
2441
        npkey, err := cache.MetaNamespaceKeyFunc(newnp)
×
2442
        if err != nil {
×
2443
                networkPolicyLogger(cont.log, newnp).
×
2444
                        Error("Could not create network policy key: ", err)
×
2445
                return
×
2446
        }
×
2447

2448
        if cont.config.HppOptimization || cont.config.EnableHppDirect {
×
2449
                if !reflect.DeepEqual(oldnp.Spec, newnp.Spec) {
×
2450
                        cont.removeFromHppCache(oldnp, npkey)
×
2451
                }
×
2452
        }
2453

2454
        cont.indexMutex.Lock()
×
2455
        oldSubnets := getNetworkPolicyEgressIpBlocks(oldnp)
×
2456
        newSubnets := getNetworkPolicyEgressIpBlocks(newnp)
×
2457
        cont.updateIpIndex(cont.netPolSubnetIndex, oldSubnets, newSubnets, npkey)
×
2458

×
2459
        oldPorts := cont.getNetPolTargetPorts(oldnp)
×
2460
        newPorts := cont.getNetPolTargetPorts(newnp)
×
2461
        cont.updateTargetPortIndex(false, npkey, oldPorts, newPorts)
×
2462
        cont.indexMutex.Unlock()
×
2463

×
2464
        if !reflect.DeepEqual(oldnp.Spec.PodSelector, newnp.Spec.PodSelector) {
×
2465
                cont.netPolPods.UpdateSelectorObjNoCallback(newobj)
×
2466
        }
×
2467
        if !reflect.DeepEqual(oldnp.Spec.PolicyTypes, newnp.Spec.PolicyTypes) {
×
2468
                peerPodKeys := cont.netPolPods.GetPodForObj(npkey)
×
2469
                for _, podkey := range peerPodKeys {
×
2470
                        cont.podQueue.Add(podkey)
×
2471
                }
×
2472
        }
2473
        var queue bool
×
2474
        if !reflect.DeepEqual(oldnp.Spec.Ingress, newnp.Spec.Ingress) {
×
2475
                cont.netPolIngressPods.UpdateSelectorObjNoCallback(newobj)
×
2476
                queue = true
×
2477
        }
×
2478
        if !reflect.DeepEqual(oldnp.Spec.Egress, newnp.Spec.Egress) {
×
2479
                cont.netPolEgressPods.UpdateSelectorObjNoCallback(newobj)
×
2480
                queue = true
×
2481
        }
×
2482
        if cont.config.EnableHppDirect && !reflect.DeepEqual(oldnp.Spec, newnp.Spec) {
×
2483
                cont.deleteHppCr(oldnp)
×
2484
                queue = true
×
2485
        }
×
2486
        if queue {
×
2487
                cont.queueNetPolUpdateByKey(npkey)
×
2488
        }
×
2489
}
2490

2491
func (cont *AciController) networkPolicyDeleted(obj interface{}) {
1✔
2492
        np, isNetworkpolicy := obj.(*v1net.NetworkPolicy)
1✔
2493
        if !isNetworkpolicy {
1✔
2494
                deletedState, ok := obj.(cache.DeletedFinalStateUnknown)
×
2495
                if !ok {
×
2496
                        networkPolicyLogger(cont.log, np).
×
2497
                                Error("Received unexpected object: ", obj)
×
2498
                        return
×
2499
                }
×
2500
                np, ok = deletedState.Obj.(*v1net.NetworkPolicy)
×
2501
                if !ok {
×
2502
                        networkPolicyLogger(cont.log, np).
×
2503
                                Error("DeletedFinalStateUnknown contained non-Networkpolicy object: ", deletedState.Obj)
×
2504
                        return
×
2505
                }
×
2506
        }
2507
        npkey, err := cache.MetaNamespaceKeyFunc(np)
1✔
2508
        if err != nil {
1✔
2509
                networkPolicyLogger(cont.log, np).
×
2510
                        Error("Could not create network policy key: ", err)
×
2511
                return
×
2512
        }
×
2513

2514
        var labelKey string
1✔
2515
        var noHppRef bool
1✔
2516
        if cont.config.HppOptimization || cont.config.EnableHppDirect {
1✔
2517
                labelKey, noHppRef = cont.removeFromHppCache(np, npkey)
×
2518
        } else {
1✔
2519
                labelKey = cont.aciNameForKey("np", npkey)
1✔
2520
                noHppRef = true
1✔
2521
        }
1✔
2522

2523
        cont.indexMutex.Lock()
1✔
2524
        subnets := getNetworkPolicyEgressIpBlocks(np)
1✔
2525
        cont.updateIpIndex(cont.netPolSubnetIndex, subnets, nil, npkey)
1✔
2526

1✔
2527
        ports := cont.getNetPolTargetPorts(np)
1✔
2528
        cont.updateTargetPortIndex(false, npkey, ports, nil)
1✔
2529
        if isNamedPortPresenInNp(np) {
2✔
2530
                delete(cont.nmPortNp, npkey)
1✔
2531
        }
1✔
2532
        cont.indexMutex.Unlock()
1✔
2533

1✔
2534
        cont.netPolPods.DeleteSelectorObj(obj)
1✔
2535
        cont.netPolIngressPods.DeleteSelectorObj(obj)
1✔
2536
        cont.netPolEgressPods.DeleteSelectorObj(obj)
1✔
2537
        if noHppRef && labelKey != "" {
2✔
2538
                cont.apicConn.ClearApicObjects(labelKey)
1✔
2539
        }
1✔
2540
        if cont.config.EnableHppDirect {
1✔
2541
                cont.deleteHppCr(np)
×
2542
        }
×
2543
}
2544

2545
func (sep *serviceEndpoint) SetNpServiceAugmentForService(servicekey string, service *v1.Service, prs *portRemoteSubnet,
2546
        portAugments map[string]*portServiceAugment, subnetIndex cidranger.Ranger, logger *logrus.Entry) {
1✔
2547
        cont := sep.cont
1✔
2548
        endpointsobj, _, err := cont.endpointsIndexer.GetByKey(servicekey)
1✔
2549
        if err != nil {
1✔
2550
                logger.Error("Could not lookup endpoints for "+
×
2551
                        servicekey+": ", err.Error())
×
2552
                return
×
2553
        }
×
2554
        if endpointsobj == nil {
1✔
2555
                return
×
2556
        }
×
2557
        endpoints := endpointsobj.(*v1.Endpoints)
1✔
2558
        portstrings := make(map[string]bool)
1✔
2559
        ports := cont.getPortNums(prs.port)
1✔
2560
        for _, port := range ports {
2✔
2561
                portstrings[strconv.Itoa(port)] = true
1✔
2562
        }
1✔
2563
        for _, svcPort := range service.Spec.Ports {
2✔
2564
                _, ok := portstrings[svcPort.TargetPort.String()]
1✔
2565
                if prs.port != nil &&
1✔
2566
                        (svcPort.Protocol != *prs.port.Protocol || !ok) {
1✔
UNCOV
2567
                        // egress rule does not match service target port
×
UNCOV
2568
                        continue
×
2569
                }
2570
                for _, subset := range endpoints.Subsets {
2✔
2571
                        var foundEpPort *v1.EndpointPort
1✔
2572
                        for ix := range subset.Ports {
2✔
2573
                                if subset.Ports[ix].Name == svcPort.Name ||
1✔
2574
                                        (len(service.Spec.Ports) == 1 &&
1✔
2575
                                                subset.Ports[ix].Name == "") {
2✔
2576
                                        foundEpPort = &subset.Ports[ix]
1✔
2577
                                        break
1✔
2578
                                }
2579
                        }
2580
                        if foundEpPort == nil {
1✔
2581
                                continue
×
2582
                        }
2583

2584
                        incomplete := false
1✔
2585
                        incomplete = incomplete ||
1✔
2586
                                !checkEndpoints(subnetIndex, subset.Addresses)
1✔
2587
                        incomplete = incomplete || !checkEndpoints(subnetIndex,
1✔
2588
                                subset.NotReadyAddresses)
1✔
2589

1✔
2590
                        if incomplete {
2✔
2591
                                continue
1✔
2592
                        }
2593

2594
                        proto := portProto(&foundEpPort.Protocol)
1✔
2595
                        port := strconv.Itoa(int(svcPort.Port))
1✔
2596
                        updateServiceAugmentForService(portAugments,
1✔
2597
                                proto, port, service)
1✔
2598

1✔
2599
                        logger.WithFields(logrus.Fields{
1✔
2600
                                "proto":   proto,
1✔
2601
                                "port":    port,
1✔
2602
                                "service": servicekey,
1✔
2603
                        }).Debug("Allowing egress for service by subnet match")
1✔
2604
                }
2605
        }
2606
}
2607

2608
func (seps *serviceEndpointSlice) SetNpServiceAugmentForService(servicekey string, service *v1.Service,
2609
        prs *portRemoteSubnet, portAugments map[string]*portServiceAugment,
2610
        subnetIndex cidranger.Ranger, logger *logrus.Entry) {
1✔
2611
        cont := seps.cont
1✔
2612
        portstrings := make(map[string]bool)
1✔
2613
        ports := cont.getPortNums(prs.port)
1✔
2614
        for _, port := range ports {
2✔
2615
                portstrings[strconv.Itoa(port)] = true
1✔
2616
        }
1✔
2617
        label := map[string]string{discovery.LabelServiceName: service.ObjectMeta.Name}
1✔
2618
        selector := labels.SelectorFromSet(label)
1✔
2619
        cache.ListAllByNamespace(cont.endpointSliceIndexer, service.ObjectMeta.Namespace, selector,
1✔
2620
                func(endpointSliceobj interface{}) {
2✔
2621
                        endpointSlices := endpointSliceobj.(*discovery.EndpointSlice)
1✔
2622
                        for _, svcPort := range service.Spec.Ports {
2✔
2623
                                _, ok := portstrings[svcPort.TargetPort.String()]
1✔
2624
                                if prs.port != nil &&
1✔
2625
                                        (svcPort.Protocol != *prs.port.Protocol || !ok) {
2✔
2626
                                        // egress rule does not match service target port
1✔
2627
                                        continue
1✔
2628
                                }
2629
                                var foundEpPort *discovery.EndpointPort
1✔
2630
                                for ix := range endpointSlices.Ports {
2✔
2631
                                        if *endpointSlices.Ports[ix].Name == svcPort.Name ||
1✔
2632
                                                (len(service.Spec.Ports) == 1 &&
1✔
2633
                                                        *endpointSlices.Ports[ix].Name == "") {
2✔
2634
                                                foundEpPort = &endpointSlices.Ports[ix]
1✔
2635
                                                cont.log.Debug("Found EpPort: ", foundEpPort)
1✔
2636
                                                break
1✔
2637
                                        }
2638
                                }
2639
                                if foundEpPort == nil {
1✔
2640
                                        return
×
2641
                                }
×
2642
                                // @FIXME for non ready address
2643
                                incomplete := false
1✔
2644
                                for _, endpoint := range endpointSlices.Endpoints {
2✔
2645
                                        incomplete = incomplete || !checkEndpointslices(subnetIndex, endpoint.Addresses)
1✔
2646
                                }
1✔
2647
                                if incomplete {
2✔
2648
                                        continue
1✔
2649
                                }
2650
                                proto := portProto(foundEpPort.Protocol)
1✔
2651
                                port := strconv.Itoa(int(svcPort.Port))
1✔
2652
                                cont.log.Debug("updateServiceAugmentForService: ", service)
1✔
2653
                                updateServiceAugmentForService(portAugments,
1✔
2654
                                        proto, port, service)
1✔
2655

1✔
2656
                                logger.WithFields(logrus.Fields{
1✔
2657
                                        "proto":   proto,
1✔
2658
                                        "port":    port,
1✔
2659
                                        "service": servicekey,
1✔
2660
                                }).Debug("Allowing egress for service by subnet match")
1✔
2661
                        }
2662
                })
2663
}
2664

2665
func isNamedPortPresenInNp(np *v1net.NetworkPolicy) bool {
1✔
2666
        for _, egress := range np.Spec.Egress {
2✔
2667
                for _, p := range egress.Ports {
2✔
2668
                        if p.Port.Type == intstr.String {
2✔
2669
                                return true
1✔
2670
                        }
1✔
2671
                }
2672
        }
2673
        return false
1✔
2674
}
2675

2676
func (cont *AciController) checkPodNmpMatchesNp(npkey, podkey string) bool {
1✔
2677
        podobj, exists, err := cont.podIndexer.GetByKey(podkey)
1✔
2678
        if err != nil {
1✔
2679
                return false
×
2680
        }
×
2681
        if !exists || podobj == nil {
1✔
2682
                return false
×
2683
        }
×
2684
        pod := podobj.(*v1.Pod)
1✔
2685
        npobj, npexists, nperr := cont.networkPolicyIndexer.GetByKey(npkey)
1✔
2686
        if npexists && nperr == nil && npobj != nil {
2✔
2687
                np := npobj.(*v1net.NetworkPolicy)
1✔
2688
                for _, egress := range np.Spec.Egress {
2✔
2689
                        for _, p := range egress.Ports {
2✔
2690
                                if p.Port.Type == intstr.String {
2✔
2691
                                        _, err := k8util.LookupContainerPortNumberByName(*pod, p.Port.String())
1✔
2692
                                        if err == nil {
2✔
2693
                                                return true
1✔
2694
                                        }
1✔
2695
                                }
2696
                        }
2697
                }
2698
        }
2699
        return false
1✔
2700
}
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