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

noironetworks / aci-containers / 11458

19 Dec 2025 11:30AM UTC coverage: 63.107% (-0.03%) from 63.133%
11458

push

travis-pro

allenantony-oc
Add support for port range in network policy

The aci-containers-controller previously ignored the endPort field
in NetworkPolicy rules. This resulted in incorrect ACI hostprotRule
objects that only enabled the starting port of an intended range.

This commit updates the controller to correctly process endPort.
It now maps the port field to fromPort and endPort to toPort,
ensuring that port ranges defined in a NetworkPolicy are properly
enforced in ACI.

31 of 44 new or added lines in 1 file covered. (70.45%)

8 existing lines in 3 files now uncovered.

13380 of 21202 relevant lines covered (63.11%)

0.72 hits per line

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

79.65
/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
type portRange struct {
920
        fromPort string
921
        toPort   string
922
}
923

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

940
func (cont *AciController) updateTargetPortIndex(service bool, key string,
941
        oldPorts map[string]targetPort, newPorts map[string]targetPort) {
1✔
942
        for portkey := range oldPorts {
2✔
943
                if _, ok := newPorts[portkey]; ok {
1✔
944
                        continue
×
945
                }
946

947
                entry, ok := cont.targetPortIndex[portkey]
1✔
948
                if !ok {
1✔
949
                        continue
×
950
                }
951

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

977
                if service {
2✔
978
                        entry.serviceKeys[key] = true
1✔
979
                } else {
2✔
980
                        entry.networkPolicyKeys[key] = true
1✔
981
                }
1✔
982
        }
983
}
984

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

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

1064
type peerRemoteInfo struct {
1065
        remotePods   []*v1.Pod
1066
        podSelectors []*metav1.LabelSelector
1067
}
1068

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

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

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

1138
func (cont *AciController) buildNetPolSubjRule(subj apicapi.ApicObject, ruleName,
1139
        direction, ethertype, proto, port string, endPort string, remoteSubnets []string,
1140
        addPodSubnetAsRemIp bool) {
1✔
1141
        rule := apicapi.NewHostprotRule(subj.GetDn(), ruleName)
1✔
1142
        rule.SetAttr("direction", direction)
1✔
1143
        rule.SetAttr("ethertype", ethertype)
1✔
1144
        if proto != "" {
2✔
1145
                rule.SetAttr("protocol", proto)
1✔
1146
        }
1✔
1147

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

1181
        subj.AddChild(rule)
1✔
1182
}
1183

1184
func (cont *AciController) isPodSelectorPresent(podSelectors []*metav1.LabelSelector,
1185
        podSelector *metav1.LabelSelector) bool {
1✔
1186

1✔
1187
        present := false
1✔
1188
        for _, selector := range podSelectors {
1✔
1189
                if reflect.DeepEqual(selector, podSelector) {
×
1190
                        present = true
×
1191
                        break
×
1192
                }
1193
        }
1194
        return present
1✔
1195
}
1196

1197
func (cont *AciController) buildLocalNetPolSubjRule(subj *hppv1.HostprotSubj, ruleName,
1198
        direction, ethertype, proto, port, endPort string, remoteNs []string,
1199
        podSelectors []*metav1.LabelSelector, remoteSubnets []string) {
1✔
1200
        rule := hppv1.HostprotRule{
1✔
1201
                ConnTrack: "reflexive",
1✔
1202
                Direction: "ingress",
1✔
1203
                Ethertype: "undefined",
1✔
1204
                Protocol:  "unspecified",
1✔
1205
                FromPort:  "unspecified",
1✔
1206
                ToPort:    "unspecified",
1✔
1207
        }
1✔
1208
        rule.Direction = direction
1✔
1209
        rule.Ethertype = ethertype
1✔
1210
        if proto != "" {
2✔
1211
                rule.Protocol = proto
1✔
1212
        }
1✔
1213
        rule.Name = ruleName
1✔
1214

1✔
1215
        rule.RsRemoteIpContainer = remoteNs
1✔
1216
        var remoteSubnetsCidr []hppv1.HostprotRemoteIp
1✔
1217
        for _, subnetStr := range remoteSubnets {
2✔
1218
                _, subnet, err := net.ParseCIDR(subnetStr)
1✔
1219
                if err == nil && subnet != nil {
2✔
1220
                        if (ethertype == "ipv4" && subnet.IP.To4() != nil) || (ethertype == "ipv6" && subnet.IP.To4() == nil) {
2✔
1221
                                remIpObj := hppv1.HostprotRemoteIp{
1✔
1222
                                        Addr: subnetStr,
1✔
1223
                                }
1✔
1224
                                remoteSubnetsCidr = append(remoteSubnetsCidr, remIpObj)
1✔
1225
                        }
1✔
1226
                }
1227
        }
1228
        if len(remoteSubnetsCidr) > 0 {
2✔
1229
                rule.HostprotRemoteIp = remoteSubnetsCidr
1✔
1230
        }
1✔
1231

1232
        var filterContainers []hppv1.HostprotFilterContainer
1✔
1233
        for _, podSelector := range podSelectors {
2✔
1234
                filterContainer := hppv1.HostprotFilterContainer{}
1✔
1235
                for key, val := range podSelector.MatchLabels {
2✔
1236
                        filter := hppv1.HostprotFilter{
1✔
1237
                                Key: key,
1✔
1238
                        }
1✔
1239
                        filter.Values = append(filter.Values, val)
1✔
1240
                        filter.Operator = "Equals"
1✔
1241
                        filterContainer.HostprotFilter = append(filterContainer.HostprotFilter, filter)
1✔
1242
                }
1✔
1243
                for _, expressions := range podSelector.MatchExpressions {
2✔
1244
                        filter := hppv1.HostprotFilter{
1✔
1245
                                Key:      expressions.Key,
1✔
1246
                                Values:   expressions.Values,
1✔
1247
                                Operator: string(expressions.Operator),
1✔
1248
                        }
1✔
1249
                        filterContainer.HostprotFilter = append(filterContainer.HostprotFilter, filter)
1✔
1250
                }
1✔
1251
                filterContainers = append(filterContainers, filterContainer)
1✔
1252
        }
1253

1254
        if len(filterContainers) > 0 {
2✔
1255
                rule.HostprotFilterContainer = filterContainers
1✔
1256
        }
1✔
1257

1258
        if port != "" {
2✔
1259
                rule.FromPort = port
1✔
1260
                if endPort != "" {
1✔
NEW
1261
                        rule.ToPort = endPort
×
NEW
1262
                }
×
1263
        }
1264

1265
        cont.log.Debug(direction)
1✔
1266
        if len(remoteSubnets) != 0 && direction == "egress" {
2✔
1267
                cont.log.Debug("HostprotServiceRemoteIps")
1✔
1268
                rule.HostprotServiceRemoteIps = remoteSubnets
1✔
1269
        }
1✔
1270

1271
        subj.HostprotRule = append(subj.HostprotRule, rule)
1✔
1272
}
1273

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

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

1366
func (cont *AciController) buildLocalNetPolSubjRules(ruleName string,
1367
        subj *hppv1.HostprotSubj, direction string, peerNs []string,
1368
        podSelector []*metav1.LabelSelector, ports []v1net.NetworkPolicyPort,
1369
        logger *logrus.Entry, npKey string, np *v1net.NetworkPolicy, peerIpBlock []string) {
1✔
1370
        if len(ports) == 0 {
2✔
1371
                if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
1372
                        cont.buildLocalNetPolSubjRule(subj, ruleName+"-ipv4", direction,
1✔
1373
                                "ipv4", "", "", "", peerNs, podSelector, peerIpBlock)
1✔
1374
                }
1✔
1375
                if !cont.configuredPodNetworkIps.V6.Empty() {
1✔
1376
                        cont.buildLocalNetPolSubjRule(subj, ruleName+"-ipv6", direction,
×
NEW
1377
                                "ipv6", "", "", "", peerNs, podSelector, peerIpBlock)
×
1378
                }
×
1379
        } else {
1✔
1380
                for j := range ports {
2✔
1381
                        proto := portProto(ports[j].Protocol)
1✔
1382
                        var portRanges []portRange
1✔
1383

1✔
1384
                        if ports[j].Port != nil {
2✔
1385
                                if ports[j].Port.Type == intstr.Int {
2✔
1386
                                        pr := portRange{fromPort: ports[j].Port.String()}
1✔
1387
                                        if ports[j].EndPort != nil {
1✔
NEW
1388
                                                pr.toPort = strconv.Itoa(int(*ports[j].EndPort))
×
NEW
1389
                                        }
×
1390
                                        portRanges = append(portRanges, pr)
1✔
1391
                                } else {
×
1392
                                        var portnums []int
×
1393
                                        if direction == "egress" {
×
1394
                                                portnums = append(portnums, cont.getPortNums(&ports[j])...)
×
1395
                                        } else {
×
1396
                                                // TODO need to handle empty Pod Selector
×
1397
                                                if reflect.DeepEqual(np.Spec.PodSelector, metav1.LabelSelector{}) {
×
1398
                                                        logger.Warning("Empty PodSelctor for NamedPort is not supported in ingress direction"+
×
1399
                                                                "port in network policy: ", ports[j].Port.String())
×
1400
                                                        continue
×
1401
                                                }
1402
                                                podKeys := cont.netPolPods.GetPodForObj(npKey)
×
1403
                                                portnums = cont.getPortNumsFromPortName(podKeys, ports[j].Port.String())
×
1404
                                        }
1405
                                        if len(portnums) == 0 {
×
1406
                                                logger.Warning("There is no matching  ports in ingress/egress direction "+
×
1407
                                                        "port in network policy: ", ports[j].Port.String())
×
1408
                                                continue
×
1409
                                        }
1410
                                        for _, portnum := range portnums {
×
NEW
1411
                                                pr := portRange{fromPort: strconv.Itoa(portnum)}
×
NEW
1412
                                                portRanges = append(portRanges, pr)
×
UNCOV
1413
                                        }
×
1414
                                }
1415
                        }
1416
                        for i, pr := range portRanges {
2✔
1417
                                if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
1418
                                        cont.buildLocalNetPolSubjRule(subj, ruleName+"_"+strconv.Itoa(i+j)+"-ipv4", direction,
1✔
1419
                                                "ipv4", proto, pr.fromPort, pr.toPort, peerNs, podSelector, peerIpBlock)
1✔
1420
                                }
1✔
1421
                                if !cont.configuredPodNetworkIps.V6.Empty() {
1✔
1422
                                        cont.buildLocalNetPolSubjRule(subj, ruleName+"_"+strconv.Itoa(i+j)+"-ipv6", direction,
×
NEW
1423
                                                "ipv6", proto, pr.fromPort, pr.toPort, peerNs, podSelector, peerIpBlock)
×
1424
                                }
×
1425
                        }
1426
                        if len(portRanges) == 0 && proto != "" {
1✔
1427
                                if !cont.configuredPodNetworkIps.V4.Empty() {
×
1428
                                        cont.buildLocalNetPolSubjRule(subj, ruleName+"_"+strconv.Itoa(j)+"-ipv4", direction,
×
NEW
1429
                                                "ipv4", proto, "", "", peerNs, podSelector, peerIpBlock)
×
1430
                                }
×
1431
                                if !cont.configuredPodNetworkIps.V6.Empty() {
×
1432
                                        cont.buildLocalNetPolSubjRule(subj, ruleName+"_"+strconv.Itoa(j)+"-ipv6", direction,
×
NEW
1433
                                                "ipv6", proto, "", "", peerNs, podSelector, peerIpBlock)
×
1434
                                }
×
1435
                        }
1436
                }
1437
        }
1438
}
1439

1440
func (cont *AciController) getPortNums(port *v1net.NetworkPolicyPort) []int {
1✔
1441
        portkey := portKey(port)
1✔
1442
        cont.indexMutex.Lock()
1✔
1443
        defer cont.indexMutex.Unlock()
1✔
1444
        cont.log.Debug("PortKey1: ", portkey)
1✔
1445
        entry := cont.targetPortIndex[portkey]
1✔
1446
        var length int
1✔
1447
        if entry == nil || len(entry.port.ports) == 0 {
2✔
1448
                return []int{}
1✔
1449
        }
1✔
1450
        length = len(entry.port.ports)
1✔
1451
        ports := make([]int, length)
1✔
1452
        copy(ports, entry.port.ports)
1✔
1453
        return ports
1✔
1454
}
1455
func portProto(protocol *v1.Protocol) string {
1✔
1456
        proto := "tcp"
1✔
1457
        if protocol != nil && *protocol == v1.ProtocolUDP {
2✔
1458
                proto = "udp"
1✔
1459
        } else if protocol != nil && *protocol == v1.ProtocolSCTP {
3✔
1460
                proto = "sctp"
1✔
1461
        }
1✔
1462
        return proto
1✔
1463
}
1464

1465
func portKey(p *v1net.NetworkPolicyPort) string {
1✔
1466
        portType := ""
1✔
1467
        port := ""
1✔
1468
        if p != nil && p.Port != nil {
2✔
1469
                if p.Port.Type == intstr.Int {
2✔
1470
                        portType = "num"
1✔
1471
                } else {
2✔
1472
                        portType = "name"
1✔
1473
                }
1✔
1474
                port = p.Port.String()
1✔
1475
                return portProto(p.Protocol) + "-" + portType + "-" + port
1✔
1476
        }
1477
        return ""
1✔
1478
}
1479

1480
func checkEndpoints(subnetIndex cidranger.Ranger,
1481
        addresses []v1.EndpointAddress) bool {
1✔
1482
        for _, addr := range addresses {
2✔
1483
                ip := net.ParseIP(addr.IP)
1✔
1484
                if ip == nil {
1✔
1485
                        return false
×
1486
                }
×
1487
                contains, err := subnetIndex.Contains(ip)
1✔
1488
                if err != nil || !contains {
2✔
1489
                        return false
1✔
1490
                }
1✔
1491
        }
1492

1493
        return true
1✔
1494
}
1495
func checkEndpointslices(subnetIndex cidranger.Ranger,
1496
        addresses []string) bool {
1✔
1497
        for _, addr := range addresses {
2✔
1498
                ip := net.ParseIP(addr)
1✔
1499
                if ip == nil {
1✔
1500
                        return false
×
1501
                }
×
1502
                contains, err := subnetIndex.Contains(ip)
1✔
1503
                if err != nil || !contains {
2✔
1504
                        return false
1✔
1505
                }
1✔
1506
        }
1507
        return true
1✔
1508
}
1509

1510
type portRemoteSubnet struct {
1511
        port           *v1net.NetworkPolicyPort
1512
        subnetMap      map[string]bool
1513
        hasNamedTarget bool
1514
}
1515

1516
func updatePortRemoteSubnets(portRemoteSubs map[string]*portRemoteSubnet,
1517
        portkey string, port *v1net.NetworkPolicyPort, subnetMap map[string]bool,
1518
        hasNamedTarget bool) {
1✔
1519
        if prs, ok := portRemoteSubs[portkey]; ok {
1✔
1520
                for s := range subnetMap {
×
1521
                        prs.subnetMap[s] = true
×
1522
                }
×
1523
                prs.hasNamedTarget = hasNamedTarget || prs.hasNamedTarget
×
1524
        } else {
1✔
1525
                portRemoteSubs[portkey] = &portRemoteSubnet{
1✔
1526
                        port:           port,
1✔
1527
                        subnetMap:      subnetMap,
1✔
1528
                        hasNamedTarget: hasNamedTarget,
1✔
1529
                }
1✔
1530
        }
1✔
1531
}
1532

1533
func portServiceAugmentKey(proto, port string) string {
1✔
1534
        return proto + "-" + port
1✔
1535
}
1✔
1536

1537
type portServiceAugment struct {
1538
        proto string
1539
        port  string
1540
        ipMap map[string]bool
1541
}
1542

1543
func updateServiceAugment(portAugments map[string]*portServiceAugment, proto, port, ip string) {
1✔
1544
        key := portServiceAugmentKey(proto, port)
1✔
1545
        if psa, ok := portAugments[key]; ok {
1✔
1546
                psa.ipMap[ip] = true
×
1547
        } else {
1✔
1548
                portAugments[key] = &portServiceAugment{
1✔
1549
                        proto: proto,
1✔
1550
                        port:  port,
1✔
1551
                        ipMap: map[string]bool{ip: true},
1✔
1552
                }
1✔
1553
        }
1✔
1554
}
1555

1556
func updateServiceAugmentForService(portAugments map[string]*portServiceAugment,
1557
        proto, port string, service *v1.Service) {
1✔
1558
        if service.Spec.ClusterIP != "" {
2✔
1559
                updateServiceAugment(portAugments,
1✔
1560
                        proto, port, service.Spec.ClusterIP)
1✔
1561
        }
1✔
1562
        for _, ig := range service.Status.LoadBalancer.Ingress {
1✔
1563
                if ig.IP == "" {
×
1564
                        continue
×
1565
                }
1566
                updateServiceAugment(portAugments,
×
1567
                        proto, port, ig.IP)
×
1568
        }
1569
}
1570

1571
// build service augment by matching peers against the endpoints ip
1572
// index
1573
func (cont *AciController) getServiceAugmentBySubnet(
1574
        prs *portRemoteSubnet, portAugments map[string]*portServiceAugment,
1575
        logger *logrus.Entry) {
1✔
1576
        matchedServices := make(map[string]bool)
1✔
1577
        subnetIndex := cidranger.NewPCTrieRanger()
1✔
1578

1✔
1579
        // find candidate service endpoints objects that include
1✔
1580
        // endpoints selected by the egress rule
1✔
1581
        cont.indexMutex.Lock()
1✔
1582
        for sub := range prs.subnetMap {
2✔
1583
                cidr := parseCIDR(sub)
1✔
1584
                if cidr == nil {
1✔
1585
                        continue
×
1586
                }
1587
                subnetIndex.Insert(cidranger.NewBasicRangerEntry(*cidr))
1✔
1588

1✔
1589
                entries, err := cont.endpointsIpIndex.CoveredNetworks(*cidr)
1✔
1590
                if err != nil {
1✔
1591
                        logger.Error("endpointsIpIndex corrupted: ", err)
×
1592
                        continue
×
1593
                }
1594
                for _, entry := range entries {
2✔
1595
                        e := entry.(*ipIndexEntry)
1✔
1596
                        for servicekey := range e.keys {
2✔
1597
                                matchedServices[servicekey] = true
1✔
1598
                        }
1✔
1599
                }
1600
        }
1601
        cont.indexMutex.Unlock()
1✔
1602

1✔
1603
        // if all endpoints are selected by egress rule, allow egress
1✔
1604
        // to the service cluster IP as well as to the endpoints
1✔
1605
        // themselves
1✔
1606
        for servicekey := range matchedServices {
2✔
1607
                serviceobj, _, err := cont.serviceIndexer.GetByKey(servicekey)
1✔
1608
                if err != nil {
1✔
1609
                        logger.Error("Could not lookup service for "+
×
1610
                                servicekey+": ", err.Error())
×
1611
                        continue
×
1612
                }
1613
                if serviceobj == nil {
1✔
1614
                        continue
×
1615
                }
1616
                service := serviceobj.(*v1.Service)
1✔
1617
                cont.serviceEndPoints.SetNpServiceAugmentForService(servicekey, service,
1✔
1618
                        prs, portAugments, subnetIndex, logger)
1✔
1619
        }
1620
}
1621

1622
// build service augment by matching against services with a given
1623
// target port
1624
func (cont *AciController) getServiceAugmentByPort(
1625
        prs *portRemoteSubnet, portAugments map[string]*portServiceAugment,
1626
        logger *logrus.Entry) {
1✔
1627
        // nil port means it matches against all ports.  If we're here, it
1✔
1628
        // means this is a rule that matches all ports with all
1✔
1629
        // destinations, so there's no need to augment anything.
1✔
1630
        if prs.port == nil ||
1✔
1631
                prs.port.Port == nil {
2✔
1632
                return
1✔
1633
        }
1✔
1634

1635
        portkey := portKey(prs.port)
1✔
1636
        cont.indexMutex.Lock()
1✔
1637
        entries := make(map[string]*portIndexEntry)
1✔
1638
        entry := cont.targetPortIndex[portkey]
1✔
1639
        if entry != nil && prs.port.Port.Type == intstr.String {
2✔
1640
                for _, port := range entry.port.ports {
2✔
1641
                        portstring := strconv.Itoa(port)
1✔
1642
                        key := portProto(prs.port.Protocol) + "-" + "num" + "-" + portstring
1✔
1643
                        portEntry := cont.targetPortIndex[key]
1✔
1644
                        if portEntry != nil {
2✔
1645
                                entries[portstring] = portEntry
1✔
1646
                        }
1✔
1647
                }
1648
        } else if entry != nil {
2✔
1649
                if len(entry.port.ports) > 0 {
2✔
1650
                        entries[strconv.Itoa(entry.port.ports[0])] = entry
1✔
1651
                }
1✔
1652
        }
1653
        for key, portentry := range entries {
2✔
1654
                for servicekey := range portentry.serviceKeys {
2✔
1655
                        serviceobj, _, err := cont.serviceIndexer.GetByKey(servicekey)
1✔
1656
                        if err != nil {
1✔
1657
                                logger.Error("Could not lookup service for "+
×
1658
                                        servicekey+": ", err.Error())
×
1659
                                continue
×
1660
                        }
1661
                        if serviceobj == nil {
1✔
1662
                                continue
×
1663
                        }
1664
                        service := serviceobj.(*v1.Service)
1✔
1665

1✔
1666
                        for _, svcPort := range service.Spec.Ports {
2✔
1667
                                if svcPort.Protocol != *prs.port.Protocol ||
1✔
1668
                                        svcPort.TargetPort.String() !=
1✔
1669
                                                key {
1✔
1670
                                        continue
×
1671
                                }
1672
                                proto := portProto(&svcPort.Protocol)
1✔
1673
                                port := strconv.Itoa(int(svcPort.Port))
1✔
1674

1✔
1675
                                updateServiceAugmentForService(portAugments,
1✔
1676
                                        proto, port, service)
1✔
1677

1✔
1678
                                logger.WithFields(logrus.Fields{
1✔
1679
                                        "proto":   proto,
1✔
1680
                                        "port":    port,
1✔
1681
                                        "service": servicekey,
1✔
1682
                                }).Debug("Allowing egress for service by port")
1✔
1683
                        }
1684
                }
1685
        }
1686
        cont.indexMutex.Unlock()
1✔
1687
}
1688

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

1779
func isAllowAllForAllNamespaces(peers []v1net.NetworkPolicyPeer) bool {
1✔
1780
        addPodSubnetAsRemIp := false
1✔
1781
        if peers != nil && len(peers) > 0 {
2✔
1782
                var emptyPodSel, emptyNsSel bool
1✔
1783
                emptyPodSel = true
1✔
1784
                for _, peer := range peers {
2✔
1785
                        // namespaceSelector: {}
1✔
1786
                        if peer.NamespaceSelector != nil && peer.NamespaceSelector.MatchLabels == nil && peer.NamespaceSelector.MatchExpressions == nil {
1✔
1787
                                emptyNsSel = true
×
1788
                        }
×
1789
                        // podSelector has some fields
1790
                        if peer.PodSelector != nil && (peer.PodSelector.MatchLabels != nil || peer.PodSelector.MatchExpressions != nil) {
2✔
1791
                                emptyPodSel = false
1✔
1792
                        }
1✔
1793
                }
1794
                if emptyNsSel && emptyPodSel {
1✔
1795
                        addPodSubnetAsRemIp = true
×
1796
                }
×
1797
        }
1798
        return addPodSubnetAsRemIp
1✔
1799
}
1800

1801
func (cont *AciController) handleRemIpContUpdate(ns string) bool {
1✔
1802
        cont.hppMutex.Lock()
1✔
1803
        defer cont.hppMutex.Unlock()
1✔
1804

1✔
1805
        sysNs := os.Getenv("SYSTEM_NAMESPACE")
1✔
1806
        aobj, err := cont.getHostprotRemoteIpContainer(ns, sysNs)
1✔
1807
        isUpdate := err == nil
1✔
1808

1✔
1809
        if err != nil && !errors.IsNotFound(err) {
1✔
1810
                cont.log.Error("Error getting HostprotRemoteIpContainers CR: ", err)
×
1811
                return true
×
1812
        }
×
1813

1814
        if !isUpdate {
2✔
1815
                aobj = &hppv1.HostprotRemoteIpContainer{
1✔
1816
                        ObjectMeta: metav1.ObjectMeta{
1✔
1817
                                Name:      ns,
1✔
1818
                                Namespace: sysNs,
1✔
1819
                        },
1✔
1820
                        Spec: hppv1.HostprotRemoteIpContainerSpec{
1✔
1821
                                Name:             ns,
1✔
1822
                                HostprotRemoteIp: []hppv1.HostprotRemoteIp{},
1✔
1823
                        },
1✔
1824
                }
1✔
1825
        } else {
1✔
1826
                cont.log.Debug("HostprotRemoteIpContainers CR already exists: ", aobj)
×
1827
        }
×
1828

1829
        remIpCont, exists := cont.nsRemoteIpCont[ns]
1✔
1830
        if !exists {
2✔
1831
                if isUpdate {
1✔
1832
                        if !cont.deleteHostprotRemoteIpContainer(ns, sysNs) {
×
1833
                                return true
×
1834
                        }
×
1835
                } else {
1✔
1836
                        cont.log.Error("Couldn't find the ns in nsRemoteIpCont cache: ", ns)
1✔
1837
                        return false
1✔
1838
                }
1✔
1839
        }
1840

1841
        aobj.Spec.HostprotRemoteIp = buildHostprotRemoteIpList(remIpCont)
1✔
1842

1✔
1843
        if isUpdate {
1✔
1844
                if !cont.updateHostprotRemoteIpContainer(aobj, sysNs) {
×
1845
                        return true
×
1846
                }
×
1847
        } else {
1✔
1848
                if !cont.createHostprotRemoteIpContainer(aobj, sysNs) {
1✔
1849
                        return true
×
1850
                }
×
1851
        }
1852

1853
        return false
1✔
1854
}
1855

1856
func buildHostprotRemoteIpList(remIpConts map[string]remoteIpCont) []hppv1.HostprotRemoteIp {
1✔
1857
        hostprotRemoteIpList := []hppv1.HostprotRemoteIp{}
1✔
1858

1✔
1859
        for _, remIpCont := range remIpConts {
2✔
1860
                for ip, labels := range remIpCont {
2✔
1861
                        remIpObj := hppv1.HostprotRemoteIp{
1✔
1862
                                Addr: ip,
1✔
1863
                        }
1✔
1864
                        for key, val := range labels {
2✔
1865
                                remIpObj.HppEpLabel = append(remIpObj.HppEpLabel, hppv1.HppEpLabel{
1✔
1866
                                        Key:   key,
1✔
1867
                                        Value: val,
1✔
1868
                                })
1✔
1869
                        }
1✔
1870
                        hostprotRemoteIpList = append(hostprotRemoteIpList, remIpObj)
1✔
1871
                }
1872
        }
1873

1874
        return hostprotRemoteIpList
1✔
1875
}
1876

1877
func (cont *AciController) deleteHppCr(np *v1net.NetworkPolicy) bool {
1✔
1878
        key, err := cache.MetaNamespaceKeyFunc(np)
1✔
1879
        logger := networkPolicyLogger(cont.log, np)
1✔
1880
        if err != nil {
1✔
1881
                logger.Error("Could not create network policy key: ", err)
×
1882
                return false
×
1883
        }
×
1884
        hash, err := util.CreateHashFromNetPol(np)
1✔
1885
        if err != nil {
1✔
1886
                logger.Error("Could not create hash from network policy: ", err)
×
1887
                return false
×
1888
        }
×
1889
        labelKey := cont.aciNameForKey("np", hash)
1✔
1890
        ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
1891
        hppName := strings.ReplaceAll(labelKey, "_", "-")
1✔
1892
        hpp, _ := cont.getHostprotPol(hppName, ns)
1✔
1893
        if hpp == nil {
2✔
1894
                logger.Error("Could not find hostprotPol: ", hppName)
1✔
1895
                return false
1✔
1896
        }
1✔
1897
        netPols := hpp.Spec.NetworkPolicies
1✔
1898
        newNetPols := make([]string, 0)
1✔
1899
        for _, npName := range netPols {
2✔
1900
                if npName != key {
2✔
1901
                        newNetPols = append(newNetPols, npName)
1✔
1902
                }
1✔
1903
        }
1904

1905
        hpp.Spec.NetworkPolicies = newNetPols
1✔
1906

1✔
1907
        if len(newNetPols) > 0 {
2✔
1908
                return cont.updateHostprotPol(hpp, ns)
1✔
1909
        } else {
2✔
1910
                return cont.deleteHostprotPol(hppName, ns)
1✔
1911
        }
1✔
1912
}
1913

1914
func (cont *AciController) updateNodeIpsHostprotRemoteIpContainer(nodeIps map[string]bool) {
1✔
1915
        ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
1916
        name := "nodeips"
1✔
1917

1✔
1918
        aobj, err := cont.getHostprotRemoteIpContainer(name, ns)
1✔
1919
        isUpdate := err == nil
1✔
1920

1✔
1921
        if err != nil && !errors.IsNotFound(err) {
1✔
1922
                cont.log.Error("Error getting HostprotRemoteIpContainers CR: ", err)
×
1923
                return
×
1924
        }
×
1925

1926
        if !isUpdate {
2✔
1927
                aobj = &hppv1.HostprotRemoteIpContainer{
1✔
1928
                        ObjectMeta: metav1.ObjectMeta{
1✔
1929
                                Name:      name,
1✔
1930
                                Namespace: ns,
1✔
1931
                        },
1✔
1932
                        Spec: hppv1.HostprotRemoteIpContainerSpec{
1✔
1933
                                Name:             name,
1✔
1934
                                HostprotRemoteIp: []hppv1.HostprotRemoteIp{},
1✔
1935
                        },
1✔
1936
                }
1✔
1937
        } else {
2✔
1938
                cont.log.Debug("HostprotRemoteIpContainers CR already exists: ", aobj)
1✔
1939
        }
1✔
1940

1941
        existingIps := make(map[string]bool)
1✔
1942
        for _, ip := range aobj.Spec.HostprotRemoteIp {
2✔
1943
                existingIps[ip.Addr] = true
1✔
1944
        }
1✔
1945

1946
        for ip := range nodeIps {
2✔
1947
                if !existingIps[ip] {
2✔
1948
                        aobj.Spec.HostprotRemoteIp = append(aobj.Spec.HostprotRemoteIp, hppv1.HostprotRemoteIp{Addr: ip})
1✔
1949
                }
1✔
1950
        }
1951

1952
        if isUpdate {
2✔
1953
                cont.updateHostprotRemoteIpContainer(aobj, ns)
1✔
1954
        } else {
2✔
1955
                cont.createHostprotRemoteIpContainer(aobj, ns)
1✔
1956
        }
1✔
1957
}
1958

1959
func (cont *AciController) deleteNodeIpsHostprotRemoteIpContainer(nodeIps map[string]bool) {
1✔
1960
        ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
1961
        name := "nodeips"
1✔
1962

1✔
1963
        aobj, _ := cont.getHostprotRemoteIpContainer(name, ns)
1✔
1964
        if aobj == nil {
1✔
1965
                return
×
1966
        }
×
1967

1968
        newHostprotRemoteIps := aobj.Spec.HostprotRemoteIp[:0]
1✔
1969
        for _, hostprotRemoteIp := range aobj.Spec.HostprotRemoteIp {
2✔
1970
                if len(nodeIps) > 0 && !nodeIps[hostprotRemoteIp.Addr] {
2✔
1971
                        newHostprotRemoteIps = append(newHostprotRemoteIps, hostprotRemoteIp)
1✔
1972
                }
1✔
1973
        }
1974

1975
        aobj.Spec.HostprotRemoteIp = newHostprotRemoteIps
1✔
1976

1✔
1977
        if len(newHostprotRemoteIps) > 0 {
2✔
1978
                cont.updateHostprotRemoteIpContainer(aobj, ns)
1✔
1979
        } else {
2✔
1980
                cont.deleteHostprotRemoteIpContainer(name, ns)
1✔
1981
        }
1✔
1982
}
1983

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

1✔
1987
        aobj, err := cont.getHostprotRemoteIpContainer(name, ns)
1✔
1988
        isUpdate := err == nil
1✔
1989

1✔
1990
        if err != nil && !errors.IsNotFound(err) {
1✔
1991
                cont.log.Error("Error getting HostprotRemoteIpContainers CR: ", err)
×
1992
                return
×
1993
        }
×
1994

1995
        if !isUpdate {
2✔
1996
                aobj = &hppv1.HostprotRemoteIpContainer{
1✔
1997
                        ObjectMeta: metav1.ObjectMeta{
1✔
1998
                                Name:      name,
1✔
1999
                                Namespace: ns,
1✔
2000
                        },
1✔
2001
                        Spec: hppv1.HostprotRemoteIpContainerSpec{
1✔
2002
                                Name:             name,
1✔
2003
                                HostprotRemoteIp: []hppv1.HostprotRemoteIp{},
1✔
2004
                        },
1✔
2005
                }
1✔
2006
        } else {
2✔
2007
                cont.log.Debug("HostprotRemoteIpContainers CR already exists: ", aobj)
1✔
2008
        }
1✔
2009

2010
        aobj.Spec.HostprotRemoteIp = make([]hppv1.HostprotRemoteIp, 0, len(nodeIps))
1✔
2011
        for ip := range nodeIps {
2✔
2012
                aobj.Spec.HostprotRemoteIp = append(aobj.Spec.HostprotRemoteIp, hppv1.HostprotRemoteIp{Addr: ip})
1✔
2013
        }
1✔
2014

2015
        if isUpdate {
2✔
2016
                cont.updateHostprotRemoteIpContainer(aobj, ns)
1✔
2017
        } else {
2✔
2018
                cont.createHostprotRemoteIpContainer(aobj, ns)
1✔
2019
        }
1✔
2020
}
2021

2022
func (cont *AciController) deleteNodeHostprotRemoteIpContainer(name string) {
1✔
2023
        ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
2024

1✔
2025
        if _, err := cont.getHostprotRemoteIpContainer(name, ns); err == nil {
2✔
2026
                cont.deleteHostprotRemoteIpContainer(name, ns)
1✔
2027
        }
1✔
2028
}
2029

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

1✔
2034
        hpp, err := cont.getHostprotPol(hppName, ns)
1✔
2035
        isUpdate := hpp != nil && err == nil
1✔
2036

1✔
2037
        if err != nil && !errors.IsNotFound(err) {
1✔
2038
                cont.log.Error("Error getting HPP CR: ", err)
×
2039
                return
×
2040
        }
×
2041

2042
        if !isUpdate {
1✔
2043
                hpp = &hppv1.HostprotPol{
×
2044
                        ObjectMeta: metav1.ObjectMeta{
×
2045
                                Name:      hppName,
×
2046
                                Namespace: ns,
×
2047
                        },
×
2048
                        Spec: hppv1.HostprotPolSpec{
×
2049
                                Name:            name,
×
2050
                                NetworkPolicies: []string{name},
×
2051
                                HostprotSubj:    []hppv1.HostprotSubj{},
×
2052
                        },
×
2053
                }
×
2054
        } else {
1✔
2055
                cont.log.Debug("HPP CR already exists: ", hpp)
1✔
2056
                hpp.Spec.HostprotSubj = []hppv1.HostprotSubj{}
1✔
2057
        }
1✔
2058

2059
        if len(nodeIps) > 0 {
2✔
2060
                cont.updateNodeHostprotRemoteIpContainer(nodeName, nodeIps)
1✔
2061
                cont.updateNodeIpsHostprotRemoteIpContainer(nodeIps)
1✔
2062

1✔
2063
                hostprotSubj := hppv1.HostprotSubj{
1✔
2064
                        Name: "local-node",
1✔
2065
                        HostprotRule: []hppv1.HostprotRule{
1✔
2066
                                {
1✔
2067
                                        Name:                "allow-all-egress",
1✔
2068
                                        Direction:           "egress",
1✔
2069
                                        Ethertype:           "ipv4",
1✔
2070
                                        ConnTrack:           "normal",
1✔
2071
                                        RsRemoteIpContainer: []string{nodeName},
1✔
2072
                                },
1✔
2073
                                {
1✔
2074
                                        Name:                "allow-all-ingress",
1✔
2075
                                        Direction:           "ingress",
1✔
2076
                                        Ethertype:           "ipv4",
1✔
2077
                                        ConnTrack:           "normal",
1✔
2078
                                        RsRemoteIpContainer: []string{nodeName},
1✔
2079
                                },
1✔
2080
                        },
1✔
2081
                }
1✔
2082

1✔
2083
                hpp.Spec.HostprotSubj = append(hpp.Spec.HostprotSubj, hostprotSubj)
1✔
2084
        } else {
2✔
2085
                cont.deleteNodeHostprotRemoteIpContainer(nodeName)
1✔
2086
                cont.deleteNodeIpsHostprotRemoteIpContainer(nodeIps)
1✔
2087
        }
1✔
2088

2089
        if isUpdate {
2✔
2090
                cont.updateHostprotPol(hpp, ns)
1✔
2091
        } else {
1✔
2092
                cont.createHostprotPol(hpp, ns)
×
2093
        }
×
2094
}
2095

2096
func (cont *AciController) handleNetPolUpdate(np *v1net.NetworkPolicy) bool {
1✔
2097
        if cont.isCNOEnabled() {
1✔
2098
                return false
×
2099
        }
×
2100
        key, err := cache.MetaNamespaceKeyFunc(np)
1✔
2101
        logger := networkPolicyLogger(cont.log, np)
1✔
2102
        if err != nil {
1✔
2103
                logger.Error("Could not create network policy key: ", err)
×
2104
                return false
×
2105
        }
×
2106

2107
        peerPodKeys := cont.netPolIngressPods.GetPodForObj(key)
1✔
2108
        peerPodKeys =
1✔
2109
                append(peerPodKeys, cont.netPolEgressPods.GetPodForObj(key)...)
1✔
2110
        var peerPods []*v1.Pod
1✔
2111
        peerNs := make(map[string]*v1.Namespace)
1✔
2112
        for _, podkey := range peerPodKeys {
2✔
2113
                podobj, exists, err := cont.podIndexer.GetByKey(podkey)
1✔
2114
                if exists && err == nil {
2✔
2115
                        pod := podobj.(*v1.Pod)
1✔
2116
                        if _, nsok := peerNs[pod.ObjectMeta.Namespace]; !nsok {
2✔
2117
                                nsobj, exists, err :=
1✔
2118
                                        cont.namespaceIndexer.GetByKey(pod.ObjectMeta.Namespace)
1✔
2119
                                if !exists || err != nil {
1✔
2120
                                        continue
×
2121
                                }
2122
                                peerNs[pod.ObjectMeta.Namespace] = nsobj.(*v1.Namespace)
1✔
2123
                        }
2124
                        peerPods = append(peerPods, pod)
1✔
2125
                }
2126
        }
2127
        ptypeset := make(map[v1net.PolicyType]bool)
1✔
2128
        for _, t := range np.Spec.PolicyTypes {
2✔
2129
                ptypeset[t] = true
1✔
2130
        }
1✔
2131
        var labelKey string
1✔
2132

1✔
2133
        if !cont.config.EnableHppDirect {
2✔
2134
                if cont.config.HppOptimization {
2✔
2135
                        hash, err := util.CreateHashFromNetPol(np)
1✔
2136
                        if err != nil {
1✔
2137
                                logger.Error("Could not create hash from network policy: ", err)
×
2138
                                return false
×
2139
                        }
×
2140
                        labelKey = cont.aciNameForKey("np", hash)
1✔
2141
                } else {
1✔
2142
                        labelKey = cont.aciNameForKey("np", key)
1✔
2143
                }
1✔
2144
                hpp := apicapi.NewHostprotPol(cont.config.AciPolicyTenant, labelKey)
1✔
2145
                // Generate ingress policies
1✔
2146
                if np.Spec.PolicyTypes == nil || ptypeset[v1net.PolicyTypeIngress] {
2✔
2147
                        subjIngress :=
1✔
2148
                                apicapi.NewHostprotSubj(hpp.GetDn(), "networkpolicy-ingress")
1✔
2149

1✔
2150
                        for i, ingress := range np.Spec.Ingress {
2✔
2151
                                addPodSubnetAsRemIp := isAllowAllForAllNamespaces(ingress.From)
1✔
2152
                                remoteSubnets, _, _, _, _ := cont.getPeerRemoteSubnets(ingress.From,
1✔
2153
                                        np.Namespace, peerPods, peerNs, logger)
1✔
2154
                                cont.buildNetPolSubjRules(strconv.Itoa(i), subjIngress,
1✔
2155
                                        "ingress", ingress.From, remoteSubnets, ingress.Ports, logger, key, np, addPodSubnetAsRemIp)
1✔
2156
                        }
1✔
2157
                        hpp.AddChild(subjIngress)
1✔
2158
                }
2159
                // Generate egress policies
2160
                if np.Spec.PolicyTypes == nil || ptypeset[v1net.PolicyTypeEgress] {
2✔
2161
                        subjEgress :=
1✔
2162
                                apicapi.NewHostprotSubj(hpp.GetDn(), "networkpolicy-egress")
1✔
2163

1✔
2164
                        portRemoteSubs := make(map[string]*portRemoteSubnet)
1✔
2165

1✔
2166
                        for i, egress := range np.Spec.Egress {
2✔
2167
                                addPodSubnetAsRemIp := isAllowAllForAllNamespaces(egress.To)
1✔
2168
                                remoteSubnets, _, _, subnetMap, _ := cont.getPeerRemoteSubnets(egress.To,
1✔
2169
                                        np.Namespace, peerPods, peerNs, logger)
1✔
2170
                                cont.buildNetPolSubjRules(strconv.Itoa(i), subjEgress,
1✔
2171
                                        "egress", egress.To, remoteSubnets, egress.Ports, logger, key, np, addPodSubnetAsRemIp)
1✔
2172

1✔
2173
                                // creating a rule to egress to all on a given port needs
1✔
2174
                                // to enable access to any service IPs/ports that have
1✔
2175
                                // that port as their target port.
1✔
2176
                                if len(egress.To) == 0 {
2✔
2177
                                        subnetMap = map[string]bool{
1✔
2178
                                                "0.0.0.0/0": true,
1✔
2179
                                        }
1✔
2180
                                }
1✔
2181
                                for idx := range egress.Ports {
2✔
2182
                                        port := egress.Ports[idx]
1✔
2183
                                        portkey := portKey(&port)
1✔
2184
                                        updatePortRemoteSubnets(portRemoteSubs, portkey, &port, subnetMap,
1✔
2185
                                                port.Port != nil && port.Port.Type == intstr.Int)
1✔
2186
                                }
1✔
2187
                                if len(egress.Ports) == 0 {
2✔
2188
                                        updatePortRemoteSubnets(portRemoteSubs, "", nil, subnetMap,
1✔
2189
                                                false)
1✔
2190
                                }
1✔
2191
                        }
2192
                        cont.buildServiceAugment(subjEgress, nil, portRemoteSubs, logger)
1✔
2193
                        hpp.AddChild(subjEgress)
1✔
2194
                }
2195
                if cont.config.HppOptimization {
2✔
2196
                        cont.addToHppCache(labelKey, key, apicapi.ApicSlice{hpp}, &hppv1.HostprotPol{})
1✔
2197
                }
1✔
2198
                cont.apicConn.WriteApicObjects(labelKey, apicapi.ApicSlice{hpp})
1✔
2199
        } else {
1✔
2200
                hash, err := util.CreateHashFromNetPol(np)
1✔
2201
                if err != nil {
1✔
2202
                        logger.Error("Could not create hash from network policy: ", err)
×
2203
                        return false
×
2204
                }
×
2205
                labelKey = cont.aciNameForKey("np", hash)
1✔
2206
                ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
2207
                hppName := strings.ReplaceAll(labelKey, "_", "-")
1✔
2208
                hpp, err := cont.getHostprotPol(hppName, ns)
1✔
2209
                isUpdate := err == nil
1✔
2210

1✔
2211
                if err != nil && !errors.IsNotFound(err) {
1✔
2212
                        logger.Error("Error getting HPP CR: ", err)
×
2213
                        return false
×
2214
                }
×
2215

2216
                if isUpdate {
1✔
2217
                        logger.Debug("HPP CR already exists: ", hpp)
×
2218
                        if !slices.Contains(hpp.Spec.NetworkPolicies, key) {
×
2219
                                hpp.Spec.NetworkPolicies = append(hpp.Spec.NetworkPolicies, key)
×
2220
                        }
×
2221
                        hpp.Spec.HostprotSubj = nil
×
2222
                } else {
1✔
2223
                        hpp = &hppv1.HostprotPol{
1✔
2224
                                ObjectMeta: metav1.ObjectMeta{
1✔
2225
                                        Name:      hppName,
1✔
2226
                                        Namespace: ns,
1✔
2227
                                },
1✔
2228
                                Spec: hppv1.HostprotPolSpec{
1✔
2229
                                        Name:            labelKey,
1✔
2230
                                        NetworkPolicies: []string{key},
1✔
2231
                                        HostprotSubj:    nil,
1✔
2232
                                },
1✔
2233
                        }
1✔
2234
                }
1✔
2235

2236
                // Generate ingress policies
2237
                if np.Spec.PolicyTypes == nil || ptypeset[v1net.PolicyTypeIngress] {
2✔
2238
                        subjIngress := &hppv1.HostprotSubj{
1✔
2239
                                Name:         "networkpolicy-ingress",
1✔
2240
                                HostprotRule: []hppv1.HostprotRule{},
1✔
2241
                        }
1✔
2242

1✔
2243
                        for i, ingress := range np.Spec.Ingress {
2✔
2244
                                remoteSubnets, peerNsList, peerremote, _, peerIpBlock := cont.getPeerRemoteSubnets(ingress.From,
1✔
2245
                                        np.Namespace, peerPods, peerNs, logger)
1✔
2246
                                if isAllowAllForAllNamespaces(ingress.From) {
1✔
2247
                                        peerNsList = append(peerNsList, "nodeips")
×
2248
                                }
×
2249
                                if !(len(ingress.From) > 0 && len(remoteSubnets) == 0) {
2✔
2250
                                        cont.buildLocalNetPolSubjRules(strconv.Itoa(i), subjIngress,
1✔
2251
                                                "ingress", peerNsList, peerremote.podSelectors, ingress.Ports,
1✔
2252
                                                logger, key, np, peerIpBlock)
1✔
2253
                                }
1✔
2254
                        }
2255
                        hpp.Spec.HostprotSubj = append(hpp.Spec.HostprotSubj, *subjIngress)
1✔
2256
                }
2257

2258
                if np.Spec.PolicyTypes == nil || ptypeset[v1net.PolicyTypeEgress] {
2✔
2259
                        subjEgress := &hppv1.HostprotSubj{
1✔
2260
                                Name:         "networkpolicy-egress",
1✔
2261
                                HostprotRule: []hppv1.HostprotRule{},
1✔
2262
                        }
1✔
2263

1✔
2264
                        portRemoteSubs := make(map[string]*portRemoteSubnet)
1✔
2265

1✔
2266
                        for i, egress := range np.Spec.Egress {
2✔
2267
                                remoteSubnets, peerNsList, peerremote, subnetMap, peerIpBlock := cont.getPeerRemoteSubnets(egress.To,
1✔
2268
                                        np.Namespace, peerPods, peerNs, logger)
1✔
2269
                                if isAllowAllForAllNamespaces(egress.To) {
1✔
2270
                                        peerNsList = append(peerNsList, "nodeips")
×
2271
                                }
×
2272
                                if !(len(egress.To) > 0 && len(remoteSubnets) == 0) {
2✔
2273
                                        cont.buildLocalNetPolSubjRules(strconv.Itoa(i), subjEgress,
1✔
2274
                                                "egress", peerNsList, peerremote.podSelectors, egress.Ports, logger, key, np, peerIpBlock)
1✔
2275
                                }
1✔
2276

2277
                                if len(egress.To) == 0 {
2✔
2278
                                        subnetMap = map[string]bool{"0.0.0.0/0": true}
1✔
2279
                                }
1✔
2280
                                for idx := range egress.Ports {
2✔
2281
                                        port := egress.Ports[idx]
1✔
2282
                                        portkey := portKey(&port)
1✔
2283
                                        updatePortRemoteSubnets(portRemoteSubs, portkey, &port, subnetMap,
1✔
2284
                                                port.Port != nil && port.Port.Type == intstr.Int)
1✔
2285
                                }
1✔
2286
                                if len(egress.Ports) == 0 {
1✔
2287
                                        updatePortRemoteSubnets(portRemoteSubs, "", nil, subnetMap,
×
2288
                                                false)
×
2289
                                }
×
2290
                        }
2291
                        cont.buildServiceAugment(nil, subjEgress, portRemoteSubs, logger)
1✔
2292
                        hpp.Spec.HostprotSubj = append(hpp.Spec.HostprotSubj, *subjEgress)
1✔
2293
                }
2294

2295
                cont.addToHppCache(labelKey, key, apicapi.ApicSlice{}, hpp)
1✔
2296

1✔
2297
                if isUpdate {
1✔
2298
                        cont.updateHostprotPol(hpp, ns)
×
2299
                } else {
1✔
2300
                        cont.createHostprotPol(hpp, ns)
1✔
2301
                }
1✔
2302
        }
2303
        return false
1✔
2304
}
2305

2306
func (cont *AciController) updateNsRemoteIpCont(pod *v1.Pod, deleted bool) bool {
1✔
2307
        podips := ipsForPod(pod)
1✔
2308
        podns := pod.ObjectMeta.Namespace
1✔
2309
        podname := pod.ObjectMeta.Name
1✔
2310
        podlabels := pod.ObjectMeta.Labels
1✔
2311
        remipconts, ok := cont.nsRemoteIpCont[podns]
1✔
2312

1✔
2313
        if deleted {
2✔
2314
                if !ok {
2✔
2315
                        return true
1✔
2316
                }
1✔
2317

2318
                present := false
1✔
2319
                if remipcont, remipcontok := remipconts[podname]; remipcontok {
1✔
2320
                        for _, ip := range podips {
×
2321
                                if _, ipok := remipcont[ip]; ipok {
×
2322
                                        delete(remipcont, ip)
×
2323
                                        present = true
×
2324
                                }
×
2325
                        }
2326
                        if len(remipcont) < 1 {
×
2327
                                delete(remipconts, podname)
×
2328
                        }
×
2329
                }
2330

2331
                if len(remipconts) < 1 {
1✔
2332
                        delete(cont.nsRemoteIpCont, podns)
×
2333
                        cont.apicConn.ClearApicObjects(cont.aciNameForKey("hostprot-ns-", podns))
×
2334
                        return false
×
2335
                }
×
2336

2337
                if !present {
2✔
2338
                        return false
1✔
2339
                }
1✔
2340
        } else {
1✔
2341
                if !ok {
2✔
2342
                        remipconts = make(remoteIpConts)
1✔
2343
                        cont.nsRemoteIpCont[podns] = remipconts
1✔
2344
                }
1✔
2345

2346
                remipcont, remipcontok := remipconts[podname]
1✔
2347
                if !remipcontok {
2✔
2348
                        remipcont = make(remoteIpCont)
1✔
2349
                }
1✔
2350
                for _, ip := range podips {
2✔
2351
                        remipcont[ip] = podlabels
1✔
2352
                }
1✔
2353
                remipconts[podname] = remipcont
1✔
2354
        }
2355

2356
        return true
1✔
2357
}
2358

2359
func (cont *AciController) addToHppCache(labelKey, key string, hpp apicapi.ApicSlice, hppcr *hppv1.HostprotPol) {
1✔
2360
        cont.indexMutex.Lock()
1✔
2361
        hppRef, ok := cont.hppRef[labelKey]
1✔
2362
        if ok {
2✔
2363
                var found bool
1✔
2364
                for _, npkey := range hppRef.Npkeys {
2✔
2365
                        if npkey == key {
2✔
2366
                                found = true
1✔
2367
                                break
1✔
2368
                        }
2369
                }
2370
                if !found {
1✔
2371
                        hppRef.RefCount++
×
2372
                        hppRef.Npkeys = append(hppRef.Npkeys, key)
×
2373
                }
×
2374
                hppRef.HppObj = hpp
1✔
2375
                hppRef.HppCr = *hppcr
1✔
2376
                cont.hppRef[labelKey] = hppRef
1✔
2377
        } else {
1✔
2378
                var newHppRef hppReference
1✔
2379
                newHppRef.RefCount++
1✔
2380
                newHppRef.HppObj = hpp
1✔
2381
                newHppRef.HppCr = *hppcr
1✔
2382
                newHppRef.Npkeys = append(newHppRef.Npkeys, key)
1✔
2383
                cont.hppRef[labelKey] = newHppRef
1✔
2384
        }
1✔
2385
        cont.indexMutex.Unlock()
1✔
2386
}
2387

2388
func (cont *AciController) removeFromHppCache(np *v1net.NetworkPolicy, key string) (string, bool) {
1✔
2389
        var labelKey string
1✔
2390
        var noRef bool
1✔
2391
        hash, err := util.CreateHashFromNetPol(np)
1✔
2392
        if err != nil {
1✔
2393
                cont.log.Error("Could not create hash from network policy: ", err)
×
2394
                cont.log.Error("Failed to remove np from hpp cache")
×
2395
                return labelKey, noRef
×
2396
        }
×
2397
        labelKey = cont.aciNameForKey("np", hash)
1✔
2398
        cont.indexMutex.Lock()
1✔
2399
        hppRef, ok := cont.hppRef[labelKey]
1✔
2400
        if ok {
2✔
2401
                for i, npkey := range hppRef.Npkeys {
2✔
2402
                        if npkey == key {
2✔
2403
                                hppRef.Npkeys = append(hppRef.Npkeys[:i], hppRef.Npkeys[i+1:]...)
1✔
2404
                                hppRef.RefCount--
1✔
2405
                                break
1✔
2406
                        }
2407
                }
2408
                if hppRef.RefCount > 0 {
1✔
2409
                        cont.hppRef[labelKey] = hppRef
×
2410
                } else {
1✔
2411
                        delete(cont.hppRef, labelKey)
1✔
2412
                        noRef = true
1✔
2413
                }
1✔
2414
        }
2415
        cont.indexMutex.Unlock()
1✔
2416
        return labelKey, noRef
1✔
2417
}
2418

2419
func getNetworkPolicyEgressIpBlocks(np *v1net.NetworkPolicy) map[string]bool {
1✔
2420
        subnets := make(map[string]bool)
1✔
2421
        for _, egress := range np.Spec.Egress {
2✔
2422
                for _, to := range egress.To {
2✔
2423
                        if to.IPBlock != nil && to.IPBlock.CIDR != "" {
2✔
2424
                                subnets[to.IPBlock.CIDR] = true
1✔
2425
                        }
1✔
2426
                }
2427
        }
2428
        return subnets
1✔
2429
}
2430

2431
func (cont *AciController) networkPolicyAdded(obj interface{}) {
1✔
2432
        np := obj.(*v1net.NetworkPolicy)
1✔
2433
        npkey, err := cache.MetaNamespaceKeyFunc(np)
1✔
2434
        if err != nil {
1✔
2435
                networkPolicyLogger(cont.log, np).
×
2436
                        Error("Could not create network policy key: ", err)
×
2437
                return
×
2438
        }
×
2439
        if cont.isCNOEnabled() {
1✔
2440
                return
×
2441
        }
×
2442
        cont.netPolPods.UpdateSelectorObj(obj)
1✔
2443
        cont.netPolIngressPods.UpdateSelectorObj(obj)
1✔
2444
        cont.netPolEgressPods.UpdateSelectorObj(obj)
1✔
2445
        cont.indexMutex.Lock()
1✔
2446
        subnets := getNetworkPolicyEgressIpBlocks(np)
1✔
2447
        cont.updateIpIndex(cont.netPolSubnetIndex, nil, subnets, npkey)
1✔
2448

1✔
2449
        ports := cont.getNetPolTargetPorts(np)
1✔
2450
        cont.updateTargetPortIndex(false, npkey, nil, ports)
1✔
2451
        if isNamedPortPresenInNp(np) {
2✔
2452
                cont.nmPortNp[npkey] = true
1✔
2453
        }
1✔
2454
        cont.indexMutex.Unlock()
1✔
2455
        cont.queueNetPolUpdateByKey(npkey)
1✔
2456
}
2457

2458
func (cont *AciController) networkPolicyChanged(oldobj interface{},
2459
        newobj interface{}) {
×
2460
        oldnp := oldobj.(*v1net.NetworkPolicy)
×
2461
        newnp := newobj.(*v1net.NetworkPolicy)
×
2462
        npkey, err := cache.MetaNamespaceKeyFunc(newnp)
×
2463
        if err != nil {
×
2464
                networkPolicyLogger(cont.log, newnp).
×
2465
                        Error("Could not create network policy key: ", err)
×
2466
                return
×
2467
        }
×
2468

2469
        if cont.config.HppOptimization || cont.config.EnableHppDirect {
×
2470
                if !reflect.DeepEqual(oldnp.Spec, newnp.Spec) {
×
2471
                        cont.removeFromHppCache(oldnp, npkey)
×
2472
                }
×
2473
        }
2474

2475
        cont.indexMutex.Lock()
×
2476
        oldSubnets := getNetworkPolicyEgressIpBlocks(oldnp)
×
2477
        newSubnets := getNetworkPolicyEgressIpBlocks(newnp)
×
2478
        cont.updateIpIndex(cont.netPolSubnetIndex, oldSubnets, newSubnets, npkey)
×
2479

×
2480
        oldPorts := cont.getNetPolTargetPorts(oldnp)
×
2481
        newPorts := cont.getNetPolTargetPorts(newnp)
×
2482
        cont.updateTargetPortIndex(false, npkey, oldPorts, newPorts)
×
2483
        cont.indexMutex.Unlock()
×
2484

×
2485
        if !reflect.DeepEqual(oldnp.Spec.PodSelector, newnp.Spec.PodSelector) {
×
2486
                cont.netPolPods.UpdateSelectorObjNoCallback(newobj)
×
2487
        }
×
2488
        if !reflect.DeepEqual(oldnp.Spec.PolicyTypes, newnp.Spec.PolicyTypes) {
×
2489
                peerPodKeys := cont.netPolPods.GetPodForObj(npkey)
×
2490
                for _, podkey := range peerPodKeys {
×
2491
                        cont.podQueue.Add(podkey)
×
2492
                }
×
2493
        }
2494
        var queue bool
×
2495
        if !reflect.DeepEqual(oldnp.Spec.Ingress, newnp.Spec.Ingress) {
×
2496
                cont.netPolIngressPods.UpdateSelectorObjNoCallback(newobj)
×
2497
                queue = true
×
2498
        }
×
2499
        if !reflect.DeepEqual(oldnp.Spec.Egress, newnp.Spec.Egress) {
×
2500
                cont.netPolEgressPods.UpdateSelectorObjNoCallback(newobj)
×
2501
                queue = true
×
2502
        }
×
2503
        if cont.config.EnableHppDirect && !reflect.DeepEqual(oldnp.Spec, newnp.Spec) {
×
2504
                cont.deleteHppCr(oldnp)
×
2505
                queue = true
×
2506
        }
×
2507
        if queue {
×
2508
                cont.queueNetPolUpdateByKey(npkey)
×
2509
        }
×
2510
}
2511

2512
func (cont *AciController) networkPolicyDeleted(obj interface{}) {
1✔
2513
        np, isNetworkpolicy := obj.(*v1net.NetworkPolicy)
1✔
2514
        if !isNetworkpolicy {
1✔
2515
                deletedState, ok := obj.(cache.DeletedFinalStateUnknown)
×
2516
                if !ok {
×
2517
                        networkPolicyLogger(cont.log, np).
×
2518
                                Error("Received unexpected object: ", obj)
×
2519
                        return
×
2520
                }
×
2521
                np, ok = deletedState.Obj.(*v1net.NetworkPolicy)
×
2522
                if !ok {
×
2523
                        networkPolicyLogger(cont.log, np).
×
2524
                                Error("DeletedFinalStateUnknown contained non-Networkpolicy object: ", deletedState.Obj)
×
2525
                        return
×
2526
                }
×
2527
        }
2528
        npkey, err := cache.MetaNamespaceKeyFunc(np)
1✔
2529
        if err != nil {
1✔
2530
                networkPolicyLogger(cont.log, np).
×
2531
                        Error("Could not create network policy key: ", err)
×
2532
                return
×
2533
        }
×
2534

2535
        var labelKey string
1✔
2536
        var noHppRef bool
1✔
2537
        if cont.config.HppOptimization || cont.config.EnableHppDirect {
1✔
2538
                labelKey, noHppRef = cont.removeFromHppCache(np, npkey)
×
2539
        } else {
1✔
2540
                labelKey = cont.aciNameForKey("np", npkey)
1✔
2541
                noHppRef = true
1✔
2542
        }
1✔
2543

2544
        cont.indexMutex.Lock()
1✔
2545
        subnets := getNetworkPolicyEgressIpBlocks(np)
1✔
2546
        cont.updateIpIndex(cont.netPolSubnetIndex, subnets, nil, npkey)
1✔
2547

1✔
2548
        ports := cont.getNetPolTargetPorts(np)
1✔
2549
        cont.updateTargetPortIndex(false, npkey, ports, nil)
1✔
2550
        if isNamedPortPresenInNp(np) {
2✔
2551
                delete(cont.nmPortNp, npkey)
1✔
2552
        }
1✔
2553
        cont.indexMutex.Unlock()
1✔
2554

1✔
2555
        cont.netPolPods.DeleteSelectorObj(obj)
1✔
2556
        cont.netPolIngressPods.DeleteSelectorObj(obj)
1✔
2557
        cont.netPolEgressPods.DeleteSelectorObj(obj)
1✔
2558
        if noHppRef && labelKey != "" {
2✔
2559
                cont.apicConn.ClearApicObjects(labelKey)
1✔
2560
        }
1✔
2561
        if cont.config.EnableHppDirect {
1✔
2562
                cont.deleteHppCr(np)
×
2563
        }
×
2564
}
2565

2566
func (sep *serviceEndpoint) SetNpServiceAugmentForService(servicekey string, service *v1.Service, prs *portRemoteSubnet,
2567
        portAugments map[string]*portServiceAugment, subnetIndex cidranger.Ranger, logger *logrus.Entry) {
1✔
2568
        cont := sep.cont
1✔
2569
        endpointsobj, _, err := cont.endpointsIndexer.GetByKey(servicekey)
1✔
2570
        if err != nil {
1✔
2571
                logger.Error("Could not lookup endpoints for "+
×
2572
                        servicekey+": ", err.Error())
×
2573
                return
×
2574
        }
×
2575
        if endpointsobj == nil {
1✔
2576
                return
×
2577
        }
×
2578
        endpoints := endpointsobj.(*v1.Endpoints)
1✔
2579
        portstrings := make(map[string]bool)
1✔
2580
        ports := cont.getPortNums(prs.port)
1✔
2581
        for _, port := range ports {
2✔
2582
                portstrings[strconv.Itoa(port)] = true
1✔
2583
        }
1✔
2584
        for _, svcPort := range service.Spec.Ports {
2✔
2585
                _, ok := portstrings[svcPort.TargetPort.String()]
1✔
2586
                if prs.port != nil &&
1✔
2587
                        (svcPort.Protocol != *prs.port.Protocol || !ok) {
2✔
2588
                        // egress rule does not match service target port
1✔
2589
                        continue
1✔
2590
                }
2591
                for _, subset := range endpoints.Subsets {
2✔
2592
                        var foundEpPort *v1.EndpointPort
1✔
2593
                        for ix := range subset.Ports {
2✔
2594
                                if subset.Ports[ix].Name == svcPort.Name ||
1✔
2595
                                        (len(service.Spec.Ports) == 1 &&
1✔
2596
                                                subset.Ports[ix].Name == "") {
2✔
2597
                                        foundEpPort = &subset.Ports[ix]
1✔
2598
                                        break
1✔
2599
                                }
2600
                        }
2601
                        if foundEpPort == nil {
1✔
2602
                                continue
×
2603
                        }
2604

2605
                        incomplete := false
1✔
2606
                        incomplete = incomplete ||
1✔
2607
                                !checkEndpoints(subnetIndex, subset.Addresses)
1✔
2608
                        incomplete = incomplete || !checkEndpoints(subnetIndex,
1✔
2609
                                subset.NotReadyAddresses)
1✔
2610

1✔
2611
                        if incomplete {
2✔
2612
                                continue
1✔
2613
                        }
2614

2615
                        proto := portProto(&foundEpPort.Protocol)
1✔
2616
                        port := strconv.Itoa(int(svcPort.Port))
1✔
2617
                        updateServiceAugmentForService(portAugments,
1✔
2618
                                proto, port, service)
1✔
2619

1✔
2620
                        logger.WithFields(logrus.Fields{
1✔
2621
                                "proto":   proto,
1✔
2622
                                "port":    port,
1✔
2623
                                "service": servicekey,
1✔
2624
                        }).Debug("Allowing egress for service by subnet match")
1✔
2625
                }
2626
        }
2627
}
2628

2629
func (seps *serviceEndpointSlice) SetNpServiceAugmentForService(servicekey string, service *v1.Service,
2630
        prs *portRemoteSubnet, portAugments map[string]*portServiceAugment,
2631
        subnetIndex cidranger.Ranger, logger *logrus.Entry) {
1✔
2632
        cont := seps.cont
1✔
2633
        portstrings := make(map[string]bool)
1✔
2634
        ports := cont.getPortNums(prs.port)
1✔
2635
        for _, port := range ports {
2✔
2636
                portstrings[strconv.Itoa(port)] = true
1✔
2637
        }
1✔
2638
        label := map[string]string{discovery.LabelServiceName: service.ObjectMeta.Name}
1✔
2639
        selector := labels.SelectorFromSet(label)
1✔
2640
        cache.ListAllByNamespace(cont.endpointSliceIndexer, service.ObjectMeta.Namespace, selector,
1✔
2641
                func(endpointSliceobj interface{}) {
2✔
2642
                        endpointSlices := endpointSliceobj.(*discovery.EndpointSlice)
1✔
2643
                        for _, svcPort := range service.Spec.Ports {
2✔
2644
                                _, ok := portstrings[svcPort.TargetPort.String()]
1✔
2645
                                if prs.port != nil &&
1✔
2646
                                        (svcPort.Protocol != *prs.port.Protocol || !ok) {
1✔
2647
                                        // egress rule does not match service target port
×
2648
                                        continue
×
2649
                                }
2650
                                var foundEpPort *discovery.EndpointPort
1✔
2651
                                for ix := range endpointSlices.Ports {
2✔
2652
                                        if *endpointSlices.Ports[ix].Name == svcPort.Name ||
1✔
2653
                                                (len(service.Spec.Ports) == 1 &&
1✔
2654
                                                        *endpointSlices.Ports[ix].Name == "") {
2✔
2655
                                                foundEpPort = &endpointSlices.Ports[ix]
1✔
2656
                                                cont.log.Debug("Found EpPort: ", foundEpPort)
1✔
2657
                                                break
1✔
2658
                                        }
2659
                                }
2660
                                if foundEpPort == nil {
1✔
2661
                                        return
×
2662
                                }
×
2663
                                // @FIXME for non ready address
2664
                                incomplete := false
1✔
2665
                                for _, endpoint := range endpointSlices.Endpoints {
2✔
2666
                                        incomplete = incomplete || !checkEndpointslices(subnetIndex, endpoint.Addresses)
1✔
2667
                                }
1✔
2668
                                if incomplete {
2✔
2669
                                        continue
1✔
2670
                                }
2671
                                proto := portProto(foundEpPort.Protocol)
1✔
2672
                                port := strconv.Itoa(int(svcPort.Port))
1✔
2673
                                cont.log.Debug("updateServiceAugmentForService: ", service)
1✔
2674
                                updateServiceAugmentForService(portAugments,
1✔
2675
                                        proto, port, service)
1✔
2676

1✔
2677
                                logger.WithFields(logrus.Fields{
1✔
2678
                                        "proto":   proto,
1✔
2679
                                        "port":    port,
1✔
2680
                                        "service": servicekey,
1✔
2681
                                }).Debug("Allowing egress for service by subnet match")
1✔
2682
                        }
2683
                })
2684
}
2685

2686
func isNamedPortPresenInNp(np *v1net.NetworkPolicy) bool {
1✔
2687
        for _, egress := range np.Spec.Egress {
2✔
2688
                for _, p := range egress.Ports {
2✔
2689
                        if p.Port.Type == intstr.String {
2✔
2690
                                return true
1✔
2691
                        }
1✔
2692
                }
2693
        }
2694
        return false
1✔
2695
}
2696

2697
func (cont *AciController) checkPodNmpMatchesNp(npkey, podkey string) bool {
1✔
2698
        podobj, exists, err := cont.podIndexer.GetByKey(podkey)
1✔
2699
        if err != nil {
1✔
2700
                return false
×
2701
        }
×
2702
        if !exists || podobj == nil {
1✔
UNCOV
2703
                return false
×
UNCOV
2704
        }
×
2705
        pod := podobj.(*v1.Pod)
1✔
2706
        npobj, npexists, nperr := cont.networkPolicyIndexer.GetByKey(npkey)
1✔
2707
        if npexists && nperr == nil && npobj != nil {
2✔
2708
                np := npobj.(*v1net.NetworkPolicy)
1✔
2709
                for _, egress := range np.Spec.Egress {
2✔
2710
                        for _, p := range egress.Ports {
2✔
2711
                                if p.Port.Type == intstr.String {
2✔
2712
                                        _, err := k8util.LookupContainerPortNumberByName(*pod, p.Port.String())
1✔
2713
                                        if err == nil {
2✔
2714
                                                return true
1✔
2715
                                        }
1✔
2716
                                }
2717
                        }
2718
                }
2719
        }
2720
        return false
1✔
2721
}
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