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

noironetworks / aci-containers / 11463

24 Dec 2025 05:52AM UTC coverage: 63.105% (-0.004%) from 63.109%
11463

Pull #1652

travis-pro

web-flow
Merge 44c008909 into 416a49489
Pull Request #1652: Fixed missing double quote in supported versions

13370 of 21187 relevant lines covered (63.1%)

0.72 hits per line

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

79.7
/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✔
2567
                        // egress rule does not match service target port
×
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) {
1✔
2626
                                        // egress rule does not match service target port
×
2627
                                        continue
×
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