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

kubeovn / kube-ovn / 18554291225

16 Oct 2025 07:53AM UTC coverage: 21.145% (+0.06%) from 21.087%
18554291225

push

github

web-flow
feat(netpol): authorize l3 protocols (#5745)

* feat(netpol): authorize l3 protocols

Signed-off-by: SkalaNetworks <contact@skala.network>

* feat(netpol): add annotation for different policy enforcements

Signed-off-by: SkalaNetworks <contact@skala.network>

* feat(netpols): add enforcement configuration and deployment config

Signed-off-by: SkalaNetworks <contact@skala.network>

* chore(netpol): add unit tests

Signed-off-by: SkalaNetworks <contact@skala.network>

* feat(netpol): only block tcp/udp/sctp in lax enforcement

Signed-off-by: SkalaNetworks <contact@skala.network>

---------

Signed-off-by: SkalaNetworks <contact@skala.network>

57 of 94 new or added lines in 3 files covered. (60.64%)

2 existing lines in 1 file now uncovered.

10729 of 50740 relevant lines covered (21.15%)

0.25 hits per line

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

0.0
/pkg/controller/network_policy.go
1
package controller
2

3
import (
4
        "fmt"
5
        "maps"
6
        "reflect"
7
        "slices"
8
        "strconv"
9
        "strings"
10
        "unicode"
11

12
        "github.com/scylladb/go-set/strset"
13
        corev1 "k8s.io/api/core/v1"
14
        netv1 "k8s.io/api/networking/v1"
15
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
16
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
17
        "k8s.io/apimachinery/pkg/labels"
18
        utilruntime "k8s.io/apimachinery/pkg/util/runtime"
19
        "k8s.io/client-go/tools/cache"
20
        "k8s.io/klog/v2"
21
        "k8s.io/utils/set"
22

23
        kubeovnv1 "github.com/kubeovn/kube-ovn/pkg/apis/kubeovn/v1"
24
        "github.com/kubeovn/kube-ovn/pkg/ovs"
25
        "github.com/kubeovn/kube-ovn/pkg/ovsdb/ovnnb"
26
        "github.com/kubeovn/kube-ovn/pkg/util"
27
)
28

29
const (
30
        NetworkPolicyEnforcementStandard = "standard"
31
        NetworkPolicyEnforcementLax      = "lax"
32
)
33

34
func (c *Controller) enqueueAddNp(obj any) {
×
35
        key := cache.MetaObjectToName(obj.(*netv1.NetworkPolicy)).String()
×
36
        klog.V(3).Infof("enqueue add network policy %s", key)
×
37
        c.updateNpQueue.Add(key)
×
38
}
×
39

40
func (c *Controller) enqueueDeleteNp(obj any) {
×
41
        var np *netv1.NetworkPolicy
×
42
        switch t := obj.(type) {
×
43
        case *netv1.NetworkPolicy:
×
44
                np = t
×
45
        case cache.DeletedFinalStateUnknown:
×
46
                n, ok := t.Obj.(*netv1.NetworkPolicy)
×
47
                if !ok {
×
48
                        klog.Warningf("unexpected object type: %T", t.Obj)
×
49
                        return
×
50
                }
×
51
                np = n
×
52
        default:
×
53
                klog.Warningf("unexpected type: %T", obj)
×
54
                return
×
55
        }
56

57
        key := cache.MetaObjectToName(np).String()
×
58
        klog.V(3).Infof("enqueue delete network policy %s", key)
×
59
        c.deleteNpQueue.Add(key)
×
60
}
61

62
func (c *Controller) enqueueUpdateNp(oldObj, newObj any) {
×
63
        oldNp := oldObj.(*netv1.NetworkPolicy)
×
64
        newNp := newObj.(*netv1.NetworkPolicy)
×
65
        if !reflect.DeepEqual(oldNp.Spec, newNp.Spec) ||
×
66
                !maps.Equal(oldNp.Annotations, newNp.Annotations) {
×
67
                key := cache.MetaObjectToName(newNp).String()
×
68
                klog.V(3).Infof("enqueue update np %s", key)
×
69
                c.updateNpQueue.Add(key)
×
70
        }
×
71
}
72

73
func (c *Controller) createAsForNetpol(ns, name, direction, asName string, addresses []string) error {
×
74
        if err := c.OVNNbClient.CreateAddressSet(asName, map[string]string{
×
75
                networkPolicyKey: fmt.Sprintf("%s/%s/%s", ns, name, direction),
×
76
        }); err != nil {
×
77
                klog.Errorf("failed to create ovn address set %s for np %s/%s: %v", asName, ns, name, err)
×
78
                return err
×
79
        }
×
80

81
        if err := c.OVNNbClient.AddressSetUpdateAddress(asName, addresses...); err != nil {
×
82
                klog.Errorf("failed to set addresses %q to address set %s: %v", strings.Join(addresses, ","), asName, err)
×
83
                return err
×
84
        }
×
85

86
        return nil
×
87
}
88

89
func (c *Controller) handleUpdateNp(key string) error {
×
90
        namespace, name, err := cache.SplitMetaNamespaceKey(key)
×
91
        if err != nil {
×
92
                utilruntime.HandleError(fmt.Errorf("invalid resource key: %s", key))
×
93
                return nil
×
94
        }
×
95

96
        c.npKeyMutex.LockKey(key)
×
97
        defer func() { _ = c.npKeyMutex.UnlockKey(key) }()
×
98
        klog.Infof("handle add/update network policy %s", key)
×
99

×
100
        np, err := c.npsLister.NetworkPolicies(namespace).Get(name)
×
101
        if err != nil {
×
102
                if k8serrors.IsNotFound(err) {
×
103
                        return nil
×
104
                }
×
105
                klog.Error(err)
×
106
                return err
×
107
        }
108

109
        defer func() {
×
110
                if err != nil {
×
111
                        c.recorder.Eventf(np, corev1.EventTypeWarning, "CreateACLFailed", err.Error())
×
112
                }
×
113
        }()
114

115
        logEnable := np.Annotations[util.NetworkPolicyLogAnnotation] == "true"
×
116

×
117
        var logActions []string
×
118
        if np.Annotations[util.ACLActionsLogAnnotation] != "" {
×
119
                logActions = strings.Split(np.Annotations[util.ACLActionsLogAnnotation], ",")
×
120
        } else {
×
121
                logActions = []string{ovnnb.ACLActionDrop}
×
122
        }
×
123

124
        npName := np.Name
×
125
        nameArray := []rune(np.Name)
×
126
        if !unicode.IsLetter(nameArray[0]) {
×
127
                npName = "np" + np.Name
×
128
        }
×
129

130
        // TODO: ovn acl doesn't support address_set name with '-', now we replace '-' by '.'.
131
        // This may cause conflict if two np with name test-np and test.np. Maybe hash is a better solution,
132
        // but we do not want to lost the readability now.
133
        pgName := strings.ReplaceAll(fmt.Sprintf("%s.%s", npName, np.Namespace), "-", ".")
×
134
        ingressAllowAsNamePrefix := strings.ReplaceAll(fmt.Sprintf("%s.%s.ingress.allow", npName, np.Namespace), "-", ".")
×
135
        ingressExceptAsNamePrefix := strings.ReplaceAll(fmt.Sprintf("%s.%s.ingress.except", npName, np.Namespace), "-", ".")
×
136
        egressAllowAsNamePrefix := strings.ReplaceAll(fmt.Sprintf("%s.%s.egress.allow", npName, np.Namespace), "-", ".")
×
137
        egressExceptAsNamePrefix := strings.ReplaceAll(fmt.Sprintf("%s.%s.egress.except", npName, np.Namespace), "-", ".")
×
138

×
139
        if err = c.OVNNbClient.CreatePortGroup(pgName, map[string]string{networkPolicyKey: np.Namespace + "/" + npName}); err != nil {
×
140
                klog.Errorf("create port group for np %s: %v", key, err)
×
141
                return err
×
142
        }
×
143

144
        namedPortMap := c.namedPort.GetNamedPortByNs(np.Namespace)
×
145
        ports, subnetNames, err := c.fetchSelectedPorts(np.Namespace, &np.Spec.PodSelector)
×
146
        if err != nil {
×
147
                klog.Errorf("fetch ports belongs to np %s: %v", key, err)
×
148
                return err
×
149
        }
×
150

151
        var subnets []*kubeovnv1.Subnet
×
152
        protocolSet := strset.NewWithSize(2)
×
153
        for _, subnetName := range subnetNames {
×
154
                subnet, err := c.subnetsLister.Get(subnetName)
×
155
                if err != nil {
×
156
                        klog.Errorf("failed to get pod's subnet %s, %v", subnetName, err)
×
157
                        return err
×
158
                }
×
159
                subnets = append(subnets, subnet)
×
160

×
161
                if subnet.Spec.Protocol == kubeovnv1.ProtocolDual {
×
162
                        protocolSet.Add(kubeovnv1.ProtocolIPv4, kubeovnv1.ProtocolIPv6)
×
163
                } else {
×
164
                        protocolSet.Add(subnet.Spec.Protocol)
×
165
                }
×
166
        }
167
        klog.Infof("UpdateNp, related subnets protocols %s", protocolSet.String())
×
168

×
169
        if err = c.OVNNbClient.PortGroupSetPorts(pgName, ports); err != nil {
×
170
                klog.Errorf("failed to set ports of port group %s to %v: %v", pgName, ports, err)
×
171
                return err
×
172
        }
×
173

174
        ingressACLOps, err := c.OVNNbClient.DeleteAclsOps(pgName, portGroupKey, "to-lport", nil)
×
175
        if err != nil {
×
176
                klog.Errorf("generate operations that clear np %s ingress acls: %v", key, err)
×
177
                return err
×
178
        }
×
179

180
        if hasIngressRule(np) {
×
181
                if protocolSet.Size() > 0 {
×
NEW
182
                        enforcementLax := c.isNetworkPolicyEnforcementLax(np)
×
NEW
183

×
NEW
184
                        blockACLOps, err := c.OVNNbClient.UpdateDefaultBlockACLOps(key, pgName, ovnnb.ACLDirectionToLport, logEnable, enforcementLax)
×
185
                        if err != nil {
×
186
                                klog.Errorf("failed to set default ingress block acl: %v", err)
×
187
                                return fmt.Errorf("failed to set default ingress block acl: %w", err)
×
188
                        }
×
189
                        ingressACLOps = append(ingressACLOps, blockACLOps...)
×
NEW
190

×
NEW
191
                        if enforcementLax {
×
NEW
192
                                defaultBlockExceptions, err := c.OVNNbClient.UpdateDefaultBlockExceptionsACLOps(key, pgName, np.Namespace, ovnnb.ACLDirectionToLport)
×
NEW
193
                                if err != nil {
×
NEW
194
                                        klog.Errorf("failed to set default block exceptions for ingress acl: %v", err)
×
NEW
195
                                        return fmt.Errorf("failed to set default block exceptions for ingress acl: %w", err)
×
NEW
196
                                }
×
NEW
197
                                ingressACLOps = append(ingressACLOps, defaultBlockExceptions...)
×
198
                        }
199
                }
200

201
                for _, protocol := range protocolSet.List() {
×
202
                        for idx, npr := range np.Spec.Ingress {
×
203
                                // A single address set must contain addresses of the same type and the name must be unique within table, so IPv4 and IPv6 address set should be different
×
204
                                ingressAllowAsName := fmt.Sprintf("%s.%s.%d", ingressAllowAsNamePrefix, protocol, idx)
×
205
                                ingressExceptAsName := fmt.Sprintf("%s.%s.%d", ingressExceptAsNamePrefix, protocol, idx)
×
206
                                aclName := fmt.Sprintf("np/%s.%s/ingress/%s/%d", npName, np.Namespace, protocol, idx)
×
207

×
208
                                var allows, excepts []string
×
209
                                if len(npr.From) == 0 {
×
210
                                        if protocol == kubeovnv1.ProtocolIPv4 {
×
211
                                                allows = []string{"0.0.0.0/0"}
×
212
                                        } else {
×
213
                                                allows = []string{"::/0"}
×
214
                                        }
×
215
                                } else {
×
216
                                        var allow, except []string
×
217
                                        for _, npp := range npr.From {
×
218
                                                if allow, except, err = c.fetchPolicySelectedAddresses(np.Namespace, protocol, npp); err != nil {
×
219
                                                        klog.Errorf("failed to fetch policy selected addresses, %v", err)
×
220
                                                        return err
×
221
                                                }
×
222
                                                allows = append(allows, allow...)
×
223
                                                excepts = append(excepts, except...)
×
224
                                        }
225
                                }
226
                                klog.Infof("UpdateNp Ingress, allows is %v, excepts is %v, log %v, protocol %v", allows, excepts, logEnable, protocol)
×
227

×
228
                                if err = c.createAsForNetpol(np.Namespace, npName, "ingress", ingressAllowAsName, allows); err != nil {
×
229
                                        klog.Error(err)
×
230
                                        return err
×
231
                                }
×
232
                                if err = c.createAsForNetpol(np.Namespace, npName, "ingress", ingressExceptAsName, excepts); err != nil {
×
233
                                        klog.Error(err)
×
234
                                        return err
×
235
                                }
×
236

237
                                npp := []netv1.NetworkPolicyPort{}
×
238
                                if len(allows) != 0 || len(excepts) != 0 {
×
239
                                        npp = npr.Ports
×
240
                                }
×
241

242
                                ops, err := c.OVNNbClient.UpdateIngressACLOps(pgName, ingressAllowAsName, ingressExceptAsName, protocol, aclName, npp, logEnable, logActions, namedPortMap)
×
243
                                if err != nil {
×
244
                                        klog.Errorf("generate operations that add ingress acls to np %s: %v", key, err)
×
245
                                        return err
×
246
                                }
×
247

248
                                ingressACLOps = append(ingressACLOps, ops...)
×
249
                        }
250
                        if len(np.Spec.Ingress) == 0 {
×
251
                                ingressAllowAsName := fmt.Sprintf("%s.%s.all", ingressAllowAsNamePrefix, protocol)
×
252
                                ingressExceptAsName := fmt.Sprintf("%s.%s.all", ingressExceptAsNamePrefix, protocol)
×
253
                                aclName := fmt.Sprintf("np/%s.%s/ingress/%s/all", npName, np.Namespace, protocol)
×
254

×
255
                                if err = c.createAsForNetpol(np.Namespace, npName, "ingress", ingressAllowAsName, nil); err != nil {
×
256
                                        klog.Error(err)
×
257
                                        return err
×
258
                                }
×
259
                                if err = c.createAsForNetpol(np.Namespace, npName, "ingress", ingressExceptAsName, nil); err != nil {
×
260
                                        klog.Error(err)
×
261
                                        return err
×
262
                                }
×
263

264
                                ops, err := c.OVNNbClient.UpdateIngressACLOps(pgName, ingressAllowAsName, ingressExceptAsName, protocol, aclName, nil, logEnable, logActions, namedPortMap)
×
265
                                if err != nil {
×
266
                                        klog.Errorf("generate operations that add ingress acls to np %s: %v", key, err)
×
267
                                        return err
×
268
                                }
×
269

270
                                ingressACLOps = append(ingressACLOps, ops...)
×
271
                        }
272
                }
273

274
                if err := c.OVNNbClient.Transact("add-ingress-acls", ingressACLOps); err != nil {
×
275
                        return fmt.Errorf("add ingress acls to %s: %w", pgName, err)
×
276
                }
×
277

278
                if err := c.OVNNbClient.SetACLLog(pgName, logEnable, true); err != nil {
×
279
                        // just log and do not return err here
×
280
                        klog.Errorf("failed to set ingress acl log for np %s, %v", key, err)
×
281
                }
×
282

283
                ass, err := c.OVNNbClient.ListAddressSets(map[string]string{
×
284
                        networkPolicyKey: fmt.Sprintf("%s/%s/%s", np.Namespace, npName, "ingress"),
×
285
                })
×
286
                if err != nil {
×
287
                        klog.Errorf("list np %s address sets: %v", key, err)
×
288
                        return err
×
289
                }
×
290

291
                // The format of asName is like "test.network.policy.test.ingress.except.0" or "test.network.policy.test.ingress.allow.0" for ingress
292
                for _, as := range ass {
×
293
                        values := strings.Split(as.Name, ".")
×
294
                        if len(values) <= 1 {
×
295
                                continue
×
296
                        }
297
                        idxStr := values[len(values)-1]
×
298
                        if idxStr == "all" {
×
299
                                continue
×
300
                        }
301
                        idx, _ := strconv.Atoi(idxStr)
×
302
                        if idx >= len(np.Spec.Ingress) {
×
303
                                if err = c.OVNNbClient.DeleteAddressSet(as.Name); err != nil {
×
304
                                        klog.Errorf("failed to delete np %s address set, %v", key, err)
×
305
                                        return err
×
306
                                }
×
307
                        }
308
                }
309
        } else {
×
310
                if err = c.OVNNbClient.DeleteAcls(pgName, portGroupKey, "to-lport", nil); err != nil {
×
311
                        klog.Errorf("delete np %s ingress acls: %v", key, err)
×
312
                        return err
×
313
                }
×
314

315
                if err := c.OVNNbClient.DeleteAddressSets(map[string]string{
×
316
                        networkPolicyKey: fmt.Sprintf("%s/%s/%s", np.Namespace, npName, "ingress"),
×
317
                }); err != nil {
×
318
                        klog.Errorf("delete np %s ingress address set: %v", key, err)
×
319
                        return err
×
320
                }
×
321
        }
322

323
        egressACLOps, err := c.OVNNbClient.DeleteAclsOps(pgName, portGroupKey, "from-lport", nil)
×
324
        if err != nil {
×
325
                klog.Errorf("generate operations that clear np %s egress acls: %v", key, err)
×
326
                return err
×
327
        }
×
328

329
        if hasEgressRule(np) {
×
330
                if protocolSet.Size() > 0 {
×
NEW
331
                        enforcementLax := c.isNetworkPolicyEnforcementLax(np)
×
NEW
332

×
NEW
333
                        blockACLOps, err := c.OVNNbClient.UpdateDefaultBlockACLOps(key, pgName, ovnnb.ACLDirectionFromLport, logEnable, enforcementLax)
×
334
                        if err != nil {
×
335
                                klog.Errorf("failed to set default egress block acl: %v", err)
×
336
                                return fmt.Errorf("failed to set default egress block acl: %w", err)
×
337
                        }
×
338
                        egressACLOps = append(egressACLOps, blockACLOps...)
×
NEW
339

×
NEW
340
                        if enforcementLax {
×
NEW
341
                                defaultBlockExceptions, err := c.OVNNbClient.UpdateDefaultBlockExceptionsACLOps(key, pgName, np.Namespace, ovnnb.ACLDirectionFromLport)
×
NEW
342
                                if err != nil {
×
NEW
343
                                        klog.Errorf("failed to set default block exceptions for ingress acl: %v", err)
×
NEW
344
                                        return fmt.Errorf("failed to set default block exceptions for ingress acl: %w", err)
×
NEW
345
                                }
×
NEW
346
                                egressACLOps = append(egressACLOps, defaultBlockExceptions...)
×
347
                        }
348
                }
349

350
                for _, protocol := range protocolSet.List() {
×
351
                        for idx, npr := range np.Spec.Egress {
×
352
                                // A single address set must contain addresses of the same type and the name must be unique within table, so IPv4 and IPv6 address set should be different
×
353
                                egressAllowAsName := fmt.Sprintf("%s.%s.%d", egressAllowAsNamePrefix, protocol, idx)
×
354
                                egressExceptAsName := fmt.Sprintf("%s.%s.%d", egressExceptAsNamePrefix, protocol, idx)
×
355
                                aclName := fmt.Sprintf("np/%s.%s/egress/%s/%d", npName, np.Namespace, protocol, idx)
×
356

×
357
                                var allows, excepts []string
×
358
                                if len(npr.To) == 0 {
×
359
                                        if protocol == kubeovnv1.ProtocolIPv4 {
×
360
                                                allows = []string{"0.0.0.0/0"}
×
361
                                        } else {
×
362
                                                allows = []string{"::/0"}
×
363
                                        }
×
364
                                } else {
×
365
                                        var allow, except []string
×
366
                                        for _, npp := range npr.To {
×
367
                                                if allow, except, err = c.fetchPolicySelectedAddresses(np.Namespace, protocol, npp); err != nil {
×
368
                                                        klog.Errorf("failed to fetch policy selected addresses, %v", err)
×
369
                                                        return err
×
370
                                                }
×
371
                                                allows = append(allows, allow...)
×
372
                                                excepts = append(excepts, except...)
×
373
                                        }
374
                                }
375
                                klog.Infof("UpdateNp Egress %s, allows is %v, excepts is %v, log %v", aclName, allows, excepts, logEnable)
×
376

×
377
                                if err = c.createAsForNetpol(np.Namespace, npName, "egress", egressAllowAsName, allows); err != nil {
×
378
                                        klog.Error(err)
×
379
                                        return err
×
380
                                }
×
381
                                if err = c.createAsForNetpol(np.Namespace, npName, "egress", egressExceptAsName, excepts); err != nil {
×
382
                                        klog.Error(err)
×
383
                                        return err
×
384
                                }
×
385

386
                                npp := []netv1.NetworkPolicyPort{}
×
387
                                if len(allows) != 0 || len(excepts) != 0 {
×
388
                                        npp = npr.Ports
×
389
                                }
×
390

391
                                ops, err := c.OVNNbClient.UpdateEgressACLOps(pgName, egressAllowAsName, egressExceptAsName, protocol, aclName, npp, logEnable, logActions, namedPortMap)
×
392
                                if err != nil {
×
393
                                        klog.Errorf("generate operations that add egress acls to np %s: %v", key, err)
×
394
                                        return err
×
395
                                }
×
396

397
                                egressACLOps = append(egressACLOps, ops...)
×
398
                        }
399
                        if len(np.Spec.Egress) == 0 {
×
400
                                egressAllowAsName := fmt.Sprintf("%s.%s.all", egressAllowAsNamePrefix, protocol)
×
401
                                egressExceptAsName := fmt.Sprintf("%s.%s.all", egressExceptAsNamePrefix, protocol)
×
402
                                aclName := fmt.Sprintf("np/%s.%s/egress/%s/all", npName, np.Namespace, protocol)
×
403

×
404
                                if err = c.createAsForNetpol(np.Namespace, npName, "egress", egressAllowAsName, nil); err != nil {
×
405
                                        klog.Error(err)
×
406
                                        return err
×
407
                                }
×
408
                                if err = c.createAsForNetpol(np.Namespace, npName, "egress", egressExceptAsName, nil); err != nil {
×
409
                                        klog.Error(err)
×
410
                                        return err
×
411
                                }
×
412

413
                                ops, err := c.OVNNbClient.UpdateEgressACLOps(pgName, egressAllowAsName, egressExceptAsName, protocol, aclName, nil, logEnable, logActions, namedPortMap)
×
414
                                if err != nil {
×
415
                                        klog.Errorf("generate operations that add egress acls to np %s: %v", key, err)
×
416
                                        return err
×
417
                                }
×
418

419
                                egressACLOps = append(egressACLOps, ops...)
×
420
                        }
421
                }
422

423
                if err := c.OVNNbClient.Transact("add-egress-acls", egressACLOps); err != nil {
×
424
                        return fmt.Errorf("add egress acls to %s: %w", pgName, err)
×
425
                }
×
426

427
                if err := c.OVNNbClient.SetACLLog(pgName, logEnable, false); err != nil {
×
428
                        // just log and do not return err here
×
429
                        klog.Errorf("failed to set egress acl log for np %s, %v", key, err)
×
430
                }
×
431

432
                ass, err := c.OVNNbClient.ListAddressSets(map[string]string{
×
433
                        networkPolicyKey: fmt.Sprintf("%s/%s/%s", np.Namespace, npName, "egress"),
×
434
                })
×
435
                if err != nil {
×
436
                        klog.Errorf("list np %s address sets: %v", key, err)
×
437
                        return err
×
438
                }
×
439

440
                // The format of asName is like "test.network.policy.test.egress.except.0" or "test.network.policy.test.egress.allow.0" for egress
441
                for _, as := range ass {
×
442
                        values := strings.Split(as.Name, ".")
×
443
                        if len(values) <= 1 {
×
444
                                continue
×
445
                        }
446
                        idxStr := values[len(values)-1]
×
447
                        if idxStr == "all" {
×
448
                                continue
×
449
                        }
450

451
                        idx, _ := strconv.Atoi(idxStr)
×
452
                        if idx >= len(np.Spec.Egress) {
×
453
                                if err = c.OVNNbClient.DeleteAddressSet(as.Name); err != nil {
×
454
                                        klog.Errorf("delete np %s address set: %v", key, err)
×
455
                                        return err
×
456
                                }
×
457
                        }
458
                }
459
        } else {
×
460
                if err = c.OVNNbClient.DeleteAcls(pgName, portGroupKey, "from-lport", nil); err != nil {
×
461
                        klog.Errorf("delete np %s egress acls: %v", key, err)
×
462
                        return err
×
463
                }
×
464

465
                if err := c.OVNNbClient.DeleteAddressSets(map[string]string{
×
466
                        networkPolicyKey: fmt.Sprintf("%s/%s/%s", np.Namespace, npName, "egress"),
×
467
                }); err != nil {
×
468
                        klog.Errorf("delete np %s egress address set: %v", key, err)
×
469
                        return err
×
470
                }
×
471
        }
472

473
        for _, subnet := range subnets {
×
474
                if err = c.OVNNbClient.CreateGatewayACL("", pgName, subnet.Spec.Gateway, subnet.Status.U2OInterconnectionIP); err != nil {
×
475
                        klog.Errorf("create gateway acl: %v", err)
×
476
                        return err
×
477
                }
×
478
        }
479
        return nil
×
480
}
481

482
func (c *Controller) handleDeleteNp(key string) error {
×
483
        namespace, name, err := cache.SplitMetaNamespaceKey(key)
×
484
        if err != nil {
×
485
                utilruntime.HandleError(fmt.Errorf("invalid resource key: %s", key))
×
486
                return nil
×
487
        }
×
488

489
        c.npKeyMutex.LockKey(key)
×
490
        defer func() { _ = c.npKeyMutex.UnlockKey(key) }()
×
491
        klog.Infof("handle delete network policy %s", key)
×
492

×
493
        npName := name
×
494
        nameArray := []rune(name)
×
495
        if !unicode.IsLetter(nameArray[0]) {
×
496
                npName = "np" + name
×
497
        }
×
498

499
        pgName := strings.ReplaceAll(fmt.Sprintf("%s.%s", npName, namespace), "-", ".")
×
500
        if err = c.OVNNbClient.DeletePortGroup(pgName); err != nil {
×
501
                klog.Errorf("delete np %s port group: %v", key, err)
×
502
        }
×
503

504
        if err := c.OVNNbClient.DeleteAddressSets(map[string]string{
×
505
                networkPolicyKey: fmt.Sprintf("%s/%s/%s", namespace, npName, "service"),
×
506
        }); err != nil {
×
507
                klog.Errorf("delete np %s service address set: %v", key, err)
×
508
                return err
×
509
        }
×
510

511
        if err := c.OVNNbClient.DeleteAddressSets(map[string]string{
×
512
                networkPolicyKey: fmt.Sprintf("%s/%s/%s", namespace, npName, "ingress"),
×
513
        }); err != nil {
×
514
                klog.Errorf("delete np %s ingress address set: %v", key, err)
×
515
                return err
×
516
        }
×
517

518
        if err := c.OVNNbClient.DeleteAddressSets(map[string]string{
×
519
                networkPolicyKey: fmt.Sprintf("%s/%s/%s", namespace, npName, "egress"),
×
520
        }); err != nil {
×
521
                klog.Errorf("delete np %s egress address set: %v", key, err)
×
522
                return err
×
523
        }
×
524

525
        return nil
×
526
}
527

528
func (c *Controller) fetchSelectedPorts(namespace string, selector *metav1.LabelSelector) ([]string, []string, error) {
×
529
        var subnets []string
×
530
        sel, err := metav1.LabelSelectorAsSelector(selector)
×
531
        if err != nil {
×
532
                return nil, nil, fmt.Errorf("error creating label selector, %w", err)
×
533
        }
×
534
        pods, err := c.podsLister.Pods(namespace).List(sel)
×
535
        if err != nil {
×
536
                return nil, nil, fmt.Errorf("failed to list pods, %w", err)
×
537
        }
×
538

539
        ports := make([]string, 0, len(pods))
×
540
        for _, pod := range pods {
×
541
                if pod.Spec.HostNetwork {
×
542
                        continue
×
543
                }
544
                podName := c.getNameByPod(pod)
×
545
                podNets, err := c.getPodKubeovnNets(pod)
×
546
                if err != nil {
×
547
                        return nil, nil, fmt.Errorf("failed to get pod networks, %w", err)
×
548
                }
×
549

550
                for _, podNet := range podNets {
×
551
                        if !isOvnSubnet(podNet.Subnet) {
×
552
                                continue
×
553
                        }
554

555
                        if pod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, podNet.ProviderName)] == "true" {
×
556
                                ports = append(ports, ovs.PodNameToPortName(podName, pod.Namespace, podNet.ProviderName))
×
557
                                // Pod selected by networkpolicy has its own subnet which is not the default subnet
×
558
                                subnets = append(subnets, podNet.Subnet.Name)
×
559
                        }
×
560
                }
561
        }
562
        subnets = slices.Compact(subnets)
×
563
        return ports, subnets, nil
×
564
}
565

566
func hasIngressRule(np *netv1.NetworkPolicy) bool {
×
567
        for _, pt := range np.Spec.PolicyTypes {
×
568
                if strings.Contains(string(pt), string(netv1.PolicyTypeIngress)) {
×
569
                        return true
×
570
                }
×
571
        }
572
        return np.Spec.Ingress != nil
×
573
}
574

575
func hasEgressRule(np *netv1.NetworkPolicy) bool {
×
576
        for _, pt := range np.Spec.PolicyTypes {
×
577
                if strings.Contains(string(pt), string(netv1.PolicyTypeEgress)) {
×
578
                        return true
×
579
                }
×
580
        }
581
        return np.Spec.Egress != nil
×
582
}
583

584
func (c *Controller) fetchPolicySelectedAddresses(namespace, protocol string, npp netv1.NetworkPolicyPeer) ([]string, []string, error) {
×
585
        selectedAddresses := []string{}
×
586
        exceptAddresses := []string{}
×
587

×
588
        // ingress.from.ipblock or egress.to.ipblock
×
589
        if npp.IPBlock != nil && util.CheckProtocol(npp.IPBlock.CIDR) == protocol {
×
590
                selectedAddresses = append(selectedAddresses, npp.IPBlock.CIDR)
×
591
                if npp.IPBlock.Except != nil {
×
592
                        exceptAddresses = append(exceptAddresses, npp.IPBlock.Except...)
×
593
                }
×
594
        }
595
        if npp.NamespaceSelector == nil && npp.PodSelector == nil {
×
596
                return selectedAddresses, exceptAddresses, nil
×
597
        }
×
598

599
        selectedNs := []string{}
×
600
        if npp.NamespaceSelector == nil {
×
601
                selectedNs = append(selectedNs, namespace)
×
602
        } else {
×
603
                sel, err := metav1.LabelSelectorAsSelector(npp.NamespaceSelector)
×
604
                if err != nil {
×
605
                        return nil, nil, fmt.Errorf("error creating label selector, %w", err)
×
606
                }
×
607
                nss, err := c.namespacesLister.List(sel)
×
608
                if err != nil {
×
609
                        return nil, nil, fmt.Errorf("failed to list ns, %w", err)
×
610
                }
×
611
                for _, ns := range nss {
×
612
                        selectedNs = append(selectedNs, ns.Name)
×
613
                }
×
614
        }
615

616
        var sel labels.Selector
×
617
        if npp.PodSelector == nil {
×
618
                sel = labels.Everything()
×
619
        } else {
×
620
                sel, _ = metav1.LabelSelectorAsSelector(npp.PodSelector)
×
621
        }
×
622

623
        for _, ns := range selectedNs {
×
624
                pods, err := c.podsLister.Pods(ns).List(sel)
×
625
                if err != nil {
×
626
                        return nil, nil, fmt.Errorf("failed to list pod, %w", err)
×
627
                }
×
628
                svcs, err := c.servicesLister.Services(ns).List(labels.Everything())
×
629
                if err != nil {
×
630
                        klog.Errorf("failed to list svc, %v", err)
×
631
                        return nil, nil, fmt.Errorf("failed to list svc, %w", err)
×
632
                }
×
633

634
                for _, pod := range pods {
×
635
                        podNets, err := c.getPodKubeovnNets(pod)
×
636
                        if err != nil {
×
637
                                klog.Errorf("failed to get pod nets %v", err)
×
638
                                return nil, nil, err
×
639
                        }
×
640
                        for _, podNet := range podNets {
×
641
                                podIPAnnotation := pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, podNet.ProviderName)]
×
642
                                podIPs := strings.SplitSeq(podIPAnnotation, ",")
×
643
                                for podIP := range podIPs {
×
644
                                        if podIP != "" && util.CheckProtocol(podIP) == protocol {
×
645
                                                selectedAddresses = append(selectedAddresses, podIP)
×
646
                                        }
×
647
                                }
648
                                if len(svcs) == 0 {
×
649
                                        continue
×
650
                                }
651

652
                                svcIPs, err := svcMatchPods(svcs, pod, protocol)
×
653
                                if err != nil {
×
654
                                        return nil, nil, err
×
655
                                }
×
656
                                selectedAddresses = append(selectedAddresses, svcIPs...)
×
657
                        }
658
                }
659
        }
660
        return selectedAddresses, exceptAddresses, nil
×
661
}
662

663
func svcMatchPods(svcs []*corev1.Service, pod *corev1.Pod, protocol string) ([]string, error) {
×
664
        matchSvcs := []string{}
×
665
        // find svc ip by pod's info
×
666
        for _, svc := range svcs {
×
667
                if isSvcMatchPod(svc, pod) {
×
668
                        clusterIPs := util.ServiceClusterIPs(*svc)
×
669
                        protocolClusterIPs := getProtocolSvcIP(clusterIPs, protocol)
×
670
                        if len(protocolClusterIPs) != 0 {
×
671
                                matchSvcs = append(matchSvcs, protocolClusterIPs...)
×
672
                        }
×
673
                }
674
        }
675
        return matchSvcs, nil
×
676
}
677

678
func getProtocolSvcIP(clusterIPs []string, protocol string) []string {
×
679
        protocolClusterIPs := []string{}
×
680
        for _, clusterIP := range clusterIPs {
×
681
                if clusterIP != "" && clusterIP != corev1.ClusterIPNone && util.CheckProtocol(clusterIP) == protocol {
×
682
                        protocolClusterIPs = append(protocolClusterIPs, clusterIP)
×
683
                }
×
684
        }
685
        return protocolClusterIPs
×
686
}
687

688
func isSvcMatchPod(svc *corev1.Service, pod *corev1.Pod) bool {
×
689
        return labels.Set(svc.Spec.Selector).AsSelector().Matches(labels.Set(pod.Labels))
×
690
}
×
691

692
func (c *Controller) podMatchNetworkPolicies(pod *corev1.Pod) []string {
×
693
        podNs, err := c.namespacesLister.Get(pod.Namespace)
×
694
        if err != nil {
×
695
                klog.Errorf("failed to get namespace %s: %v", pod.Namespace, err)
×
696
                utilruntime.HandleError(err)
×
697
                return nil
×
698
        }
×
699

700
        nps, err := c.npsLister.NetworkPolicies(corev1.NamespaceAll).List(labels.Everything())
×
701
        if err != nil {
×
702
                klog.Errorf("failed to list network policies: %v", err)
×
703
                utilruntime.HandleError(err)
×
704
                return nil
×
705
        }
×
706

707
        match := []string{}
×
708
        for _, np := range nps {
×
709
                if isPodMatchNetworkPolicy(pod, podNs, np, np.Namespace) {
×
710
                        match = append(match, cache.MetaObjectToName(np).String())
×
711
                }
×
712
        }
713
        return match
×
714
}
715

716
func (c *Controller) svcMatchNetworkPolicies(svc *corev1.Service) ([]string, error) {
×
717
        // find all match pod
×
718
        sel := labels.Set(svc.Spec.Selector).AsSelector()
×
719
        pods, err := c.podsLister.Pods(svc.Namespace).List(sel)
×
720
        if err != nil {
×
721
                return nil, fmt.Errorf("failed to list pods, %w", err)
×
722
        }
×
723

724
        // find all match netpol
725
        nps, err := c.npsLister.NetworkPolicies(corev1.NamespaceAll).List(labels.Everything())
×
726
        if err != nil {
×
727
                return nil, fmt.Errorf("failed to list netpols, %w", err)
×
728
        }
×
729
        match := set.New[string]()
×
730
        ns, _ := c.namespacesLister.Get(svc.Namespace)
×
731
        for _, pod := range pods {
×
732
                for _, np := range nps {
×
733
                        key := cache.MetaObjectToName(np).String()
×
734
                        if match.Has(key) {
×
735
                                continue
×
736
                        }
737
                        if isPodMatchNetworkPolicy(pod, ns, np, np.Namespace) {
×
738
                                match.Insert(key)
×
739
                                klog.V(3).Infof("svc %s/%s match np %s", svc.Namespace, svc.Name, key)
×
740
                        }
×
741
                }
742
        }
743
        return match.UnsortedList(), nil
×
744
}
745

746
func isPodMatchNetworkPolicy(pod *corev1.Pod, podNs *corev1.Namespace, policy *netv1.NetworkPolicy, policyNs string) bool {
×
747
        sel, _ := metav1.LabelSelectorAsSelector(&policy.Spec.PodSelector)
×
748
        if podNs.Name == policyNs && sel.Matches(labels.Set(pod.Labels)) {
×
749
                return true
×
750
        }
×
751
        for _, npr := range policy.Spec.Ingress {
×
752
                for _, npp := range npr.From {
×
753
                        if isPodMatchPolicyPeer(pod, podNs, npp, policyNs) {
×
754
                                return true
×
755
                        }
×
756
                }
757
        }
758
        for _, npr := range policy.Spec.Egress {
×
759
                for _, npp := range npr.To {
×
760
                        if isPodMatchPolicyPeer(pod, podNs, npp, policyNs) {
×
761
                                return true
×
762
                        }
×
763
                }
764
        }
765
        return false
×
766
}
767

768
func isPodMatchPolicyPeer(pod *corev1.Pod, podNs *corev1.Namespace, policyPeer netv1.NetworkPolicyPeer, policyNs string) bool {
×
769
        if policyPeer.IPBlock != nil {
×
770
                return false
×
771
        }
×
772
        if policyPeer.NamespaceSelector == nil {
×
773
                if policyNs != podNs.Name {
×
774
                        return false
×
775
                }
×
776
        } else if !util.ObjectMatchesLabelSelector(podNs, policyPeer.NamespaceSelector) {
×
777
                return false
×
778
        }
×
779

780
        return policyPeer.PodSelector == nil || util.ObjectMatchesLabelSelector(pod, policyPeer.PodSelector)
×
781
}
782

783
func (c *Controller) namespaceMatchNetworkPolicies(ns *corev1.Namespace) []string {
×
784
        nps, _ := c.npsLister.NetworkPolicies(corev1.NamespaceAll).List(labels.Everything())
×
785
        match := make([]string, 0, len(nps))
×
786
        for _, np := range nps {
×
787
                if isNamespaceMatchNetworkPolicy(ns, np) {
×
788
                        match = append(match, cache.MetaObjectToName(np).String())
×
789
                }
×
790
        }
791
        return match
×
792
}
793

794
func isNamespaceMatchNetworkPolicy(ns *corev1.Namespace, policy *netv1.NetworkPolicy) bool {
×
795
        for _, npr := range policy.Spec.Ingress {
×
796
                for _, npp := range npr.From {
×
797
                        if npp.NamespaceSelector != nil {
×
798
                                nsSel, _ := metav1.LabelSelectorAsSelector(npp.NamespaceSelector)
×
799
                                if ns.Labels == nil {
×
800
                                        ns.Labels = map[string]string{}
×
801
                                }
×
802
                                if nsSel.Matches(labels.Set(ns.Labels)) {
×
803
                                        return true
×
804
                                }
×
805
                        }
806
                }
807
        }
808

809
        for _, npr := range policy.Spec.Egress {
×
810
                for _, npp := range npr.To {
×
811
                        if npp.NamespaceSelector != nil {
×
812
                                nsSel, _ := metav1.LabelSelectorAsSelector(npp.NamespaceSelector)
×
813
                                if ns.Labels == nil {
×
814
                                        ns.Labels = map[string]string{}
×
815
                                }
×
816
                                if nsSel.Matches(labels.Set(ns.Labels)) {
×
817
                                        return true
×
818
                                }
×
819
                        }
820
                }
821
        }
822
        return false
×
823
}
824

NEW
825
func (c *Controller) isNetworkPolicyEnforcementLax(policy *netv1.NetworkPolicy) bool {
×
NEW
826
        // User provided a custom enforcement through annotations
×
NEW
827
        if value, ok := policy.Annotations[util.NetworkPolicyEnforcementAnnotation]; ok {
×
NEW
828
                return value == NetworkPolicyEnforcementLax
×
NEW
829
        }
×
830

831
        // Fallback to the configuration of the controller
NEW
832
        return c.config.NetworkPolicyEnforcement == NetworkPolicyEnforcementLax
×
833
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc