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

noironetworks / aci-containers / 10369

22 Jan 2025 04:12AM UTC coverage: 69.093% (+0.06%) from 69.031%
10369

push

travis-pro

web-flow
Merge pull request #1481 from noironetworks/backport-fix-operator-git-cve

Fixing git high cve for aci-containers-operator

13230 of 19148 relevant lines covered (69.09%)

0.79 hits per line

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

79.83
/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) deleteHostprotPol(hppName string, ns string) bool {
1✔
376
        hppcl, ok := cont.getHppClient()
1✔
377
        if !ok {
2✔
378
                return false
1✔
379
        }
1✔
380

381
        cont.log.Debug("Deleting HPP CR: ", hppName)
1✔
382
        err := hppcl.AciV1().HostprotPols(ns).Delete(context.TODO(), hppName, metav1.DeleteOptions{})
1✔
383
        if err != nil {
1✔
384
                cont.log.Error("Error deleting HPP CR: ", err)
×
385
                return false
×
386
        }
×
387

388
        return true
1✔
389
}
390

391
func (cont *AciController) getHostprotPol(hppName string, ns string) (*hppv1.HostprotPol, error) {
1✔
392
        hppcl, ok := cont.getHppClient()
1✔
393
        if !ok {
2✔
394
                return nil, fmt.Errorf("hpp client not found")
1✔
395
        }
1✔
396

397
        hpp, err := hppcl.AciV1().HostprotPols(ns).Get(context.TODO(), hppName, metav1.GetOptions{})
1✔
398
        if err != nil {
2✔
399
                return nil, err
1✔
400
        }
1✔
401
        cont.log.Debug("HPP CR found: ", hpp)
1✔
402
        return hpp, nil
1✔
403
}
404

405
func (cont *AciController) getHostprotRemoteIpContainer(name, ns string) (*hppv1.HostprotRemoteIpContainer, error) {
1✔
406
        hppcl, ok := cont.getHppClient()
1✔
407
        if !ok {
2✔
408
                return nil, fmt.Errorf("hpp client not found")
1✔
409
        }
1✔
410

411
        hpp, err := hppcl.AciV1().HostprotRemoteIpContainers(ns).Get(context.TODO(), name, metav1.GetOptions{})
1✔
412
        if err != nil {
2✔
413
                cont.log.Error("Error getting HostprotRemoteIpContainers CR: ", err)
1✔
414
                return nil, err
1✔
415
        }
1✔
416
        cont.log.Debug("HostprotRemoteIpContainers CR found: ", hpp)
1✔
417
        return hpp, nil
1✔
418
}
419

420
func (cont *AciController) createHostprotRemoteIpContainer(hppIpCont *hppv1.HostprotRemoteIpContainer, ns string) bool {
1✔
421
        hppcl, ok := cont.getHppClient()
1✔
422
        if !ok {
2✔
423
                return false
1✔
424
        }
1✔
425

426
        cont.log.Debug("Creating HostprotRemoteIpContainer CR: ", hppIpCont)
1✔
427
        _, err := hppcl.AciV1().HostprotRemoteIpContainers(ns).Create(context.TODO(), hppIpCont, metav1.CreateOptions{})
1✔
428
        if err != nil {
1✔
429
                cont.log.Error("Error creating HostprotRemoteIpContainer CR: ", err)
×
430
                return false
×
431
        }
×
432

433
        return true
1✔
434
}
435

436
func (cont *AciController) updateHostprotRemoteIpContainer(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("Updating HostprotRemoteIpContainer CR: ", hppIpCont)
1✔
443
        _, err := hppcl.AciV1().HostprotRemoteIpContainers(ns).Update(context.TODO(), hppIpCont, metav1.UpdateOptions{})
1✔
444
        if err != nil {
1✔
445
                cont.log.Error("Error updating HostprotRemoteIpContainer CR: ", err)
×
446
                return false
×
447
        }
×
448

449
        return true
1✔
450
}
451

452
func (cont *AciController) deleteHostprotRemoteIpContainer(hppIpContName string, 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("Deleting HostprotRemoteIpContainer CR: ", hppIpContName)
1✔
459
        err := hppcl.AciV1().HostprotRemoteIpContainers(ns).Delete(context.TODO(), hppIpContName, metav1.DeleteOptions{})
1✔
460
        if err != nil {
1✔
461
                cont.log.Error("Error deleting HostprotRemoteIpContainer CR: ", err)
×
462
                return false
×
463
        }
×
464

465
        return true
1✔
466
}
467

468
func (cont *AciController) listHostprotPol(ns string) (*hppv1.HostprotPolList, error) {
1✔
469
        hppcl, ok := cont.getHppClient()
1✔
470
        if !ok {
1✔
471
                return nil, fmt.Errorf("hpp client not found")
×
472
        }
×
473

474
        hpps, err := hppcl.AciV1().HostprotPols(ns).List(context.TODO(), metav1.ListOptions{})
1✔
475
        if err != nil {
2✔
476
                cont.log.Error("Error listing HPP CR: ", err)
1✔
477
                return nil, err
1✔
478
        }
1✔
479
        return hpps, nil
×
480
}
481

482
func (cont *AciController) listHostprotRemoteIpContainers(ns string) (*hppv1.HostprotRemoteIpContainerList, error) {
1✔
483
        hppcl, ok := cont.getHppClient()
1✔
484
        if !ok {
1✔
485
                return nil, fmt.Errorf("hpp client not found")
×
486
        }
×
487

488
        hpRemoteIpConts, err := hppcl.AciV1().HostprotRemoteIpContainers(ns).List(context.TODO(), metav1.ListOptions{})
1✔
489
        if err != nil {
2✔
490
                cont.log.Error("Error getting HostprotRemoteIpContainers CRs: ", err)
1✔
491
                return nil, err
1✔
492
        }
1✔
493
        return hpRemoteIpConts, nil
×
494
}
495

496
func (cont *AciController) createStaticNetPolCrs() bool {
1✔
497
        ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
498

1✔
499
        createPol := func(labelKey, subjName, direction string, rules []hppv1.HostprotRule) bool {
2✔
500
                hppName := strings.ReplaceAll(labelKey, "_", "-")
1✔
501
                if _, err := cont.getHostprotPol(hppName, ns); errors.IsNotFound(err) {
2✔
502
                        hpp := &hppv1.HostprotPol{
1✔
503
                                ObjectMeta: metav1.ObjectMeta{
1✔
504
                                        Name:      hppName,
1✔
505
                                        Namespace: ns,
1✔
506
                                },
1✔
507
                                Spec: hppv1.HostprotPolSpec{
1✔
508
                                        Name:            labelKey,
1✔
509
                                        NetworkPolicies: []string{labelKey},
1✔
510
                                        HostprotSubj: []hppv1.HostprotSubj{
1✔
511
                                                {
1✔
512
                                                        Name:         subjName,
1✔
513
                                                        HostprotRule: rules,
1✔
514
                                                },
1✔
515
                                        },
1✔
516
                                },
1✔
517
                        }
1✔
518
                        if !cont.createHostprotPol(hpp, ns) {
1✔
519
                                return false
×
520
                        }
×
521
                }
522
                return true
1✔
523
        }
524

525
        if !createPol(cont.aciNameForKey("np", "static-ingress"), "ingress", "ingress", cont.getHostprotRules("ingress")) {
1✔
526
                return false
×
527
        }
×
528
        if !createPol(cont.aciNameForKey("np", "static-egress"), "egress", "egress", cont.getHostprotRules("egress")) {
1✔
529
                return false
×
530
        }
×
531
        if !createPol(cont.aciNameForKey("np", "static-discovery"), "discovery", "discovery", cont.getDiscoveryRules()) {
1✔
532
                return false
×
533
        }
×
534

535
        return true
1✔
536
}
537

538
func (cont *AciController) getHostprotRules(direction string) []hppv1.HostprotRule {
1✔
539
        var rules []hppv1.HostprotRule
1✔
540
        outbound := hppv1.HostprotRule{
1✔
541
                ConnTrack: "reflexive",
1✔
542
                Protocol:  "unspecified",
1✔
543
                FromPort:  "unspecified",
1✔
544
                ToPort:    "unspecified",
1✔
545
                Direction: direction,
1✔
546
        }
1✔
547

1✔
548
        if !cont.configuredPodNetworkIps.V6.Empty() {
1✔
549
                outbound.Name = "allow-all-reflexive-v6"
×
550
                outbound.Ethertype = "ipv6"
×
551
                rules = append(rules, outbound)
×
552
        }
×
553
        if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
554
                outbound.Name = "allow-all-reflexive"
1✔
555
                outbound.Ethertype = "ipv4"
1✔
556
                rules = append(rules, outbound)
1✔
557
        }
1✔
558

559
        return rules
1✔
560
}
561

562
func (cont *AciController) getDiscoveryRules() []hppv1.HostprotRule {
1✔
563
        rules := []hppv1.HostprotRule{
1✔
564
                {
1✔
565
                        Name:      "arp-ingress",
1✔
566
                        Direction: "ingress",
1✔
567
                        Ethertype: "arp",
1✔
568
                        ConnTrack: "normal",
1✔
569
                },
1✔
570
                {
1✔
571
                        Name:      "arp-egress",
1✔
572
                        Direction: "egress",
1✔
573
                        Ethertype: "arp",
1✔
574
                        ConnTrack: "normal",
1✔
575
                },
1✔
576
        }
1✔
577

1✔
578
        if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
579
                rules = append(rules,
1✔
580
                        hppv1.HostprotRule{
1✔
581
                                Name:      "icmp-ingress",
1✔
582
                                Direction: "ingress",
1✔
583
                                Ethertype: "ipv4",
1✔
584
                                Protocol:  "icmp",
1✔
585
                                ConnTrack: "normal",
1✔
586
                        },
1✔
587
                        hppv1.HostprotRule{
1✔
588
                                Name:      "icmp-egress",
1✔
589
                                Direction: "egress",
1✔
590
                                Ethertype: "ipv4",
1✔
591
                                Protocol:  "icmp",
1✔
592
                                ConnTrack: "normal",
1✔
593
                        },
1✔
594
                )
1✔
595
        }
1✔
596

597
        if !cont.configuredPodNetworkIps.V6.Empty() {
1✔
598
                rules = append(rules,
×
599
                        hppv1.HostprotRule{
×
600
                                Name:      "icmpv6-ingress",
×
601
                                Direction: "ingress",
×
602
                                Ethertype: "ipv6",
×
603
                                Protocol:  "icmpv6",
×
604
                                ConnTrack: "normal",
×
605
                        },
×
606
                        hppv1.HostprotRule{
×
607
                                Name:      "icmpv6-egress",
×
608
                                Direction: "egress",
×
609
                                Ethertype: "ipv6",
×
610
                                Protocol:  "icmpv6",
×
611
                                ConnTrack: "normal",
×
612
                        },
×
613
                )
×
614
        }
×
615

616
        return rules
1✔
617
}
618

619
func (cont *AciController) cleanStaleHppCrs() {
1✔
620
        sysNs := os.Getenv("SYSTEM_NAMESPACE")
1✔
621
        npNames := make(map[string]struct{})
1✔
622

1✔
623
        namespaces, err := cont.listNamespaces()
1✔
624
        if err != nil {
1✔
625
                cont.log.Error("Error listing namespaces: ", err)
×
626
                return
×
627
        }
×
628

629
        for _, ns := range namespaces.Items {
1✔
630
                netpols, err := cont.listNetworkPolicies(ns.Name)
×
631
                if err != nil {
×
632
                        cont.log.Error("Error listing network policies in namespace ", ns.Name, ": ", err)
×
633
                        continue
×
634
                }
635
                for _, np := range netpols.Items {
×
636
                        nsName := np.ObjectMeta.Namespace + "/" + np.ObjectMeta.Name
×
637
                        npNames[nsName] = struct{}{}
×
638
                }
×
639
        }
640

641
        hpps, err := cont.listHostprotPol(sysNs)
1✔
642
        if err != nil {
2✔
643
                cont.log.Error("Error listing HostprotPols: ", err)
1✔
644
                return
1✔
645
        }
1✔
646

647
        for _, hpp := range hpps.Items {
×
648
                for _, npName := range hpp.Spec.NetworkPolicies {
×
649
                        if _, exists := npNames[npName]; !exists {
×
650
                                if !cont.deleteHostprotPol(hpp.ObjectMeta.Name, sysNs) {
×
651
                                        cont.log.Error("Error deleting stale HostprotPol: ", hpp.ObjectMeta.Name)
×
652
                                }
×
653
                        }
654
                }
655
        }
656
}
657

658
func (cont *AciController) cleanStaleHostprotRemoteIpContainers() {
1✔
659
        sysNs := os.Getenv("SYSTEM_NAMESPACE")
1✔
660
        nsNames := make(map[string]struct{})
1✔
661

1✔
662
        namespaces, err := cont.listNamespaces()
1✔
663
        if err != nil {
1✔
664
                cont.log.Error("Error listing namespaces: ", err)
×
665
                return
×
666
        }
×
667

668
        for _, ns := range namespaces.Items {
1✔
669
                nsNames[ns.Name] = struct{}{}
×
670
        }
×
671

672
        hpRemIpConts, err := cont.listHostprotRemoteIpContainers(sysNs)
1✔
673
        if err != nil {
2✔
674
                cont.log.Error("Error listing HostprotRemoteIpContainers: ", err)
1✔
675
                return
1✔
676
        }
1✔
677

678
        for _, hpRemIpCont := range hpRemIpConts.Items {
×
679
                if _, exists := nsNames[hpRemIpCont.ObjectMeta.Name]; !exists {
×
680
                        if !cont.deleteHostprotRemoteIpContainer(hpRemIpCont.ObjectMeta.Name, sysNs) {
×
681
                                cont.log.Error("Error deleting stale HostprotRemoteIpContainer: ", hpRemIpCont.ObjectMeta.Name)
×
682
                        }
×
683
                }
684
        }
685
}
686

687
func (cont *AciController) initStaticNetPolObjs() {
1✔
688
        if cont.config.EnableHppDirect {
2✔
689
                cont.cleanStaleHostprotRemoteIpContainers()
1✔
690
                cont.cleanStaleHppCrs()
1✔
691

1✔
692
                if !cont.createStaticNetPolCrs() {
1✔
693
                        cont.log.Error("Error creating static HPP CRs")
×
694
                }
×
695
                return
1✔
696
        }
697

698
        cont.apicConn.WriteApicObjects(cont.config.AciPrefix+"_np_static", cont.staticNetPolObjs())
1✔
699
}
700

701
func networkPolicyLogger(log *logrus.Logger,
702
        np *v1net.NetworkPolicy) *logrus.Entry {
1✔
703
        return log.WithFields(logrus.Fields{
1✔
704
                "namespace": np.ObjectMeta.Namespace,
1✔
705
                "name":      np.ObjectMeta.Name,
1✔
706
        })
1✔
707
}
1✔
708

709
func (cont *AciController) queueNetPolUpdateByKey(key string) {
1✔
710
        cont.netPolQueue.Add(key)
1✔
711
}
1✔
712

713
func (cont *AciController) queueRemoteIpConUpdate(pod *v1.Pod, deleted bool) {
1✔
714
        cont.hppMutex.Lock()
1✔
715
        update := cont.updateNsRemoteIpCont(pod, deleted)
1✔
716
        if update {
2✔
717
                podns := pod.ObjectMeta.Namespace
1✔
718
                cont.remIpContQueue.Add(podns)
1✔
719
        }
1✔
720
        cont.hppMutex.Unlock()
1✔
721
}
722

723
func (cont *AciController) queueNetPolUpdate(netpol *v1net.NetworkPolicy) {
1✔
724
        key, err := cache.MetaNamespaceKeyFunc(netpol)
1✔
725
        if err != nil {
1✔
726
                networkPolicyLogger(cont.log, netpol).
×
727
                        Error("Could not create network policy key: ", err)
×
728
                return
×
729
        }
×
730
        cont.netPolQueue.Add(key)
1✔
731
}
732

733
func (cont *AciController) peerMatchesPod(npNs string,
734
        peer *v1net.NetworkPolicyPeer, pod *v1.Pod, podNs *v1.Namespace) bool {
1✔
735
        if peer.PodSelector != nil && npNs == pod.ObjectMeta.Namespace {
2✔
736
                selector, err :=
1✔
737
                        metav1.LabelSelectorAsSelector(peer.PodSelector)
1✔
738
                if err != nil {
1✔
739
                        cont.log.Error("Could not parse pod selector: ", err)
×
740
                } else {
1✔
741
                        return selector.Matches(labels.Set(pod.ObjectMeta.Labels))
1✔
742
                }
1✔
743
        }
744
        if peer.NamespaceSelector != nil {
2✔
745
                selector, err :=
1✔
746
                        metav1.LabelSelectorAsSelector(peer.NamespaceSelector)
1✔
747
                if err != nil {
1✔
748
                        cont.log.Error("Could not parse namespace selector: ", err)
×
749
                } else {
1✔
750
                        return selector.Matches(labels.Set(podNs.ObjectMeta.Labels))
1✔
751
                }
1✔
752
        }
753
        return false
×
754
}
755

756
func ipsForPod(pod *v1.Pod) []string {
1✔
757
        var ips []string
1✔
758
        podIPsField := reflect.ValueOf(pod.Status).FieldByName("PodIPs")
1✔
759
        if podIPsField.IsValid() {
2✔
760
                if len(pod.Status.PodIPs) > 0 {
1✔
761
                        for _, ip := range pod.Status.PodIPs {
×
762
                                ips = append(ips, ip.IP)
×
763
                        }
×
764
                        return ips
×
765
                }
766
        }
767
        if pod.Status.PodIP != "" {
2✔
768
                return []string{pod.Status.PodIP}
1✔
769
        }
1✔
770
        return nil
1✔
771
}
772

773
func ipBlockToSubnets(ipblock *v1net.IPBlock) ([]string, error) {
1✔
774
        _, nw, err := net.ParseCIDR(ipblock.CIDR)
1✔
775
        if err != nil {
1✔
776
                return nil, err
×
777
        }
×
778
        ips := ipam.New()
1✔
779
        ips.AddSubnet(nw)
1✔
780
        for _, except := range ipblock.Except {
2✔
781
                _, nw, err = net.ParseCIDR(except)
1✔
782
                if err != nil {
1✔
783
                        return nil, err
×
784
                }
×
785
                ips.RemoveSubnet(nw)
1✔
786
        }
787
        var subnets []string
1✔
788
        for _, r := range ips.FreeList {
2✔
789
                ipnets := ipam.Range2Cidr(r.Start, r.End)
1✔
790
                for _, n := range ipnets {
2✔
791
                        subnets = append(subnets, n.String())
1✔
792
                }
1✔
793
        }
794
        return subnets, nil
1✔
795
}
796

797
func parseCIDR(sub string) *net.IPNet {
1✔
798
        _, netw, err := net.ParseCIDR(sub)
1✔
799
        if err == nil {
2✔
800
                return netw
1✔
801
        }
1✔
802
        ip := net.ParseIP(sub)
1✔
803
        if ip == nil {
1✔
804
                return nil
×
805
        }
×
806
        var mask net.IPMask
1✔
807
        if ip.To4() != nil {
2✔
808
                mask = net.CIDRMask(32, 32)
1✔
809
        } else if ip.To16() != nil {
3✔
810
                mask = net.CIDRMask(128, 128)
1✔
811
        } else {
1✔
812
                return nil
×
813
        }
×
814
        return &net.IPNet{
1✔
815
                IP:   ip,
1✔
816
                Mask: mask,
1✔
817
        }
1✔
818
}
819

820
func netEqual(a, b net.IPNet) bool {
1✔
821
        return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask)
1✔
822
}
1✔
823

824
func (cont *AciController) updateIpIndexEntry(index cidranger.Ranger,
825
        subnetStr string, key string, add bool) bool {
1✔
826
        cidr := parseCIDR(subnetStr)
1✔
827
        if cidr == nil {
1✔
828
                cont.log.WithFields(logrus.Fields{
×
829
                        "subnet": subnetStr,
×
830
                        "netpol": key,
×
831
                }).Warning("Invalid subnet or IP")
×
832
                return false
×
833
        }
×
834

835
        entries, err := index.CoveredNetworks(*cidr)
1✔
836
        if err != nil {
1✔
837
                cont.log.Error("Corrupted subnet index: ", err)
×
838
                return false
×
839
        }
×
840
        if add {
2✔
841
                for _, entryObj := range entries {
2✔
842
                        if netEqual(entryObj.Network(), *cidr) {
2✔
843
                                entry := entryObj.(*ipIndexEntry)
1✔
844
                                existing := entry.keys[key]
1✔
845
                                entry.keys[key] = true
1✔
846
                                return !existing
1✔
847
                        }
1✔
848
                }
849

850
                entry := &ipIndexEntry{
1✔
851
                        ipNet: *cidr,
1✔
852
                        keys: map[string]bool{
1✔
853
                                key: true,
1✔
854
                        },
1✔
855
                }
1✔
856
                index.Insert(entry)
1✔
857
                return true
1✔
858
        } else {
1✔
859
                var existing bool
1✔
860
                for _, entryObj := range entries {
2✔
861
                        entry := entryObj.(*ipIndexEntry)
1✔
862
                        if entry.keys[key] {
2✔
863
                                existing = true
1✔
864
                                delete(entry.keys, key)
1✔
865
                        }
1✔
866
                        if len(entry.keys) == 0 {
2✔
867
                                index.Remove(entry.Network())
1✔
868
                        }
1✔
869
                }
870
                return existing
1✔
871
        }
872
}
873

874
func (cont *AciController) updateIpIndex(index cidranger.Ranger,
875
        oldSubnets map[string]bool, newSubnets map[string]bool, key string) {
1✔
876
        for subStr := range oldSubnets {
2✔
877
                if newSubnets[subStr] {
2✔
878
                        continue
1✔
879
                }
880
                cont.updateIpIndexEntry(index, subStr, key, false)
1✔
881
        }
882
        for subStr := range newSubnets {
2✔
883
                if oldSubnets[subStr] {
2✔
884
                        continue
1✔
885
                }
886
                cont.updateIpIndexEntry(index, subStr, key, true)
1✔
887
        }
888
}
889

890
func (cont *AciController) updateTargetPortIndex(service bool, key string,
891
        oldPorts map[string]targetPort, newPorts map[string]targetPort) {
1✔
892
        for portkey := range oldPorts {
2✔
893
                if _, ok := newPorts[portkey]; ok {
1✔
894
                        continue
×
895
                }
896

897
                entry, ok := cont.targetPortIndex[portkey]
1✔
898
                if !ok {
1✔
899
                        continue
×
900
                }
901

902
                if service {
1✔
903
                        delete(entry.serviceKeys, key)
×
904
                } else {
1✔
905
                        delete(entry.networkPolicyKeys, key)
1✔
906
                }
1✔
907
                if len(entry.serviceKeys) == 0 && len(entry.networkPolicyKeys) == 0 {
2✔
908
                        delete(cont.targetPortIndex, portkey)
1✔
909
                }
1✔
910
        }
911
        for portkey, port := range newPorts {
2✔
912
                if _, ok := oldPorts[portkey]; ok {
1✔
913
                        continue
×
914
                }
915
                entry := cont.targetPortIndex[portkey]
1✔
916
                if entry == nil {
2✔
917
                        entry = &portIndexEntry{
1✔
918
                                port:              port,
1✔
919
                                serviceKeys:       make(map[string]bool),
1✔
920
                                networkPolicyKeys: make(map[string]bool),
1✔
921
                        }
1✔
922
                        cont.targetPortIndex[portkey] = entry
1✔
923
                } else {
2✔
924
                        entry.port.ports = port.ports
1✔
925
                }
1✔
926

927
                if service {
2✔
928
                        entry.serviceKeys[key] = true
1✔
929
                } else {
2✔
930
                        entry.networkPolicyKeys[key] = true
1✔
931
                }
1✔
932
        }
933
}
934

935
func (cont *AciController) getPortNumsFromPortName(podKeys []string, portName string) []int {
1✔
936
        var ports []int
1✔
937
        portmap := make(map[int]bool)
1✔
938
        for _, podkey := range podKeys {
2✔
939
                podobj, exists, err := cont.podIndexer.GetByKey(podkey)
1✔
940
                if exists && err == nil {
2✔
941
                        pod := podobj.(*v1.Pod)
1✔
942
                        port, err := k8util.LookupContainerPortNumberByName(*pod, portName)
1✔
943
                        if err != nil {
1✔
944
                                continue
×
945
                        }
946
                        if _, ok := portmap[int(port)]; !ok {
2✔
947
                                ports = append(ports, int(port))
1✔
948
                                portmap[int(port)] = true
1✔
949
                        }
1✔
950
                }
951
        }
952
        if len(ports) == 0 {
2✔
953
                cont.log.Infof("No matching portnumbers for portname %s: ", portName)
1✔
954
        }
1✔
955
        cont.log.Debug("PortName: ", portName, "Mapping port numbers: ", ports)
1✔
956
        return ports
1✔
957
}
958

959
// get a map of target ports for egress rules that have no "To" clause
960
func (cont *AciController) getNetPolTargetPorts(np *v1net.NetworkPolicy) map[string]targetPort {
1✔
961
        ports := make(map[string]targetPort)
1✔
962
        for _, egress := range np.Spec.Egress {
2✔
963
                if len(egress.To) != 0 && !isNamedPortPresenInNp(np) {
2✔
964
                        continue
1✔
965
                }
966
                for _, port := range egress.Ports {
2✔
967
                        if port.Port == nil {
1✔
968
                                continue
×
969
                        }
970
                        proto := v1.ProtocolTCP
1✔
971
                        if port.Protocol != nil {
2✔
972
                                proto = *port.Protocol
1✔
973
                        }
1✔
974
                        npKey, _ := cache.MetaNamespaceKeyFunc(np)
1✔
975
                        var key string
1✔
976
                        var portnums []int
1✔
977
                        if port.Port.Type == intstr.Int {
2✔
978
                                key = portProto(&proto) + "-num-" + port.Port.String()
1✔
979
                                portnums = append(portnums, port.Port.IntValue())
1✔
980
                        } else {
2✔
981
                                if len(egress.To) != 0 {
2✔
982
                                        // TODO optimize this code instead going through all matching pods every time
1✔
983
                                        podKeys := cont.netPolEgressPods.GetPodForObj(npKey)
1✔
984
                                        portnums = cont.getPortNumsFromPortName(podKeys, port.Port.String())
1✔
985
                                } else {
2✔
986
                                        ctrNmpEntry, ok := cont.ctrPortNameCache[port.Port.String()]
1✔
987
                                        if ok {
2✔
988
                                                for key := range ctrNmpEntry.ctrNmpToPods {
2✔
989
                                                        val := strings.Split(key, "-")
1✔
990
                                                        if len(val) != 2 {
1✔
991
                                                                continue
×
992
                                                        }
993
                                                        if val[0] == portProto(&proto) {
2✔
994
                                                                port, _ := strconv.Atoi(val[1])
1✔
995
                                                                portnums = append(portnums, port)
1✔
996
                                                        }
1✔
997
                                                }
998
                                        }
999
                                }
1000
                                if len(portnums) == 0 {
2✔
1001
                                        continue
1✔
1002
                                }
1003
                                key = portProto(&proto) + "-name-" + port.Port.String()
1✔
1004
                        }
1005
                        ports[key] = targetPort{
1✔
1006
                                proto: proto,
1✔
1007
                                ports: portnums,
1✔
1008
                        }
1✔
1009
                }
1010
        }
1011
        return ports
1✔
1012
}
1013

1014
type peerRemoteInfo struct {
1015
        remotePods  []*v1.Pod
1016
        podSelector *metav1.LabelSelector
1017
}
1018

1019
func (cont *AciController) getPeerRemoteSubnets(peers []v1net.NetworkPolicyPeer,
1020
        namespace string, peerPods []*v1.Pod, peerNs map[string]*v1.Namespace,
1021
        logger *logrus.Entry) ([]string, []string, peerRemoteInfo, map[string]bool, []string) {
1✔
1022
        var remoteSubnets []string
1✔
1023
        var peerremote peerRemoteInfo
1✔
1024
        subnetMap := make(map[string]bool)
1✔
1025
        var peerNsList []string
1✔
1026
        var ipBlockSubs []string
1✔
1027
        if len(peers) > 0 {
2✔
1028
                // only applies to matching pods
1✔
1029
                for _, pod := range peerPods {
2✔
1030
                        for peerIx, peer := range peers {
2✔
1031
                                if ns, ok := peerNs[pod.ObjectMeta.Namespace]; ok &&
1✔
1032
                                        cont.peerMatchesPod(namespace,
1✔
1033
                                                &peers[peerIx], pod, ns) {
2✔
1034
                                        podIps := ipsForPod(pod)
1✔
1035
                                        for _, ip := range podIps {
2✔
1036
                                                if _, exists := subnetMap[ip]; !exists {
2✔
1037
                                                        subnetMap[ip] = true
1✔
1038
                                                        if cont.config.EnableHppDirect {
2✔
1039
                                                                peerremote.remotePods = append(peerremote.remotePods, pod)
1✔
1040
                                                                if !slices.Contains(peerNsList, pod.ObjectMeta.Namespace) {
2✔
1041
                                                                        peerNsList = append(peerNsList, pod.ObjectMeta.Namespace)
1✔
1042
                                                                }
1✔
1043
                                                        }
1044
                                                        remoteSubnets = append(remoteSubnets, ip)
1✔
1045
                                                }
1046
                                        }
1047
                                }
1048
                                if cont.config.EnableHppDirect && peer.PodSelector != nil {
2✔
1049
                                        peerremote.podSelector = peer.PodSelector
1✔
1050
                                }
1✔
1051
                        }
1052
                }
1053

1054
                for _, peer := range peers {
2✔
1055
                        if peer.IPBlock == nil {
2✔
1056
                                continue
1✔
1057
                        }
1058
                        subs, err := ipBlockToSubnets(peer.IPBlock)
1✔
1059
                        if err != nil {
1✔
1060
                                logger.Warning("Invalid IPBlock in network policy rule: ", err)
×
1061
                        } else {
1✔
1062
                                for _, subnet := range subs {
2✔
1063
                                        subnetMap[subnet] = true
1✔
1064
                                }
1✔
1065
                                remoteSubnets = append(remoteSubnets, subs...)
1✔
1066
                                ipBlockSubs = append(ipBlockSubs, subs...)
1✔
1067
                        }
1068
                }
1069
        }
1070
        sort.Strings(remoteSubnets)
1✔
1071
        return remoteSubnets, peerNsList, peerremote, subnetMap, ipBlockSubs
1✔
1072
}
1073

1074
func (cont *AciController) ipInPodSubnet(ip net.IP) bool {
×
1075
        for _, podsubnet := range cont.config.PodSubnet {
×
1076
                _, subnet, err := net.ParseCIDR(podsubnet)
×
1077
                if err == nil && subnet != nil {
×
1078
                        if subnet.Contains(ip) {
×
1079
                                return true
×
1080
                        }
×
1081
                }
1082
        }
1083
        return false
×
1084
}
1085

1086
func (cont *AciController) buildNetPolSubjRule(subj apicapi.ApicObject, ruleName,
1087
        direction, ethertype, proto, port string, remoteSubnets []string,
1088
        addPodSubnetAsRemIp bool) {
1✔
1089
        ruleNameWithEtherType := fmt.Sprintf("%s-%s", ruleName, ethertype)
1✔
1090
        rule := apicapi.NewHostprotRule(subj.GetDn(), ruleNameWithEtherType)
1✔
1091
        rule.SetAttr("direction", direction)
1✔
1092
        rule.SetAttr("ethertype", ethertype)
1✔
1093
        if proto != "" {
2✔
1094
                rule.SetAttr("protocol", proto)
1✔
1095
        }
1✔
1096

1097
        if addPodSubnetAsRemIp {
1✔
1098
                for _, podsubnet := range cont.config.PodSubnet {
×
1099
                        _, subnet, err := net.ParseCIDR(podsubnet)
×
1100
                        if err == nil && subnet != nil {
×
1101
                                if (ethertype == "ipv4" && subnet.IP.To4() != nil) || (ethertype == "ipv6" && subnet.IP.To4() == nil) {
×
1102
                                        rule.AddChild(apicapi.NewHostprotRemoteIp(rule.GetDn(), podsubnet))
×
1103
                                }
×
1104
                        }
1105
                }
1106
        }
1107
        for _, subnetStr := range remoteSubnets {
2✔
1108
                _, subnet, err := net.ParseCIDR(subnetStr)
1✔
1109
                if err == nil && subnet != nil {
2✔
1110
                        // subnetStr is a valid CIDR notation, check its IP version and add the subnet to the rule
1✔
1111
                        if (ethertype == "ipv4" && subnet.IP.To4() != nil) || (ethertype == "ipv6" && subnet.IP.To4() == nil) {
2✔
1112
                                rule.AddChild(apicapi.NewHostprotRemoteIp(rule.GetDn(), subnetStr))
1✔
1113
                        }
1✔
1114
                } else if ip := net.ParseIP(subnetStr); ip != nil {
2✔
1115
                        if addPodSubnetAsRemIp && cont.ipInPodSubnet(ip) {
1✔
1116
                                continue
×
1117
                        }
1118
                        if ethertype == "ipv6" && (ip.To16() != nil && ip.To4() == nil) || ethertype == "ipv4" && ip.To4() != nil {
2✔
1119
                                rule.AddChild(apicapi.NewHostprotRemoteIp(rule.GetDn(), subnetStr))
1✔
1120
                        }
1✔
1121
                }
1122
        }
1123
        if port != "" {
2✔
1124
                rule.SetAttr("toPort", port)
1✔
1125
        }
1✔
1126

1127
        subj.AddChild(rule)
1✔
1128
}
1129

1130
func (cont *AciController) buildLocalNetPolSubjRule(subj *hppv1.HostprotSubj, ruleName,
1131
        direction, ethertype, proto, port string, remoteNs []string,
1132
        podSelector *metav1.LabelSelector, remoteSubnets []string) {
1✔
1133
        rule := hppv1.HostprotRule{
1✔
1134
                ConnTrack: "reflexive",
1✔
1135
                Direction: "ingress",
1✔
1136
                Ethertype: "undefined",
1✔
1137
                Protocol:  "unspecified",
1✔
1138
                FromPort:  "unspecified",
1✔
1139
                ToPort:    "unspecified",
1✔
1140
        }
1✔
1141
        rule.Direction = direction
1✔
1142
        rule.Ethertype = ethertype
1✔
1143
        if proto != "" {
2✔
1144
                rule.Protocol = proto
1✔
1145
        }
1✔
1146
        rule.Name = ruleName
1✔
1147

1✔
1148
        rule.RsRemoteIpContainer = remoteNs
1✔
1149

1✔
1150
        if podSelector != nil {
2✔
1151
                filterContainer := hppv1.HostprotFilterContainer{}
1✔
1152
                for key, val := range podSelector.MatchLabels {
2✔
1153
                        filter := hppv1.HostprotFilter{
1✔
1154
                                Key: key,
1✔
1155
                        }
1✔
1156
                        filter.Values = append(filter.Values, val)
1✔
1157
                        filter.Operator = "Equals"
1✔
1158
                        filterContainer.HostprotFilter = append(filterContainer.HostprotFilter, filter)
1✔
1159
                }
1✔
1160
                for _, expressions := range podSelector.MatchExpressions {
2✔
1161
                        filter := hppv1.HostprotFilter{
1✔
1162
                                Key:      expressions.Key,
1✔
1163
                                Values:   expressions.Values,
1✔
1164
                                Operator: string(expressions.Operator),
1✔
1165
                        }
1✔
1166
                        filterContainer.HostprotFilter = append(filterContainer.HostprotFilter, filter)
1✔
1167
                }
1✔
1168
                rule.HostprotFilterContainer = filterContainer
1✔
1169
        }
1170

1171
        if port != "" {
2✔
1172
                rule.ToPort = port
1✔
1173
        }
1✔
1174

1175
        if len(remoteSubnets) != 0 {
2✔
1176
                rule.HostprotServiceRemoteIps = remoteSubnets
1✔
1177
        }
1✔
1178

1179
        subj.HostprotRule = append(subj.HostprotRule, rule)
1✔
1180
}
1181

1182
func (cont *AciController) buildNetPolSubjRules(ruleName string,
1183
        subj apicapi.ApicObject, direction string, peers []v1net.NetworkPolicyPeer,
1184
        remoteSubnets []string, ports []v1net.NetworkPolicyPort,
1185
        logger *logrus.Entry, npKey string, np *v1net.NetworkPolicy,
1186
        addPodSubnetAsRemIp bool) {
1✔
1187
        if len(peers) > 0 && len(remoteSubnets) == 0 {
2✔
1188
                // nonempty From matches no pods or IPBlocks; don't
1✔
1189
                // create the rule
1✔
1190
                return
1✔
1191
        }
1✔
1192
        if len(ports) == 0 {
2✔
1193
                if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
1194
                        cont.buildNetPolSubjRule(subj, ruleName, direction,
1✔
1195
                                "ipv4", "", "", remoteSubnets, addPodSubnetAsRemIp)
1✔
1196
                }
1✔
1197
                if !cont.configuredPodNetworkIps.V6.Empty() {
2✔
1198
                        cont.buildNetPolSubjRule(subj, ruleName, direction,
1✔
1199
                                "ipv6", "", "", remoteSubnets, addPodSubnetAsRemIp)
1✔
1200
                }
1✔
1201
        } else {
1✔
1202
                for j := range ports {
2✔
1203
                        proto := portProto(ports[j].Protocol)
1✔
1204
                        var portList []string
1✔
1205

1✔
1206
                        if ports[j].Port != nil {
2✔
1207
                                if ports[j].Port.Type == intstr.Int {
2✔
1208
                                        portList = append(portList, ports[j].Port.String())
1✔
1209
                                } else {
2✔
1210
                                        var portnums []int
1✔
1211
                                        if direction == "egress" {
2✔
1212
                                                portnums = append(portnums, cont.getPortNums(&ports[j])...)
1✔
1213
                                        } else {
2✔
1214
                                                // TODO need to handle empty Pod Selector
1✔
1215
                                                if reflect.DeepEqual(np.Spec.PodSelector, metav1.LabelSelector{}) {
1✔
1216
                                                        logger.Warning("Empty PodSelctor for NamedPort is not supported in ingress direction"+
×
1217
                                                                "port in network policy: ", ports[j].Port.String())
×
1218
                                                        continue
×
1219
                                                }
1220
                                                podKeys := cont.netPolPods.GetPodForObj(npKey)
1✔
1221
                                                portnums = cont.getPortNumsFromPortName(podKeys, ports[j].Port.String())
1✔
1222
                                        }
1223
                                        if len(portnums) == 0 {
2✔
1224
                                                logger.Warning("There is no matching  ports in ingress/egress direction "+
1✔
1225
                                                        "port in network policy: ", ports[j].Port.String())
1✔
1226
                                                continue
1✔
1227
                                        }
1228
                                        for _, portnum := range portnums {
2✔
1229
                                                portList = append(portList, strconv.Itoa(portnum))
1✔
1230
                                        }
1✔
1231
                                }
1232
                        }
1233
                        for i, port := range portList {
2✔
1234
                                if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
1235
                                        cont.buildNetPolSubjRule(subj, ruleName+"_"+strconv.Itoa(i+j), direction,
1✔
1236
                                                "ipv4", proto, port, remoteSubnets, addPodSubnetAsRemIp)
1✔
1237
                                }
1✔
1238
                                if !cont.configuredPodNetworkIps.V6.Empty() {
2✔
1239
                                        cont.buildNetPolSubjRule(subj, ruleName+"_"+strconv.Itoa(i+j), direction,
1✔
1240
                                                "ipv6", proto, port, remoteSubnets, addPodSubnetAsRemIp)
1✔
1241
                                }
1✔
1242
                        }
1243
                        if len(portList) == 0 && proto != "" {
2✔
1244
                                if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
1245
                                        cont.buildNetPolSubjRule(subj, ruleName+"_"+strconv.Itoa(j), direction,
1✔
1246
                                                "ipv4", proto, "", remoteSubnets, addPodSubnetAsRemIp)
1✔
1247
                                }
1✔
1248
                                if !cont.configuredPodNetworkIps.V6.Empty() {
1✔
1249
                                        cont.buildNetPolSubjRule(subj, ruleName+"_"+strconv.Itoa(j), direction,
×
1250
                                                "ipv6", proto, "", remoteSubnets, addPodSubnetAsRemIp)
×
1251
                                }
×
1252
                        }
1253
                }
1254
        }
1255
}
1256

1257
func (cont *AciController) buildLocalNetPolSubjRules(ruleName string,
1258
        subj *hppv1.HostprotSubj, direction string, peerNs []string,
1259
        podSelector *metav1.LabelSelector, ports []v1net.NetworkPolicyPort,
1260
        logger *logrus.Entry, npKey string, np *v1net.NetworkPolicy, peerIpBlock []string) {
1✔
1261
        if len(ports) == 0 {
2✔
1262
                if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
1263
                        cont.buildLocalNetPolSubjRule(subj, ruleName+"-ipv4", direction,
1✔
1264
                                "ipv4", "", "", peerNs, podSelector, peerIpBlock)
1✔
1265
                }
1✔
1266
                if !cont.configuredPodNetworkIps.V6.Empty() {
1✔
1267
                        cont.buildLocalNetPolSubjRule(subj, ruleName+"-ipv6", direction,
×
1268
                                "ipv6", "", "", peerNs, podSelector, peerIpBlock)
×
1269
                }
×
1270
        } else {
1✔
1271
                for j := range ports {
2✔
1272
                        proto := portProto(ports[j].Protocol)
1✔
1273
                        var portList []string
1✔
1274

1✔
1275
                        if ports[j].Port != nil {
2✔
1276
                                if ports[j].Port.Type == intstr.Int {
2✔
1277
                                        portList = append(portList, ports[j].Port.String())
1✔
1278
                                } else {
1✔
1279
                                        var portnums []int
×
1280
                                        if direction == "egress" {
×
1281
                                                portnums = append(portnums, cont.getPortNums(&ports[j])...)
×
1282
                                        } else {
×
1283
                                                // TODO need to handle empty Pod Selector
×
1284
                                                if reflect.DeepEqual(np.Spec.PodSelector, metav1.LabelSelector{}) {
×
1285
                                                        logger.Warning("Empty PodSelctor for NamedPort is not supported in ingress direction"+
×
1286
                                                                "port in network policy: ", ports[j].Port.String())
×
1287
                                                        continue
×
1288
                                                }
1289
                                                podKeys := cont.netPolPods.GetPodForObj(npKey)
×
1290
                                                portnums = cont.getPortNumsFromPortName(podKeys, ports[j].Port.String())
×
1291
                                        }
1292
                                        if len(portnums) == 0 {
×
1293
                                                logger.Warning("There is no matching  ports in ingress/egress direction "+
×
1294
                                                        "port in network policy: ", ports[j].Port.String())
×
1295
                                                continue
×
1296
                                        }
1297
                                        for _, portnum := range portnums {
×
1298
                                                portList = append(portList, strconv.Itoa(portnum))
×
1299
                                        }
×
1300
                                }
1301
                        }
1302
                        for i, port := range portList {
2✔
1303
                                if !cont.configuredPodNetworkIps.V4.Empty() {
2✔
1304
                                        cont.buildLocalNetPolSubjRule(subj, ruleName+"_"+strconv.Itoa(i+j)+"-ipv4", direction,
1✔
1305
                                                "ipv4", proto, port, peerNs, podSelector, peerIpBlock)
1✔
1306
                                }
1✔
1307
                                if !cont.configuredPodNetworkIps.V6.Empty() {
1✔
1308
                                        cont.buildLocalNetPolSubjRule(subj, ruleName+"_"+strconv.Itoa(i+j)+"-ipv6", direction,
×
1309
                                                "ipv6", proto, port, peerNs, podSelector, peerIpBlock)
×
1310
                                }
×
1311
                        }
1312
                        if len(portList) == 0 && proto != "" {
1✔
1313
                                if !cont.configuredPodNetworkIps.V4.Empty() {
×
1314
                                        cont.buildLocalNetPolSubjRule(subj, ruleName+"_"+strconv.Itoa(j)+"-ipv4", direction,
×
1315
                                                "ipv4", proto, "", peerNs, podSelector, peerIpBlock)
×
1316
                                }
×
1317
                                if !cont.configuredPodNetworkIps.V6.Empty() {
×
1318
                                        cont.buildLocalNetPolSubjRule(subj, ruleName+"_"+strconv.Itoa(j)+"-ipv6", direction,
×
1319
                                                "ipv6", proto, "", peerNs, podSelector, peerIpBlock)
×
1320
                                }
×
1321
                        }
1322
                }
1323
        }
1324
}
1325

1326
func (cont *AciController) getPortNums(port *v1net.NetworkPolicyPort) []int {
1✔
1327
        portkey := portKey(port)
1✔
1328
        cont.indexMutex.Lock()
1✔
1329
        defer cont.indexMutex.Unlock()
1✔
1330
        cont.log.Debug("PortKey1: ", portkey)
1✔
1331
        entry := cont.targetPortIndex[portkey]
1✔
1332
        var length int
1✔
1333
        if entry == nil || len(entry.port.ports) == 0 {
2✔
1334
                return []int{}
1✔
1335
        }
1✔
1336
        length = len(entry.port.ports)
1✔
1337
        ports := make([]int, length)
1✔
1338
        copy(ports, entry.port.ports)
1✔
1339
        return ports
1✔
1340
}
1341
func portProto(protocol *v1.Protocol) string {
1✔
1342
        proto := "tcp"
1✔
1343
        if protocol != nil && *protocol == v1.ProtocolUDP {
2✔
1344
                proto = "udp"
1✔
1345
        } else if protocol != nil && *protocol == v1.ProtocolSCTP {
3✔
1346
                proto = "sctp"
1✔
1347
        }
1✔
1348
        return proto
1✔
1349
}
1350

1351
func portKey(p *v1net.NetworkPolicyPort) string {
1✔
1352
        portType := ""
1✔
1353
        port := ""
1✔
1354
        if p != nil && p.Port != nil {
2✔
1355
                if p.Port.Type == intstr.Int {
2✔
1356
                        portType = "num"
1✔
1357
                } else {
2✔
1358
                        portType = "name"
1✔
1359
                }
1✔
1360
                port = p.Port.String()
1✔
1361
                return portProto(p.Protocol) + "-" + portType + "-" + port
1✔
1362
        }
1363
        return ""
1✔
1364
}
1365

1366
func checkEndpoints(subnetIndex cidranger.Ranger,
1367
        addresses []v1.EndpointAddress) bool {
1✔
1368
        for _, addr := range addresses {
2✔
1369
                ip := net.ParseIP(addr.IP)
1✔
1370
                if ip == nil {
1✔
1371
                        return false
×
1372
                }
×
1373
                contains, err := subnetIndex.Contains(ip)
1✔
1374
                if err != nil || !contains {
2✔
1375
                        return false
1✔
1376
                }
1✔
1377
        }
1378

1379
        return true
1✔
1380
}
1381
func checkEndpointslices(subnetIndex cidranger.Ranger,
1382
        addresses []string) bool {
1✔
1383
        for _, addr := range addresses {
2✔
1384
                ip := net.ParseIP(addr)
1✔
1385
                if ip == nil {
1✔
1386
                        return false
×
1387
                }
×
1388
                contains, err := subnetIndex.Contains(ip)
1✔
1389
                if err != nil || !contains {
2✔
1390
                        return false
1✔
1391
                }
1✔
1392
        }
1393
        return true
1✔
1394
}
1395

1396
type portRemoteSubnet struct {
1397
        port           *v1net.NetworkPolicyPort
1398
        subnetMap      map[string]bool
1399
        hasNamedTarget bool
1400
}
1401

1402
func updatePortRemoteSubnets(portRemoteSubs map[string]*portRemoteSubnet,
1403
        portkey string, port *v1net.NetworkPolicyPort, subnetMap map[string]bool,
1404
        hasNamedTarget bool) {
1✔
1405
        if prs, ok := portRemoteSubs[portkey]; ok {
1✔
1406
                for s := range subnetMap {
×
1407
                        prs.subnetMap[s] = true
×
1408
                }
×
1409
                prs.hasNamedTarget = hasNamedTarget || prs.hasNamedTarget
×
1410
        } else {
1✔
1411
                portRemoteSubs[portkey] = &portRemoteSubnet{
1✔
1412
                        port:           port,
1✔
1413
                        subnetMap:      subnetMap,
1✔
1414
                        hasNamedTarget: hasNamedTarget,
1✔
1415
                }
1✔
1416
        }
1✔
1417
}
1418

1419
func portServiceAugmentKey(proto, port string) string {
1✔
1420
        return proto + "-" + port
1✔
1421
}
1✔
1422

1423
type portServiceAugment struct {
1424
        proto string
1425
        port  string
1426
        ipMap map[string]bool
1427
}
1428

1429
func updateServiceAugment(portAugments map[string]*portServiceAugment, proto, port, ip string) {
1✔
1430
        key := portServiceAugmentKey(proto, port)
1✔
1431
        if psa, ok := portAugments[key]; ok {
1✔
1432
                psa.ipMap[ip] = true
×
1433
        } else {
1✔
1434
                portAugments[key] = &portServiceAugment{
1✔
1435
                        proto: proto,
1✔
1436
                        port:  port,
1✔
1437
                        ipMap: map[string]bool{ip: true},
1✔
1438
                }
1✔
1439
        }
1✔
1440
}
1441

1442
func updateServiceAugmentForService(portAugments map[string]*portServiceAugment,
1443
        proto, port string, service *v1.Service) {
1✔
1444
        if service.Spec.ClusterIP != "" {
2✔
1445
                updateServiceAugment(portAugments,
1✔
1446
                        proto, port, service.Spec.ClusterIP)
1✔
1447
        }
1✔
1448
        for _, ig := range service.Status.LoadBalancer.Ingress {
1✔
1449
                if ig.IP == "" {
×
1450
                        continue
×
1451
                }
1452
                updateServiceAugment(portAugments,
×
1453
                        proto, port, ig.IP)
×
1454
        }
1455
}
1456

1457
// build service augment by matching peers against the endpoints ip
1458
// index
1459
func (cont *AciController) getServiceAugmentBySubnet(
1460
        prs *portRemoteSubnet, portAugments map[string]*portServiceAugment,
1461
        logger *logrus.Entry) {
1✔
1462
        matchedServices := make(map[string]bool)
1✔
1463
        subnetIndex := cidranger.NewPCTrieRanger()
1✔
1464

1✔
1465
        // find candidate service endpoints objects that include
1✔
1466
        // endpoints selected by the egress rule
1✔
1467
        cont.indexMutex.Lock()
1✔
1468
        for sub := range prs.subnetMap {
2✔
1469
                cidr := parseCIDR(sub)
1✔
1470
                if cidr == nil {
1✔
1471
                        continue
×
1472
                }
1473
                subnetIndex.Insert(cidranger.NewBasicRangerEntry(*cidr))
1✔
1474

1✔
1475
                entries, err := cont.endpointsIpIndex.CoveredNetworks(*cidr)
1✔
1476
                if err != nil {
1✔
1477
                        logger.Error("endpointsIpIndex corrupted: ", err)
×
1478
                        continue
×
1479
                }
1480
                for _, entry := range entries {
2✔
1481
                        e := entry.(*ipIndexEntry)
1✔
1482
                        for servicekey := range e.keys {
2✔
1483
                                matchedServices[servicekey] = true
1✔
1484
                        }
1✔
1485
                }
1486
        }
1487
        cont.indexMutex.Unlock()
1✔
1488

1✔
1489
        // if all endpoints are selected by egress rule, allow egress
1✔
1490
        // to the service cluster IP as well as to the endpoints
1✔
1491
        // themselves
1✔
1492
        for servicekey := range matchedServices {
2✔
1493
                serviceobj, _, err := cont.serviceIndexer.GetByKey(servicekey)
1✔
1494
                if err != nil {
1✔
1495
                        logger.Error("Could not lookup service for "+
×
1496
                                servicekey+": ", err.Error())
×
1497
                        continue
×
1498
                }
1499
                if serviceobj == nil {
1✔
1500
                        continue
×
1501
                }
1502
                service := serviceobj.(*v1.Service)
1✔
1503
                cont.serviceEndPoints.SetNpServiceAugmentForService(servicekey, service,
1✔
1504
                        prs, portAugments, subnetIndex, logger)
1✔
1505
        }
1506
}
1507

1508
// build service augment by matching against services with a given
1509
// target port
1510
func (cont *AciController) getServiceAugmentByPort(
1511
        prs *portRemoteSubnet, portAugments map[string]*portServiceAugment,
1512
        logger *logrus.Entry) {
1✔
1513
        // nil port means it matches against all ports.  If we're here, it
1✔
1514
        // means this is a rule that matches all ports with all
1✔
1515
        // destinations, so there's no need to augment anything.
1✔
1516
        if prs.port == nil ||
1✔
1517
                prs.port.Port == nil {
2✔
1518
                return
1✔
1519
        }
1✔
1520

1521
        portkey := portKey(prs.port)
1✔
1522
        cont.indexMutex.Lock()
1✔
1523
        entries := make(map[string]*portIndexEntry)
1✔
1524
        entry := cont.targetPortIndex[portkey]
1✔
1525
        if entry != nil && prs.port.Port.Type == intstr.String {
2✔
1526
                for _, port := range entry.port.ports {
2✔
1527
                        portstring := strconv.Itoa(port)
1✔
1528
                        key := portProto(prs.port.Protocol) + "-" + "num" + "-" + portstring
1✔
1529
                        portEntry := cont.targetPortIndex[key]
1✔
1530
                        if portEntry != nil {
2✔
1531
                                entries[portstring] = portEntry
1✔
1532
                        }
1✔
1533
                }
1534
        } else if entry != nil {
2✔
1535
                if len(entry.port.ports) > 0 {
2✔
1536
                        entries[strconv.Itoa(entry.port.ports[0])] = entry
1✔
1537
                }
1✔
1538
        }
1539
        for key, portentry := range entries {
2✔
1540
                for servicekey := range portentry.serviceKeys {
2✔
1541
                        serviceobj, _, err := cont.serviceIndexer.GetByKey(servicekey)
1✔
1542
                        if err != nil {
1✔
1543
                                logger.Error("Could not lookup service for "+
×
1544
                                        servicekey+": ", err.Error())
×
1545
                                continue
×
1546
                        }
1547
                        if serviceobj == nil {
1✔
1548
                                continue
×
1549
                        }
1550
                        service := serviceobj.(*v1.Service)
1✔
1551

1✔
1552
                        for _, svcPort := range service.Spec.Ports {
2✔
1553
                                if svcPort.Protocol != *prs.port.Protocol ||
1✔
1554
                                        svcPort.TargetPort.String() !=
1✔
1555
                                                key {
1✔
1556
                                        continue
×
1557
                                }
1558
                                proto := portProto(&svcPort.Protocol)
1✔
1559
                                port := strconv.Itoa(int(svcPort.Port))
1✔
1560

1✔
1561
                                updateServiceAugmentForService(portAugments,
1✔
1562
                                        proto, port, service)
1✔
1563

1✔
1564
                                logger.WithFields(logrus.Fields{
1✔
1565
                                        "proto":   proto,
1✔
1566
                                        "port":    port,
1✔
1567
                                        "service": servicekey,
1✔
1568
                                }).Debug("Allowing egress for service by port")
1✔
1569
                        }
1570
                }
1571
        }
1572
        cont.indexMutex.Unlock()
1✔
1573
}
1574

1575
// The egress NetworkPolicy API were designed with the iptables
1576
// implementation in mind and don't contemplate that the layer 4 load
1577
// balancer could happen separately from the policy.  In particular,
1578
// it expects load balancer operations to be applied before the policy
1579
// is applied in both directions, so network policies would apply only
1580
// to pods and not to service IPs. This presents a problem for egress
1581
// policies on ACI since the security groups are applied before load
1582
// balancer operations when egressing, and after when ingressing.
1583
//
1584
// To solve this problem, we use some indexes to discover situations
1585
// when an egress policy covers all the endpoints associated with a
1586
// particular service, and automatically add a rule that allows egress
1587
// to the corresponding service cluster IP and ports.
1588
//
1589
// Note that this differs slightly from the behavior you'd see if you
1590
// applied the load balancer rule first: If the egress policy allows
1591
// access to a subset of the allowed IPs you'd see random failures
1592
// depending on which destination is chosen, while with this approach
1593
// it's all or nothing.  This should not impact any correctly-written
1594
// network policies.
1595
//
1596
// To do this, we work first from the set of pods and subnets matches
1597
// by the egress policy.  We use this to find using the
1598
// endpointsIpIndex all services that contain at least one of the
1599
// matched pods or subnets.  For each of these candidate services, we
1600
// find service ports for which _all_ referenced endpoints are allowed
1601
// by the egress policy.  Note that a service will have the service
1602
// port and the target port; the NetworkPolicy (confusingly) refers to
1603
// the target port.
1604
//
1605
// Once confirmed matches are found, we augment the egress policy with
1606
// extra rules to allow egress to the service IPs and service ports.
1607
//
1608
// As a special case, for rules that match everything, we also have a
1609
// backup index that works through ports which should allow more
1610
// efficient matching when allowing egress to all.
1611
func (cont *AciController) buildServiceAugment(subj apicapi.ApicObject,
1612
        localsubj *hppv1.HostprotSubj,
1613
        portRemoteSubs map[string]*portRemoteSubnet, logger *logrus.Entry) {
1✔
1614
        portAugments := make(map[string]*portServiceAugment)
1✔
1615
        for _, prs := range portRemoteSubs {
2✔
1616
                // TODO ipv6
1✔
1617
                if prs.subnetMap["0.0.0.0/0"] {
2✔
1618
                        cont.getServiceAugmentByPort(prs, portAugments, logger)
1✔
1619
                } else {
2✔
1620
                        cont.getServiceAugmentBySubnet(prs, portAugments, logger)
1✔
1621
                }
1✔
1622
        }
1623
        for _, augment := range portAugments {
2✔
1624
                var remoteIpsv4 []string
1✔
1625
                var remoteIpsv6 []string
1✔
1626
                for ipstr := range augment.ipMap {
2✔
1627
                        ip := net.ParseIP(ipstr)
1✔
1628
                        if ip == nil {
1✔
1629
                                continue
×
1630
                        } else if ip.To4() != nil {
2✔
1631
                                remoteIpsv4 = append(remoteIpsv4, ipstr)
1✔
1632
                        } else if ip.To16() != nil {
3✔
1633
                                remoteIpsv6 = append(remoteIpsv6, ipstr)
1✔
1634
                        }
1✔
1635
                }
1636
                cont.log.Debug("Service Augment: ", augment)
1✔
1637
                if !cont.config.EnableHppDirect && subj != nil {
2✔
1638
                        if len(remoteIpsv4) > 0 {
2✔
1639
                                cont.buildNetPolSubjRule(subj,
1✔
1640
                                        "service_"+augment.proto+"_"+augment.port,
1✔
1641
                                        "egress", "ipv4", augment.proto, augment.port, remoteIpsv4, false)
1✔
1642
                        }
1✔
1643
                        if len(remoteIpsv6) > 0 {
2✔
1644
                                cont.buildNetPolSubjRule(subj,
1✔
1645
                                        "service_"+augment.proto+"_"+augment.port,
1✔
1646
                                        "egress", "ipv6", augment.proto, augment.port, remoteIpsv6, false)
1✔
1647
                        }
1✔
1648
                } else if cont.config.EnableHppDirect && localsubj != nil {
×
1649
                        if len(remoteIpsv4) > 0 {
×
1650
                                cont.buildLocalNetPolSubjRule(localsubj,
×
1651
                                        "service_"+augment.proto+"_"+augment.port,
×
1652
                                        "egress", "ipv4", augment.proto, augment.port, nil, nil, remoteIpsv4)
×
1653
                        }
×
1654
                        if len(remoteIpsv6) > 0 {
×
1655
                                cont.buildLocalNetPolSubjRule(localsubj,
×
1656
                                        "service_"+augment.proto+"_"+augment.port,
×
1657
                                        "egress", "ipv6", augment.proto, augment.port, nil, nil, remoteIpsv6)
×
1658
                        }
×
1659
                }
1660
        }
1661
}
1662

1663
func isAllowAllForAllNamespaces(peers []v1net.NetworkPolicyPeer) bool {
1✔
1664
        addPodSubnetAsRemIp := false
1✔
1665
        if peers != nil && len(peers) > 0 {
2✔
1666
                var emptyPodSel, emptyNsSel bool
1✔
1667
                emptyPodSel = true
1✔
1668
                for _, peer := range peers {
2✔
1669
                        // namespaceSelector: {}
1✔
1670
                        if peer.NamespaceSelector != nil && peer.NamespaceSelector.MatchLabels == nil && peer.NamespaceSelector.MatchExpressions == nil {
1✔
1671
                                emptyNsSel = true
×
1672
                        }
×
1673
                        // podSelector has some fields
1674
                        if peer.PodSelector != nil && (peer.PodSelector.MatchLabels != nil || peer.PodSelector.MatchExpressions != nil) {
2✔
1675
                                emptyPodSel = false
1✔
1676
                        }
1✔
1677
                }
1678
                if emptyNsSel && emptyPodSel {
1✔
1679
                        addPodSubnetAsRemIp = true
×
1680
                }
×
1681
        }
1682
        return addPodSubnetAsRemIp
1✔
1683
}
1684

1685
func (cont *AciController) handleRemIpContUpdate(ns string) bool {
1✔
1686
        cont.hppMutex.Lock()
1✔
1687
        defer cont.hppMutex.Unlock()
1✔
1688

1✔
1689
        sysNs := os.Getenv("SYSTEM_NAMESPACE")
1✔
1690
        aobj, err := cont.getHostprotRemoteIpContainer(ns, sysNs)
1✔
1691
        isUpdate := err == nil
1✔
1692

1✔
1693
        if err != nil && !errors.IsNotFound(err) {
1✔
1694
                cont.log.Error("Error getting HostprotRemoteIpContainers CR: ", err)
×
1695
                return true
×
1696
        }
×
1697

1698
        if !isUpdate {
2✔
1699
                aobj = &hppv1.HostprotRemoteIpContainer{
1✔
1700
                        ObjectMeta: metav1.ObjectMeta{
1✔
1701
                                Name:      ns,
1✔
1702
                                Namespace: sysNs,
1✔
1703
                        },
1✔
1704
                        Spec: hppv1.HostprotRemoteIpContainerSpec{
1✔
1705
                                Name:             ns,
1✔
1706
                                HostprotRemoteIp: []hppv1.HostprotRemoteIp{},
1✔
1707
                        },
1✔
1708
                }
1✔
1709
        } else {
1✔
1710
                cont.log.Debug("HostprotRemoteIpContainers CR already exists: ", aobj)
×
1711
        }
×
1712

1713
        remIpCont, exists := cont.nsRemoteIpCont[ns]
1✔
1714
        if !exists {
2✔
1715
                if isUpdate {
1✔
1716
                        if !cont.deleteHostprotRemoteIpContainer(ns, sysNs) {
×
1717
                                return true
×
1718
                        }
×
1719
                } else {
1✔
1720
                        cont.log.Error("Couldn't find the ns in nsRemoteIpCont cache: ", ns)
1✔
1721
                        return false
1✔
1722
                }
1✔
1723
        }
1724

1725
        aobj.Spec.HostprotRemoteIp = buildHostprotRemoteIpList(remIpCont)
1✔
1726

1✔
1727
        if isUpdate {
1✔
1728
                if !cont.updateHostprotRemoteIpContainer(aobj, sysNs) {
×
1729
                        return true
×
1730
                }
×
1731
        } else {
1✔
1732
                if !cont.createHostprotRemoteIpContainer(aobj, sysNs) {
1✔
1733
                        return true
×
1734
                }
×
1735
        }
1736

1737
        return false
1✔
1738
}
1739

1740
func buildHostprotRemoteIpList(remIpCont map[string]map[string]string) []hppv1.HostprotRemoteIp {
1✔
1741
        hostprotRemoteIpList := []hppv1.HostprotRemoteIp{}
1✔
1742

1✔
1743
        for ip, labels := range remIpCont {
2✔
1744
                remIpObj := hppv1.HostprotRemoteIp{
1✔
1745
                        Addr: ip,
1✔
1746
                }
1✔
1747
                for key, val := range labels {
2✔
1748
                        remIpObj.HppEpLabel = append(remIpObj.HppEpLabel, hppv1.HppEpLabel{
1✔
1749
                                Key:   key,
1✔
1750
                                Value: val,
1✔
1751
                        })
1✔
1752
                }
1✔
1753
                hostprotRemoteIpList = append(hostprotRemoteIpList, remIpObj)
1✔
1754
        }
1755

1756
        return hostprotRemoteIpList
1✔
1757
}
1758

1759
func (cont *AciController) deleteHppCr(np *v1net.NetworkPolicy) bool {
1✔
1760
        key, err := cache.MetaNamespaceKeyFunc(np)
1✔
1761
        logger := networkPolicyLogger(cont.log, np)
1✔
1762
        if err != nil {
1✔
1763
                logger.Error("Could not create network policy key: ", err)
×
1764
                return false
×
1765
        }
×
1766
        hash, err := util.CreateHashFromNetPol(np)
1✔
1767
        if err != nil {
1✔
1768
                logger.Error("Could not create hash from network policy: ", err)
×
1769
                return false
×
1770
        }
×
1771
        labelKey := cont.aciNameForKey("np", hash)
1✔
1772
        ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
1773
        hppName := strings.ReplaceAll(labelKey, "_", "-")
1✔
1774
        hpp, _ := cont.getHostprotPol(hppName, ns)
1✔
1775
        if hpp == nil {
2✔
1776
                logger.Error("Could not find hostprotPol: ", hppName)
1✔
1777
                return false
1✔
1778
        }
1✔
1779
        netPols := hpp.Spec.NetworkPolicies
1✔
1780
        newNetPols := make([]string, 0)
1✔
1781
        for _, npName := range netPols {
2✔
1782
                if npName != key {
2✔
1783
                        newNetPols = append(newNetPols, npName)
1✔
1784
                }
1✔
1785
        }
1786

1787
        hpp.Spec.NetworkPolicies = newNetPols
1✔
1788

1✔
1789
        if len(newNetPols) > 0 {
2✔
1790
                return cont.updateHostprotPol(hpp, ns)
1✔
1791
        } else {
2✔
1792
                return cont.deleteHostprotPol(hppName, ns)
1✔
1793
        }
1✔
1794
}
1795

1796
func (cont *AciController) updateNodeIpsHostprotRemoteIpContainer(nodeIps map[string]bool) {
1✔
1797
        ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
1798
        name := "nodeips"
1✔
1799

1✔
1800
        aobj, err := cont.getHostprotRemoteIpContainer(name, ns)
1✔
1801
        isUpdate := err == nil
1✔
1802

1✔
1803
        if err != nil && !errors.IsNotFound(err) {
1✔
1804
                cont.log.Error("Error getting HostprotRemoteIpContainers CR: ", err)
×
1805
                return
×
1806
        }
×
1807

1808
        if !isUpdate {
2✔
1809
                aobj = &hppv1.HostprotRemoteIpContainer{
1✔
1810
                        ObjectMeta: metav1.ObjectMeta{
1✔
1811
                                Name:      name,
1✔
1812
                                Namespace: ns,
1✔
1813
                        },
1✔
1814
                        Spec: hppv1.HostprotRemoteIpContainerSpec{
1✔
1815
                                Name:             name,
1✔
1816
                                HostprotRemoteIp: []hppv1.HostprotRemoteIp{},
1✔
1817
                        },
1✔
1818
                }
1✔
1819
        } else {
2✔
1820
                cont.log.Debug("HostprotRemoteIpContainers CR already exists: ", aobj)
1✔
1821
        }
1✔
1822

1823
        existingIps := make(map[string]bool)
1✔
1824
        for _, ip := range aobj.Spec.HostprotRemoteIp {
2✔
1825
                existingIps[ip.Addr] = true
1✔
1826
        }
1✔
1827

1828
        for ip := range nodeIps {
2✔
1829
                if !existingIps[ip] {
2✔
1830
                        aobj.Spec.HostprotRemoteIp = append(aobj.Spec.HostprotRemoteIp, hppv1.HostprotRemoteIp{Addr: ip})
1✔
1831
                }
1✔
1832
        }
1833

1834
        if isUpdate {
2✔
1835
                cont.updateHostprotRemoteIpContainer(aobj, ns)
1✔
1836
        } else {
2✔
1837
                cont.createHostprotRemoteIpContainer(aobj, ns)
1✔
1838
        }
1✔
1839
}
1840

1841
func (cont *AciController) deleteNodeIpsHostprotRemoteIpContainer(nodeIps map[string]bool) {
1✔
1842
        ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
1843
        name := "nodeips"
1✔
1844

1✔
1845
        aobj, _ := cont.getHostprotRemoteIpContainer(name, ns)
1✔
1846
        if aobj == nil {
1✔
1847
                return
×
1848
        }
×
1849

1850
        newHostprotRemoteIps := aobj.Spec.HostprotRemoteIp[:0]
1✔
1851
        for _, hostprotRemoteIp := range aobj.Spec.HostprotRemoteIp {
2✔
1852
                if len(nodeIps) > 0 && !nodeIps[hostprotRemoteIp.Addr] {
2✔
1853
                        newHostprotRemoteIps = append(newHostprotRemoteIps, hostprotRemoteIp)
1✔
1854
                }
1✔
1855
        }
1856

1857
        aobj.Spec.HostprotRemoteIp = newHostprotRemoteIps
1✔
1858

1✔
1859
        if len(newHostprotRemoteIps) > 0 {
2✔
1860
                cont.updateHostprotRemoteIpContainer(aobj, ns)
1✔
1861
        } else {
2✔
1862
                cont.deleteHostprotRemoteIpContainer(name, ns)
1✔
1863
        }
1✔
1864
}
1865

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

1✔
1869
        aobj, err := cont.getHostprotRemoteIpContainer(name, ns)
1✔
1870
        isUpdate := err == nil
1✔
1871

1✔
1872
        if err != nil && !errors.IsNotFound(err) {
1✔
1873
                cont.log.Error("Error getting HostprotRemoteIpContainers CR: ", err)
×
1874
                return
×
1875
        }
×
1876

1877
        if !isUpdate {
2✔
1878
                aobj = &hppv1.HostprotRemoteIpContainer{
1✔
1879
                        ObjectMeta: metav1.ObjectMeta{
1✔
1880
                                Name:      name,
1✔
1881
                                Namespace: ns,
1✔
1882
                        },
1✔
1883
                        Spec: hppv1.HostprotRemoteIpContainerSpec{
1✔
1884
                                Name:             name,
1✔
1885
                                HostprotRemoteIp: []hppv1.HostprotRemoteIp{},
1✔
1886
                        },
1✔
1887
                }
1✔
1888
        } else {
2✔
1889
                cont.log.Debug("HostprotRemoteIpContainers CR already exists: ", aobj)
1✔
1890
        }
1✔
1891

1892
        aobj.Spec.HostprotRemoteIp = make([]hppv1.HostprotRemoteIp, 0, len(nodeIps))
1✔
1893
        for ip := range nodeIps {
2✔
1894
                aobj.Spec.HostprotRemoteIp = append(aobj.Spec.HostprotRemoteIp, hppv1.HostprotRemoteIp{Addr: ip})
1✔
1895
        }
1✔
1896

1897
        if isUpdate {
2✔
1898
                cont.updateHostprotRemoteIpContainer(aobj, ns)
1✔
1899
        } else {
2✔
1900
                cont.createHostprotRemoteIpContainer(aobj, ns)
1✔
1901
        }
1✔
1902
}
1903

1904
func (cont *AciController) deleteNodeHostprotRemoteIpContainer(name string) {
1✔
1905
        ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
1906

1✔
1907
        if _, err := cont.getHostprotRemoteIpContainer(name, ns); err == nil {
2✔
1908
                cont.deleteHostprotRemoteIpContainer(name, ns)
1✔
1909
        }
1✔
1910
}
1911

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

1✔
1916
        hpp, err := cont.getHostprotPol(hppName, ns)
1✔
1917
        isUpdate := hpp != nil && err == nil
1✔
1918

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

1924
        if !isUpdate {
1✔
1925
                hpp = &hppv1.HostprotPol{
×
1926
                        ObjectMeta: metav1.ObjectMeta{
×
1927
                                Name:      hppName,
×
1928
                                Namespace: ns,
×
1929
                        },
×
1930
                        Spec: hppv1.HostprotPolSpec{
×
1931
                                Name:            name,
×
1932
                                NetworkPolicies: []string{name},
×
1933
                                HostprotSubj:    []hppv1.HostprotSubj{},
×
1934
                        },
×
1935
                }
×
1936
        } else {
1✔
1937
                cont.log.Debug("HPP CR already exists: ", hpp)
1✔
1938
                hpp.Spec.HostprotSubj = []hppv1.HostprotSubj{}
1✔
1939
        }
1✔
1940

1941
        if len(nodeIps) > 0 {
2✔
1942
                cont.updateNodeHostprotRemoteIpContainer(nodeName, nodeIps)
1✔
1943
                cont.updateNodeIpsHostprotRemoteIpContainer(nodeIps)
1✔
1944

1✔
1945
                hostprotSubj := hppv1.HostprotSubj{
1✔
1946
                        Name: "local-node",
1✔
1947
                        HostprotRule: []hppv1.HostprotRule{
1✔
1948
                                {
1✔
1949
                                        Name:                "allow-all-egress",
1✔
1950
                                        Direction:           "egress",
1✔
1951
                                        Ethertype:           "ipv4",
1✔
1952
                                        ConnTrack:           "normal",
1✔
1953
                                        RsRemoteIpContainer: []string{nodeName},
1✔
1954
                                },
1✔
1955
                                {
1✔
1956
                                        Name:                "allow-all-ingress",
1✔
1957
                                        Direction:           "ingress",
1✔
1958
                                        Ethertype:           "ipv4",
1✔
1959
                                        ConnTrack:           "normal",
1✔
1960
                                        RsRemoteIpContainer: []string{nodeName},
1✔
1961
                                },
1✔
1962
                        },
1✔
1963
                }
1✔
1964

1✔
1965
                hpp.Spec.HostprotSubj = append(hpp.Spec.HostprotSubj, hostprotSubj)
1✔
1966
        } else {
2✔
1967
                cont.deleteNodeHostprotRemoteIpContainer(nodeName)
1✔
1968
                cont.deleteNodeIpsHostprotRemoteIpContainer(nodeIps)
1✔
1969
        }
1✔
1970

1971
        if isUpdate {
2✔
1972
                cont.updateHostprotPol(hpp, ns)
1✔
1973
        } else {
1✔
1974
                cont.createHostprotPol(hpp, ns)
×
1975
        }
×
1976
}
1977

1978
func (cont *AciController) handleNetPolUpdate(np *v1net.NetworkPolicy) bool {
1✔
1979
        if cont.config.ChainedMode {
1✔
1980
                return false
×
1981
        }
×
1982
        key, err := cache.MetaNamespaceKeyFunc(np)
1✔
1983
        logger := networkPolicyLogger(cont.log, np)
1✔
1984
        if err != nil {
1✔
1985
                logger.Error("Could not create network policy key: ", err)
×
1986
                return false
×
1987
        }
×
1988

1989
        peerPodKeys := cont.netPolIngressPods.GetPodForObj(key)
1✔
1990
        peerPodKeys =
1✔
1991
                append(peerPodKeys, cont.netPolEgressPods.GetPodForObj(key)...)
1✔
1992
        var peerPods []*v1.Pod
1✔
1993
        peerNs := make(map[string]*v1.Namespace)
1✔
1994
        for _, podkey := range peerPodKeys {
2✔
1995
                podobj, exists, err := cont.podIndexer.GetByKey(podkey)
1✔
1996
                if exists && err == nil {
2✔
1997
                        pod := podobj.(*v1.Pod)
1✔
1998
                        if _, nsok := peerNs[pod.ObjectMeta.Namespace]; !nsok {
2✔
1999
                                nsobj, exists, err :=
1✔
2000
                                        cont.namespaceIndexer.GetByKey(pod.ObjectMeta.Namespace)
1✔
2001
                                if !exists || err != nil {
1✔
2002
                                        continue
×
2003
                                }
2004
                                peerNs[pod.ObjectMeta.Namespace] = nsobj.(*v1.Namespace)
1✔
2005
                        }
2006
                        peerPods = append(peerPods, pod)
1✔
2007
                }
2008
        }
2009
        ptypeset := make(map[v1net.PolicyType]bool)
1✔
2010
        for _, t := range np.Spec.PolicyTypes {
2✔
2011
                ptypeset[t] = true
1✔
2012
        }
1✔
2013
        var labelKey string
1✔
2014

1✔
2015
        if !cont.config.EnableHppDirect {
2✔
2016
                if cont.config.HppOptimization {
2✔
2017
                        hash, err := util.CreateHashFromNetPol(np)
1✔
2018
                        if err != nil {
1✔
2019
                                logger.Error("Could not create hash from network policy: ", err)
×
2020
                                return false
×
2021
                        }
×
2022
                        labelKey = cont.aciNameForKey("np", hash)
1✔
2023
                } else {
1✔
2024
                        labelKey = cont.aciNameForKey("np", key)
1✔
2025
                }
1✔
2026
                hpp := apicapi.NewHostprotPol(cont.config.AciPolicyTenant, labelKey)
1✔
2027
                // Generate ingress policies
1✔
2028
                if np.Spec.PolicyTypes == nil || ptypeset[v1net.PolicyTypeIngress] {
2✔
2029
                        subjIngress :=
1✔
2030
                                apicapi.NewHostprotSubj(hpp.GetDn(), "networkpolicy-ingress")
1✔
2031

1✔
2032
                        for i, ingress := range np.Spec.Ingress {
2✔
2033
                                addPodSubnetAsRemIp := isAllowAllForAllNamespaces(ingress.From)
1✔
2034
                                remoteSubnets, _, _, _, _ := cont.getPeerRemoteSubnets(ingress.From,
1✔
2035
                                        np.Namespace, peerPods, peerNs, logger)
1✔
2036
                                cont.buildNetPolSubjRules(strconv.Itoa(i), subjIngress,
1✔
2037
                                        "ingress", ingress.From, remoteSubnets, ingress.Ports, logger, key, np, addPodSubnetAsRemIp)
1✔
2038
                        }
1✔
2039
                        hpp.AddChild(subjIngress)
1✔
2040
                }
2041
                // Generate egress policies
2042
                if np.Spec.PolicyTypes == nil || ptypeset[v1net.PolicyTypeEgress] {
2✔
2043
                        subjEgress :=
1✔
2044
                                apicapi.NewHostprotSubj(hpp.GetDn(), "networkpolicy-egress")
1✔
2045

1✔
2046
                        portRemoteSubs := make(map[string]*portRemoteSubnet)
1✔
2047

1✔
2048
                        for i, egress := range np.Spec.Egress {
2✔
2049
                                addPodSubnetAsRemIp := isAllowAllForAllNamespaces(egress.To)
1✔
2050
                                remoteSubnets, _, _, subnetMap, _ := cont.getPeerRemoteSubnets(egress.To,
1✔
2051
                                        np.Namespace, peerPods, peerNs, logger)
1✔
2052
                                cont.buildNetPolSubjRules(strconv.Itoa(i), subjEgress,
1✔
2053
                                        "egress", egress.To, remoteSubnets, egress.Ports, logger, key, np, addPodSubnetAsRemIp)
1✔
2054

1✔
2055
                                // creating a rule to egress to all on a given port needs
1✔
2056
                                // to enable access to any service IPs/ports that have
1✔
2057
                                // that port as their target port.
1✔
2058
                                if len(egress.To) == 0 {
2✔
2059
                                        subnetMap = map[string]bool{
1✔
2060
                                                "0.0.0.0/0": true,
1✔
2061
                                        }
1✔
2062
                                }
1✔
2063
                                for idx := range egress.Ports {
2✔
2064
                                        port := egress.Ports[idx]
1✔
2065
                                        portkey := portKey(&port)
1✔
2066
                                        updatePortRemoteSubnets(portRemoteSubs, portkey, &port, subnetMap,
1✔
2067
                                                port.Port != nil && port.Port.Type == intstr.Int)
1✔
2068
                                }
1✔
2069
                                if len(egress.Ports) == 0 {
2✔
2070
                                        updatePortRemoteSubnets(portRemoteSubs, "", nil, subnetMap,
1✔
2071
                                                false)
1✔
2072
                                }
1✔
2073
                        }
2074
                        cont.buildServiceAugment(subjEgress, nil, portRemoteSubs, logger)
1✔
2075
                        hpp.AddChild(subjEgress)
1✔
2076
                }
2077
                if cont.config.HppOptimization {
2✔
2078
                        cont.addToHppCache(labelKey, key, apicapi.ApicSlice{hpp}, &hppv1.HostprotPol{})
1✔
2079
                }
1✔
2080
                cont.apicConn.WriteApicObjects(labelKey, apicapi.ApicSlice{hpp})
1✔
2081
        } else {
1✔
2082
                hash, err := util.CreateHashFromNetPol(np)
1✔
2083
                if err != nil {
1✔
2084
                        logger.Error("Could not create hash from network policy: ", err)
×
2085
                        return false
×
2086
                }
×
2087
                labelKey = cont.aciNameForKey("np", hash)
1✔
2088
                ns := os.Getenv("SYSTEM_NAMESPACE")
1✔
2089
                hppName := strings.ReplaceAll(labelKey, "_", "-")
1✔
2090
                hpp, err := cont.getHostprotPol(hppName, ns)
1✔
2091
                isUpdate := err == nil
1✔
2092

1✔
2093
                if err != nil && !errors.IsNotFound(err) {
1✔
2094
                        logger.Error("Error getting HPP CR: ", err)
×
2095
                        return false
×
2096
                }
×
2097

2098
                if isUpdate {
1✔
2099
                        logger.Debug("HPP CR already exists: ", hpp)
×
2100
                        if !slices.Contains(hpp.Spec.NetworkPolicies, key) {
×
2101
                                hpp.Spec.NetworkPolicies = append(hpp.Spec.NetworkPolicies, key)
×
2102
                        }
×
2103
                        hpp.Spec.HostprotSubj = nil
×
2104
                } else {
1✔
2105
                        hpp = &hppv1.HostprotPol{
1✔
2106
                                ObjectMeta: metav1.ObjectMeta{
1✔
2107
                                        Name:      hppName,
1✔
2108
                                        Namespace: ns,
1✔
2109
                                },
1✔
2110
                                Spec: hppv1.HostprotPolSpec{
1✔
2111
                                        Name:            labelKey,
1✔
2112
                                        NetworkPolicies: []string{key},
1✔
2113
                                        HostprotSubj:    nil,
1✔
2114
                                },
1✔
2115
                        }
1✔
2116
                }
1✔
2117

2118
                // Generate ingress policies
2119
                if np.Spec.PolicyTypes == nil || ptypeset[v1net.PolicyTypeIngress] {
2✔
2120
                        subjIngress := &hppv1.HostprotSubj{
1✔
2121
                                Name:         "networkpolicy-ingress",
1✔
2122
                                HostprotRule: []hppv1.HostprotRule{},
1✔
2123
                        }
1✔
2124

1✔
2125
                        for i, ingress := range np.Spec.Ingress {
2✔
2126
                                remoteSubnets, peerNsList, peerremote, _, _ := cont.getPeerRemoteSubnets(ingress.From,
1✔
2127
                                        np.Namespace, peerPods, peerNs, logger)
1✔
2128
                                if isAllowAllForAllNamespaces(ingress.From) {
1✔
2129
                                        peerNsList = append(peerNsList, "nodeips")
×
2130
                                }
×
2131
                                if !(len(ingress.From) > 0 && len(remoteSubnets) == 0) {
2✔
2132
                                        cont.buildLocalNetPolSubjRules(strconv.Itoa(i), subjIngress,
1✔
2133
                                                "ingress", peerNsList, peerremote.podSelector, ingress.Ports,
1✔
2134
                                                logger, key, np, nil)
1✔
2135
                                }
1✔
2136
                        }
2137
                        hpp.Spec.HostprotSubj = append(hpp.Spec.HostprotSubj, *subjIngress)
1✔
2138
                }
2139

2140
                if np.Spec.PolicyTypes == nil || ptypeset[v1net.PolicyTypeEgress] {
2✔
2141
                        subjEgress := &hppv1.HostprotSubj{
1✔
2142
                                Name:         "networkpolicy-egress",
1✔
2143
                                HostprotRule: []hppv1.HostprotRule{},
1✔
2144
                        }
1✔
2145

1✔
2146
                        portRemoteSubs := make(map[string]*portRemoteSubnet)
1✔
2147

1✔
2148
                        for i, egress := range np.Spec.Egress {
2✔
2149
                                remoteSubnets, peerNsList, peerremote, subnetMap, peerIpBlock := cont.getPeerRemoteSubnets(egress.To,
1✔
2150
                                        np.Namespace, peerPods, peerNs, logger)
1✔
2151
                                if isAllowAllForAllNamespaces(egress.To) {
1✔
2152
                                        peerNsList = append(peerNsList, "nodeips")
×
2153
                                }
×
2154
                                if !(len(egress.To) > 0 && len(remoteSubnets) == 0) {
2✔
2155
                                        cont.buildLocalNetPolSubjRules(strconv.Itoa(i), subjEgress,
1✔
2156
                                                "egress", peerNsList, peerremote.podSelector, egress.Ports, logger, key, np, peerIpBlock)
1✔
2157
                                }
1✔
2158

2159
                                if len(egress.To) == 0 {
2✔
2160
                                        subnetMap = map[string]bool{"0.0.0.0/0": true}
1✔
2161
                                }
1✔
2162
                                for idx := range egress.Ports {
2✔
2163
                                        port := egress.Ports[idx]
1✔
2164
                                        portkey := portKey(&port)
1✔
2165
                                        updatePortRemoteSubnets(portRemoteSubs, portkey, &port, subnetMap,
1✔
2166
                                                port.Port != nil && port.Port.Type == intstr.Int)
1✔
2167
                                }
1✔
2168
                                if len(egress.Ports) == 0 {
1✔
2169
                                        updatePortRemoteSubnets(portRemoteSubs, "", nil, subnetMap,
×
2170
                                                false)
×
2171
                                }
×
2172
                        }
2173
                        cont.buildServiceAugment(nil, subjEgress, portRemoteSubs, logger)
1✔
2174
                        hpp.Spec.HostprotSubj = append(hpp.Spec.HostprotSubj, *subjEgress)
1✔
2175
                }
2176

2177
                cont.addToHppCache(labelKey, key, apicapi.ApicSlice{}, hpp)
1✔
2178

1✔
2179
                if isUpdate {
1✔
2180
                        cont.updateHostprotPol(hpp, ns)
×
2181
                } else {
1✔
2182
                        cont.createHostprotPol(hpp, ns)
1✔
2183
                }
1✔
2184
        }
2185
        return false
1✔
2186
}
2187

2188
func (cont *AciController) updateNsRemoteIpCont(pod *v1.Pod, deleted bool) bool {
1✔
2189
        podips := ipsForPod(pod)
1✔
2190
        podns := pod.ObjectMeta.Namespace
1✔
2191
        podlabels := pod.ObjectMeta.Labels
1✔
2192
        remipcont, ok := cont.nsRemoteIpCont[podns]
1✔
2193

1✔
2194
        if deleted {
2✔
2195
                if !ok {
2✔
2196
                        return true
1✔
2197
                }
1✔
2198

2199
                present := false
1✔
2200
                for _, ip := range podips {
1✔
2201
                        if _, ipok := remipcont[ip]; ipok {
×
2202
                                delete(remipcont, ip)
×
2203
                                present = true
×
2204
                        }
×
2205
                }
2206

2207
                if len(remipcont) < 1 {
1✔
2208
                        delete(cont.nsRemoteIpCont, podns)
×
2209
                        cont.apicConn.ClearApicObjects(cont.aciNameForKey("hostprot-ns-", podns))
×
2210
                        return false
×
2211
                }
×
2212

2213
                if !present {
2✔
2214
                        return false
1✔
2215
                }
1✔
2216
        } else {
1✔
2217
                if !ok {
2✔
2218
                        remipcont = make(remoteIpCont)
1✔
2219
                        cont.nsRemoteIpCont[podns] = remipcont
1✔
2220
                }
1✔
2221

2222
                for _, ip := range podips {
2✔
2223
                        remipcont[ip] = podlabels
1✔
2224
                }
1✔
2225
        }
2226

2227
        return true
1✔
2228
}
2229

2230
func (cont *AciController) addToHppCache(labelKey, key string, hpp apicapi.ApicSlice, hppcr *hppv1.HostprotPol) {
1✔
2231
        cont.indexMutex.Lock()
1✔
2232
        hppRef, ok := cont.hppRef[labelKey]
1✔
2233
        if ok {
2✔
2234
                var found bool
1✔
2235
                for _, npkey := range hppRef.Npkeys {
2✔
2236
                        if npkey == key {
2✔
2237
                                found = true
1✔
2238
                                break
1✔
2239
                        }
2240
                }
2241
                if !found {
1✔
2242
                        hppRef.RefCount++
×
2243
                        hppRef.Npkeys = append(hppRef.Npkeys, key)
×
2244
                }
×
2245
                hppRef.HppObj = hpp
1✔
2246
                hppRef.HppCr = *hppcr
1✔
2247
                cont.hppRef[labelKey] = hppRef
1✔
2248
        } else {
1✔
2249
                var newHppRef hppReference
1✔
2250
                newHppRef.RefCount++
1✔
2251
                newHppRef.HppObj = hpp
1✔
2252
                newHppRef.HppCr = *hppcr
1✔
2253
                newHppRef.Npkeys = append(newHppRef.Npkeys, key)
1✔
2254
                cont.hppRef[labelKey] = newHppRef
1✔
2255
        }
1✔
2256
        cont.indexMutex.Unlock()
1✔
2257
}
2258

2259
func (cont *AciController) removeFromHppCache(np *v1net.NetworkPolicy, key string) (string, bool) {
1✔
2260
        var labelKey string
1✔
2261
        var noRef bool
1✔
2262
        hash, err := util.CreateHashFromNetPol(np)
1✔
2263
        if err != nil {
1✔
2264
                cont.log.Error("Could not create hash from network policy: ", err)
×
2265
                cont.log.Error("Failed to remove np from hpp cache")
×
2266
                return labelKey, noRef
×
2267
        }
×
2268
        labelKey = cont.aciNameForKey("np", hash)
1✔
2269
        cont.indexMutex.Lock()
1✔
2270
        hppRef, ok := cont.hppRef[labelKey]
1✔
2271
        if ok {
2✔
2272
                for i, npkey := range hppRef.Npkeys {
2✔
2273
                        if npkey == key {
2✔
2274
                                hppRef.Npkeys = append(hppRef.Npkeys[:i], hppRef.Npkeys[i+1:]...)
1✔
2275
                                hppRef.RefCount--
1✔
2276
                                break
1✔
2277
                        }
2278
                }
2279
                if hppRef.RefCount > 0 {
1✔
2280
                        cont.hppRef[labelKey] = hppRef
×
2281
                } else {
1✔
2282
                        delete(cont.hppRef, labelKey)
1✔
2283
                        noRef = true
1✔
2284
                }
1✔
2285
        }
2286
        cont.indexMutex.Unlock()
1✔
2287
        return labelKey, noRef
1✔
2288
}
2289

2290
func getNetworkPolicyEgressIpBlocks(np *v1net.NetworkPolicy) map[string]bool {
1✔
2291
        subnets := make(map[string]bool)
1✔
2292
        for _, egress := range np.Spec.Egress {
2✔
2293
                for _, to := range egress.To {
2✔
2294
                        if to.IPBlock != nil && to.IPBlock.CIDR != "" {
2✔
2295
                                subnets[to.IPBlock.CIDR] = true
1✔
2296
                        }
1✔
2297
                }
2298
        }
2299
        return subnets
1✔
2300
}
2301

2302
func (cont *AciController) networkPolicyAdded(obj interface{}) {
1✔
2303
        np := obj.(*v1net.NetworkPolicy)
1✔
2304
        npkey, err := cache.MetaNamespaceKeyFunc(np)
1✔
2305
        if err != nil {
1✔
2306
                networkPolicyLogger(cont.log, np).
×
2307
                        Error("Could not create network policy key: ", err)
×
2308
                return
×
2309
        }
×
2310
        if cont.config.ChainedMode {
1✔
2311
                return
×
2312
        }
×
2313
        cont.netPolPods.UpdateSelectorObj(obj)
1✔
2314
        cont.netPolIngressPods.UpdateSelectorObj(obj)
1✔
2315
        cont.netPolEgressPods.UpdateSelectorObj(obj)
1✔
2316
        cont.indexMutex.Lock()
1✔
2317
        subnets := getNetworkPolicyEgressIpBlocks(np)
1✔
2318
        cont.updateIpIndex(cont.netPolSubnetIndex, nil, subnets, npkey)
1✔
2319

1✔
2320
        ports := cont.getNetPolTargetPorts(np)
1✔
2321
        cont.updateTargetPortIndex(false, npkey, nil, ports)
1✔
2322
        if isNamedPortPresenInNp(np) {
2✔
2323
                cont.nmPortNp[npkey] = true
1✔
2324
        }
1✔
2325
        cont.indexMutex.Unlock()
1✔
2326
        cont.queueNetPolUpdateByKey(npkey)
1✔
2327
}
2328

2329
func (cont *AciController) networkPolicyChanged(oldobj interface{},
2330
        newobj interface{}) {
×
2331
        oldnp := oldobj.(*v1net.NetworkPolicy)
×
2332
        newnp := newobj.(*v1net.NetworkPolicy)
×
2333
        npkey, err := cache.MetaNamespaceKeyFunc(newnp)
×
2334
        if err != nil {
×
2335
                networkPolicyLogger(cont.log, newnp).
×
2336
                        Error("Could not create network policy key: ", err)
×
2337
                return
×
2338
        }
×
2339

2340
        if cont.config.HppOptimization || cont.config.EnableHppDirect {
×
2341
                if !reflect.DeepEqual(oldnp.Spec, newnp.Spec) {
×
2342
                        cont.removeFromHppCache(oldnp, npkey)
×
2343
                }
×
2344
        }
2345

2346
        cont.indexMutex.Lock()
×
2347
        oldSubnets := getNetworkPolicyEgressIpBlocks(oldnp)
×
2348
        newSubnets := getNetworkPolicyEgressIpBlocks(newnp)
×
2349
        cont.updateIpIndex(cont.netPolSubnetIndex, oldSubnets, newSubnets, npkey)
×
2350

×
2351
        oldPorts := cont.getNetPolTargetPorts(oldnp)
×
2352
        newPorts := cont.getNetPolTargetPorts(newnp)
×
2353
        cont.updateTargetPortIndex(false, npkey, oldPorts, newPorts)
×
2354
        cont.indexMutex.Unlock()
×
2355

×
2356
        if !reflect.DeepEqual(oldnp.Spec.PodSelector, newnp.Spec.PodSelector) {
×
2357
                cont.netPolPods.UpdateSelectorObjNoCallback(newobj)
×
2358
        }
×
2359
        if !reflect.DeepEqual(oldnp.Spec.PolicyTypes, newnp.Spec.PolicyTypes) {
×
2360
                peerPodKeys := cont.netPolPods.GetPodForObj(npkey)
×
2361
                for _, podkey := range peerPodKeys {
×
2362
                        cont.podQueue.Add(podkey)
×
2363
                }
×
2364
        }
2365
        var queue bool
×
2366
        if !reflect.DeepEqual(oldnp.Spec.Ingress, newnp.Spec.Ingress) {
×
2367
                cont.netPolIngressPods.UpdateSelectorObjNoCallback(newobj)
×
2368
                queue = true
×
2369
        }
×
2370
        if !reflect.DeepEqual(oldnp.Spec.Egress, newnp.Spec.Egress) {
×
2371
                cont.netPolEgressPods.UpdateSelectorObjNoCallback(newobj)
×
2372
                queue = true
×
2373
        }
×
2374
        if cont.config.EnableHppDirect {
×
2375
                cont.deleteHppCr(oldnp)
×
2376
        }
×
2377
        if queue {
×
2378
                cont.queueNetPolUpdateByKey(npkey)
×
2379
        }
×
2380
}
2381

2382
func (cont *AciController) networkPolicyDeleted(obj interface{}) {
1✔
2383
        np, isNetworkpolicy := obj.(*v1net.NetworkPolicy)
1✔
2384
        if !isNetworkpolicy {
1✔
2385
                deletedState, ok := obj.(cache.DeletedFinalStateUnknown)
×
2386
                if !ok {
×
2387
                        networkPolicyLogger(cont.log, np).
×
2388
                                Error("Received unexpected object: ", obj)
×
2389
                        return
×
2390
                }
×
2391
                np, ok = deletedState.Obj.(*v1net.NetworkPolicy)
×
2392
                if !ok {
×
2393
                        networkPolicyLogger(cont.log, np).
×
2394
                                Error("DeletedFinalStateUnknown contained non-Networkpolicy object: ", deletedState.Obj)
×
2395
                        return
×
2396
                }
×
2397
        }
2398
        npkey, err := cache.MetaNamespaceKeyFunc(np)
1✔
2399
        if err != nil {
1✔
2400
                networkPolicyLogger(cont.log, np).
×
2401
                        Error("Could not create network policy key: ", err)
×
2402
                return
×
2403
        }
×
2404

2405
        var labelKey string
1✔
2406
        var noHppRef bool
1✔
2407
        if cont.config.HppOptimization || cont.config.EnableHppDirect {
1✔
2408
                labelKey, noHppRef = cont.removeFromHppCache(np, npkey)
×
2409
        } else {
1✔
2410
                labelKey = cont.aciNameForKey("np", npkey)
1✔
2411
                noHppRef = true
1✔
2412
        }
1✔
2413

2414
        cont.indexMutex.Lock()
1✔
2415
        subnets := getNetworkPolicyEgressIpBlocks(np)
1✔
2416
        cont.updateIpIndex(cont.netPolSubnetIndex, subnets, nil, npkey)
1✔
2417

1✔
2418
        ports := cont.getNetPolTargetPorts(np)
1✔
2419
        cont.updateTargetPortIndex(false, npkey, ports, nil)
1✔
2420
        if isNamedPortPresenInNp(np) {
2✔
2421
                delete(cont.nmPortNp, npkey)
1✔
2422
        }
1✔
2423
        cont.indexMutex.Unlock()
1✔
2424

1✔
2425
        cont.netPolPods.DeleteSelectorObj(obj)
1✔
2426
        cont.netPolIngressPods.DeleteSelectorObj(obj)
1✔
2427
        cont.netPolEgressPods.DeleteSelectorObj(obj)
1✔
2428
        if noHppRef && labelKey != "" {
2✔
2429
                cont.apicConn.ClearApicObjects(labelKey)
1✔
2430
        }
1✔
2431
        if cont.config.EnableHppDirect {
1✔
2432
                cont.deleteHppCr(np)
×
2433
        }
×
2434
}
2435

2436
func (sep *serviceEndpoint) SetNpServiceAugmentForService(servicekey string, service *v1.Service, prs *portRemoteSubnet,
2437
        portAugments map[string]*portServiceAugment, subnetIndex cidranger.Ranger, logger *logrus.Entry) {
1✔
2438
        cont := sep.cont
1✔
2439
        endpointsobj, _, err := cont.endpointsIndexer.GetByKey(servicekey)
1✔
2440
        if err != nil {
1✔
2441
                logger.Error("Could not lookup endpoints for "+
×
2442
                        servicekey+": ", err.Error())
×
2443
                return
×
2444
        }
×
2445
        if endpointsobj == nil {
1✔
2446
                return
×
2447
        }
×
2448
        endpoints := endpointsobj.(*v1.Endpoints)
1✔
2449
        portstrings := make(map[string]bool)
1✔
2450
        ports := cont.getPortNums(prs.port)
1✔
2451
        for _, port := range ports {
2✔
2452
                portstrings[strconv.Itoa(port)] = true
1✔
2453
        }
1✔
2454
        for _, svcPort := range service.Spec.Ports {
2✔
2455
                _, ok := portstrings[svcPort.TargetPort.String()]
1✔
2456
                if prs.port != nil &&
1✔
2457
                        (svcPort.Protocol != *prs.port.Protocol || !ok) {
1✔
2458
                        // egress rule does not match service target port
×
2459
                        continue
×
2460
                }
2461
                for _, subset := range endpoints.Subsets {
2✔
2462
                        var foundEpPort *v1.EndpointPort
1✔
2463
                        for ix := range subset.Ports {
2✔
2464
                                if subset.Ports[ix].Name == svcPort.Name ||
1✔
2465
                                        (len(service.Spec.Ports) == 1 &&
1✔
2466
                                                subset.Ports[ix].Name == "") {
2✔
2467
                                        foundEpPort = &subset.Ports[ix]
1✔
2468
                                        break
1✔
2469
                                }
2470
                        }
2471
                        if foundEpPort == nil {
1✔
2472
                                continue
×
2473
                        }
2474

2475
                        incomplete := false
1✔
2476
                        incomplete = incomplete ||
1✔
2477
                                !checkEndpoints(subnetIndex, subset.Addresses)
1✔
2478
                        incomplete = incomplete || !checkEndpoints(subnetIndex,
1✔
2479
                                subset.NotReadyAddresses)
1✔
2480

1✔
2481
                        if incomplete {
2✔
2482
                                continue
1✔
2483
                        }
2484

2485
                        proto := portProto(&foundEpPort.Protocol)
1✔
2486
                        port := strconv.Itoa(int(svcPort.Port))
1✔
2487
                        updateServiceAugmentForService(portAugments,
1✔
2488
                                proto, port, service)
1✔
2489

1✔
2490
                        logger.WithFields(logrus.Fields{
1✔
2491
                                "proto":   proto,
1✔
2492
                                "port":    port,
1✔
2493
                                "service": servicekey,
1✔
2494
                        }).Debug("Allowing egress for service by subnet match")
1✔
2495
                }
2496
        }
2497
}
2498

2499
func (seps *serviceEndpointSlice) SetNpServiceAugmentForService(servicekey string, service *v1.Service,
2500
        prs *portRemoteSubnet, portAugments map[string]*portServiceAugment,
2501
        subnetIndex cidranger.Ranger, logger *logrus.Entry) {
1✔
2502
        cont := seps.cont
1✔
2503
        portstrings := make(map[string]bool)
1✔
2504
        ports := cont.getPortNums(prs.port)
1✔
2505
        for _, port := range ports {
2✔
2506
                portstrings[strconv.Itoa(port)] = true
1✔
2507
        }
1✔
2508
        label := map[string]string{discovery.LabelServiceName: service.ObjectMeta.Name}
1✔
2509
        selector := labels.SelectorFromSet(label)
1✔
2510
        cache.ListAllByNamespace(cont.endpointSliceIndexer, service.ObjectMeta.Namespace, selector,
1✔
2511
                func(endpointSliceobj interface{}) {
2✔
2512
                        endpointSlices := endpointSliceobj.(*discovery.EndpointSlice)
1✔
2513
                        for _, svcPort := range service.Spec.Ports {
2✔
2514
                                _, ok := portstrings[svcPort.TargetPort.String()]
1✔
2515
                                if prs.port != nil &&
1✔
2516
                                        (svcPort.Protocol != *prs.port.Protocol || !ok) {
1✔
2517
                                        // egress rule does not match service target port
×
2518
                                        continue
×
2519
                                }
2520
                                var foundEpPort *discovery.EndpointPort
1✔
2521
                                for ix := range endpointSlices.Ports {
2✔
2522
                                        if *endpointSlices.Ports[ix].Name == svcPort.Name ||
1✔
2523
                                                (len(service.Spec.Ports) == 1 &&
1✔
2524
                                                        *endpointSlices.Ports[ix].Name == "") {
2✔
2525
                                                foundEpPort = &endpointSlices.Ports[ix]
1✔
2526
                                                cont.log.Debug("Found EpPort: ", foundEpPort)
1✔
2527
                                                break
1✔
2528
                                        }
2529
                                }
2530
                                if foundEpPort == nil {
1✔
2531
                                        return
×
2532
                                }
×
2533
                                // @FIXME for non ready address
2534
                                incomplete := false
1✔
2535
                                for _, endpoint := range endpointSlices.Endpoints {
2✔
2536
                                        incomplete = incomplete || !checkEndpointslices(subnetIndex, endpoint.Addresses)
1✔
2537
                                }
1✔
2538
                                if incomplete {
2✔
2539
                                        continue
1✔
2540
                                }
2541
                                proto := portProto(foundEpPort.Protocol)
1✔
2542
                                port := strconv.Itoa(int(svcPort.Port))
1✔
2543
                                cont.log.Debug("updateServiceAugmentForService: ", service)
1✔
2544
                                updateServiceAugmentForService(portAugments,
1✔
2545
                                        proto, port, service)
1✔
2546

1✔
2547
                                logger.WithFields(logrus.Fields{
1✔
2548
                                        "proto":   proto,
1✔
2549
                                        "port":    port,
1✔
2550
                                        "service": servicekey,
1✔
2551
                                }).Debug("Allowing egress for service by subnet match")
1✔
2552
                        }
2553
                })
2554
}
2555

2556
func isNamedPortPresenInNp(np *v1net.NetworkPolicy) bool {
1✔
2557
        for _, egress := range np.Spec.Egress {
2✔
2558
                for _, p := range egress.Ports {
2✔
2559
                        if p.Port.Type == intstr.String {
2✔
2560
                                return true
1✔
2561
                        }
1✔
2562
                }
2563
        }
2564
        return false
1✔
2565
}
2566

2567
func (cont *AciController) checkPodNmpMatchesNp(npkey, podkey string) bool {
1✔
2568
        podobj, exists, err := cont.podIndexer.GetByKey(podkey)
1✔
2569
        if err != nil {
1✔
2570
                return false
×
2571
        }
×
2572
        if !exists || podobj == nil {
1✔
2573
                return false
×
2574
        }
×
2575
        pod := podobj.(*v1.Pod)
1✔
2576
        npobj, npexists, nperr := cont.networkPolicyIndexer.GetByKey(npkey)
1✔
2577
        if npexists && nperr == nil && npobj != nil {
2✔
2578
                np := npobj.(*v1net.NetworkPolicy)
1✔
2579
                for _, egress := range np.Spec.Egress {
2✔
2580
                        for _, p := range egress.Ports {
2✔
2581
                                if p.Port.Type == intstr.String {
2✔
2582
                                        _, err := k8util.LookupContainerPortNumberByName(*pod, p.Port.String())
1✔
2583
                                        if err == nil {
2✔
2584
                                                return true
1✔
2585
                                        }
1✔
2586
                                }
2587
                        }
2588
                }
2589
        }
2590
        return false
1✔
2591
}
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