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

kubeovn / kube-ovn / 15626264542

13 Jun 2025 04:11AM UTC coverage: 21.73% (-0.03%) from 21.755%
15626264542

Pull #5357

github

changluyi
fix duplicate acls because of parentkey

Signed-off-by: clyi <clyi@alauda.io>
Pull Request #5357: fix duplicate acls because of parentkey

0 of 69 new or added lines in 2 files covered. (0.0%)

7 existing lines in 1 file now uncovered.

10443 of 48057 relevant lines covered (21.73%)

0.25 hits per line

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

79.63
/pkg/ovs/ovn-nb-acl.go
1
package ovs
2

3
import (
4
        "context"
5
        "errors"
6
        "fmt"
7
        "slices"
8
        "strconv"
9
        "strings"
10

11
        "github.com/ovn-org/libovsdb/model"
12
        "github.com/ovn-org/libovsdb/ovsdb"
13
        netv1 "k8s.io/api/networking/v1"
14
        "k8s.io/apimachinery/pkg/util/intstr"
15
        "k8s.io/klog/v2"
16
        "k8s.io/utils/ptr"
17
        "k8s.io/utils/set"
18

19
        v1alpha1 "sigs.k8s.io/network-policy-api/apis/v1alpha1"
20

21
        kubeovnv1 "github.com/kubeovn/kube-ovn/pkg/apis/kubeovn/v1"
22
        ovsclient "github.com/kubeovn/kube-ovn/pkg/ovsdb/client"
23
        "github.com/kubeovn/kube-ovn/pkg/ovsdb/ovnnb"
24
        "github.com/kubeovn/kube-ovn/pkg/util"
25
)
26

27
func setACLName(acl *ovnnb.ACL, name string) {
1✔
28
        if len(name) > 63 {
1✔
29
                // ACL name length limit is 63
×
30
                name = name[:60] + "..."
×
31
        }
×
32
        acl.Name = ptr.To(name)
1✔
33
}
34

35
// UpdateIngressACLOps return operation that creates an ingress ACL
36
func (c *OVNNbClient) UpdateIngressACLOps(netpol, pgName, asIngressName, asExceptName, protocol, aclName string, npp []netv1.NetworkPolicyPort, logEnable bool, logACLActions []ovnnb.ACLAction, namedPortMap map[string]*util.NamedPortInfo) ([]ovsdb.Operation, error) {
1✔
37
        acls := make([]*ovnnb.ACL, 0)
1✔
38

1✔
39
        if strings.HasSuffix(asIngressName, ".0") || strings.HasSuffix(asIngressName, ".all") {
2✔
40
                // create the default drop rule for only once
1✔
41
                // both IPv4 and IPv6 traffic should be forbade in dual-stack situation
1✔
42
                allIPMatch := NewAndACLMatch(
1✔
43
                        NewACLMatch("outport", "==", "@"+pgName, ""),
1✔
44
                        NewACLMatch("ip", "", "", ""),
1✔
45
                )
1✔
46
                options := func(acl *ovnnb.ACL) {
2✔
47
                        setACLName(acl, netpol)
1✔
48
                        if logEnable {
2✔
49
                                acl.Log = true
1✔
50
                                acl.Severity = ptr.To(ovnnb.ACLSeverityWarning)
1✔
51
                        }
1✔
52
                }
53

54
                defaultDropACL, err := c.newACLWithoutCheck(pgName, ovnnb.ACLDirectionToLport, util.IngressDefaultDrop, allIPMatch.String(), ovnnb.ACLActionDrop, util.NetpolACLTier, options)
1✔
55
                if err != nil {
2✔
56
                        klog.Error(err)
1✔
57
                        return nil, fmt.Errorf("new default drop ingress acl for port group %s: %w", pgName, err)
1✔
58
                }
1✔
59

60
                acls = append(acls, defaultDropACL)
1✔
61
        }
62

63
        /* allow acl */
64
        matches := newNetworkPolicyACLMatch(pgName, asIngressName, asExceptName, protocol, ovnnb.ACLDirectionToLport, npp, namedPortMap)
1✔
65
        for _, m := range matches {
2✔
66
                options := func(acl *ovnnb.ACL) {
2✔
67
                        setACLName(acl, aclName)
1✔
68
                        if logEnable && slices.Contains(logACLActions, ovnnb.ACLActionAllow) {
1✔
69
                                acl.Log = true
×
70
                        }
×
71
                }
72

73
                allowACL, err := c.newACLWithoutCheck(pgName, ovnnb.ACLDirectionToLport, util.IngressAllowPriority, m, ovnnb.ACLActionAllowRelated, util.NetpolACLTier, options)
1✔
74
                if err != nil {
2✔
75
                        klog.Error(err)
1✔
76
                        return nil, fmt.Errorf("new allow ingress acl for port group %s: %w", pgName, err)
1✔
77
                }
1✔
78

79
                acls = append(acls, allowACL)
1✔
80
        }
81

82
        ops, err := c.CreateAclsOps(pgName, portGroupKey, acls...)
1✔
83
        if err != nil {
1✔
84
                klog.Error(err)
×
85
                return nil, fmt.Errorf("failed to create ingress acl for port group %s: %w", pgName, err)
×
86
        }
×
87

88
        return ops, nil
1✔
89
}
90

91
// UpdateEgressACLOps return operation that creates an egress ACL
92
func (c *OVNNbClient) UpdateEgressACLOps(netpol, pgName, asEgressName, asExceptName, protocol, aclName string, npp []netv1.NetworkPolicyPort, logEnable bool, logACLActions []ovnnb.ACLAction, namedPortMap map[string]*util.NamedPortInfo) ([]ovsdb.Operation, error) {
1✔
93
        acls := make([]*ovnnb.ACL, 0)
1✔
94

1✔
95
        if strings.HasSuffix(asEgressName, ".0") || strings.HasSuffix(asEgressName, ".all") {
2✔
96
                // create the default drop rule for only once
1✔
97
                // both IPv4 and IPv6 traffic should be forbade in dual-stack situation
1✔
98
                allIPMatch := NewAndACLMatch(
1✔
99
                        NewACLMatch("inport", "==", "@"+pgName, ""),
1✔
100
                        NewACLMatch("ip", "", "", ""),
1✔
101
                )
1✔
102
                options := func(acl *ovnnb.ACL) {
2✔
103
                        setACLName(acl, netpol)
1✔
104
                        if logEnable {
2✔
105
                                acl.Log = true
1✔
106
                                acl.Severity = ptr.To(ovnnb.ACLSeverityWarning)
1✔
107
                        }
1✔
108

109
                        if acl.Options == nil {
2✔
110
                                acl.Options = make(map[string]string)
1✔
111
                        }
1✔
112
                        acl.Options["apply-after-lb"] = "true"
1✔
113
                }
114

115
                defaultDropACL, err := c.newACLWithoutCheck(pgName, ovnnb.ACLDirectionFromLport, util.EgressDefaultDrop, allIPMatch.String(), ovnnb.ACLActionDrop, util.NetpolACLTier, options)
1✔
116
                if err != nil {
2✔
117
                        klog.Error(err)
1✔
118
                        return nil, fmt.Errorf("new default drop egress acl for port group %s: %w", pgName, err)
1✔
119
                }
1✔
120

121
                acls = append(acls, defaultDropACL)
1✔
122
        }
123

124
        /* allow acl */
125
        matches := newNetworkPolicyACLMatch(pgName, asEgressName, asExceptName, protocol, ovnnb.ACLDirectionFromLport, npp, namedPortMap)
1✔
126
        for _, m := range matches {
2✔
127
                allowACL, err := c.newACLWithoutCheck(pgName, ovnnb.ACLDirectionFromLport, util.EgressAllowPriority, m, ovnnb.ACLActionAllowRelated, util.NetpolACLTier, func(acl *ovnnb.ACL) {
2✔
128
                        setACLName(acl, aclName)
1✔
129
                        if acl.Options == nil {
2✔
130
                                acl.Options = make(map[string]string)
1✔
131
                        }
1✔
132
                        acl.Options["apply-after-lb"] = "true"
1✔
133
                        if logEnable && slices.Contains(logACLActions, ovnnb.ACLActionAllow) {
1✔
134
                                acl.Log = true
×
135
                        }
×
136
                })
137
                if err != nil {
2✔
138
                        klog.Error(err)
1✔
139
                        return nil, fmt.Errorf("new allow egress acl for port group %s: %w", pgName, err)
1✔
140
                }
1✔
141

142
                acls = append(acls, allowACL)
1✔
143
        }
144

145
        ops, err := c.CreateAclsOps(pgName, portGroupKey, acls...)
1✔
146
        if err != nil {
1✔
147
                klog.Error(err)
×
148
                return nil, err
×
149
        }
×
150

151
        return ops, nil
1✔
152
}
153

154
// CreateGatewayACL create allow acl for subnet gateway
155
func (c *OVNNbClient) CreateGatewayACL(lsName, pgName, gateway, u2oInterconnectionIP string) error {
1✔
156
        acls := make([]*ovnnb.ACL, 0)
1✔
157

1✔
158
        var parentName, parentType string
1✔
159
        switch {
1✔
160
        case len(pgName) != 0:
1✔
161
                parentName, parentType = pgName, portGroupKey
1✔
162
        case len(lsName) != 0:
1✔
163
                parentName, parentType = lsName, logicalSwitchKey
1✔
164
        default:
1✔
165
                return errors.New("one of port group name and logical switch name must be specified")
1✔
166
        }
167

168
        gateways := set.New(strings.Split(gateway, ",")...)
1✔
169
        if u2oInterconnectionIP != "" {
2✔
170
                gateways = gateways.Insert(strings.Split(u2oInterconnectionIP, ",")...)
1✔
171
        }
1✔
172

173
        options := func(acl *ovnnb.ACL) {
2✔
174
                if acl.Options == nil {
2✔
175
                        acl.Options = make(map[string]string)
1✔
176
                }
1✔
177
                acl.Options["apply-after-lb"] = "true"
1✔
178
        }
179
        v6Exists := false
1✔
180
        for gw := range gateways {
2✔
181
                protocol := util.CheckProtocol(gw)
1✔
182
                ipSuffix := "ip4"
1✔
183
                if protocol == kubeovnv1.ProtocolIPv6 {
2✔
184
                        ipSuffix = "ip6"
1✔
185
                        v6Exists = true
1✔
186
                }
1✔
187

188
                allowIngressACL, err := c.newACL(parentName, ovnnb.ACLDirectionToLport, util.IngressAllowPriority, fmt.Sprintf("%s.src == %s", ipSuffix, gw), ovnnb.ACLActionAllowStateless, util.NetpolACLTier)
1✔
189
                if err != nil {
1✔
190
                        klog.Error(err)
×
191
                        return fmt.Errorf("new allow ingress acl for %s: %w", parentName, err)
×
192
                }
×
193

194
                allowEgressACL, err := c.newACL(parentName, ovnnb.ACLDirectionFromLport, util.EgressAllowPriority, fmt.Sprintf("%s.dst == %s", ipSuffix, gw), ovnnb.ACLActionAllowStateless, util.NetpolACLTier, options)
1✔
195
                if err != nil {
1✔
196
                        klog.Error(err)
×
197
                        return fmt.Errorf("new allow egress acl for %s: %w", parentName, err)
×
198
                }
×
199

200
                acls = append(acls, allowIngressACL, allowEgressACL)
1✔
201
        }
202

203
        if v6Exists {
2✔
204
                ndACL, err := c.newACL(parentName, ovnnb.ACLDirectionFromLport, util.EgressAllowPriority, "nd || nd_ra || nd_rs", ovnnb.ACLActionAllowStateless, util.NetpolACLTier, options)
1✔
205
                if err != nil {
1✔
206
                        klog.Error(err)
×
207
                        return fmt.Errorf("new nd acl for %s: %w", parentName, err)
×
208
                }
×
209

210
                acls = append(acls, ndACL)
1✔
211
        }
212

213
        if err := c.CreateAcls(parentName, parentType, acls...); err != nil {
1✔
214
                klog.Error(err)
×
215
                return fmt.Errorf("add gateway acls to %s: %w", pgName, err)
×
216
        }
×
217

218
        return nil
1✔
219
}
220

221
// CreateNodeACL create allow acl for node join ip
222
func (c *OVNNbClient) CreateNodeACL(pgName, nodeIPStr, joinIPStr string) error {
1✔
223
        acls := make([]*ovnnb.ACL, 0)
1✔
224
        nodeIPs := strings.Split(nodeIPStr, ",")
1✔
225
        for _, nodeIP := range nodeIPs {
2✔
226
                protocol := util.CheckProtocol(nodeIP)
1✔
227
                ipSuffix := "ip4"
1✔
228
                if protocol == kubeovnv1.ProtocolIPv6 {
2✔
229
                        ipSuffix = "ip6"
1✔
230
                }
1✔
231
                pgAs := fmt.Sprintf("%s_%s", pgName, ipSuffix)
1✔
232

1✔
233
                allowIngressACL, err := c.newACL(pgName, ovnnb.ACLDirectionToLport, util.NodeAllowPriority, fmt.Sprintf("%s.src == %s && %s.dst == $%s", ipSuffix, nodeIP, ipSuffix, pgAs), ovnnb.ACLActionAllowRelated, util.NetpolACLTier)
1✔
234
                if err != nil {
2✔
235
                        klog.Error(err)
1✔
236
                        return fmt.Errorf("new allow ingress acl for port group %s: %w", pgName, err)
1✔
237
                }
1✔
238

239
                options := func(acl *ovnnb.ACL) {
2✔
240
                        if acl.Options == nil {
2✔
241
                                acl.Options = make(map[string]string)
1✔
242
                        }
1✔
243
                        acl.Options["apply-after-lb"] = "true"
1✔
244
                }
245

246
                allowEgressACL, err := c.newACL(pgName, ovnnb.ACLDirectionFromLport, util.NodeAllowPriority, fmt.Sprintf("%s.dst == %s && %s.src == $%s", ipSuffix, nodeIP, ipSuffix, pgAs), ovnnb.ACLActionAllowRelated, util.NetpolACLTier, options)
1✔
247
                if err != nil {
1✔
248
                        klog.Error(err)
×
249
                        return fmt.Errorf("new allow egress acl for port group %s: %w", pgName, err)
×
250
                }
×
251

252
                acls = append(acls, allowIngressACL, allowEgressACL)
1✔
253
        }
254

255
        for joinIP := range strings.SplitSeq(joinIPStr, ",") {
2✔
256
                if slices.Contains(nodeIPs, joinIP) {
2✔
257
                        continue
1✔
258
                }
259

260
                protocol := util.CheckProtocol(joinIP)
1✔
261
                ipSuffix := "ip4"
1✔
262
                if protocol == kubeovnv1.ProtocolIPv6 {
2✔
263
                        ipSuffix = "ip6"
1✔
264
                }
1✔
265

266
                pgAs := fmt.Sprintf("%s_%s", pgName, ipSuffix)
1✔
267

1✔
268
                if err := c.DeleteACL(pgName, portGroupKey, ovnnb.ACLDirectionToLport, util.NodeAllowPriority, fmt.Sprintf("%s.src == %s && %s.dst == $%s", ipSuffix, joinIP, ipSuffix, pgAs)); err != nil {
1✔
269
                        klog.Errorf("delete ingress acl from port group %s: %v", pgName, err)
×
270
                        return err
×
271
                }
×
272

273
                if err := c.DeleteACL(pgName, portGroupKey, ovnnb.ACLDirectionFromLport, util.NodeAllowPriority, fmt.Sprintf("%s.dst == %s && %s.src == $%s", ipSuffix, joinIP, ipSuffix, pgAs)); err != nil {
1✔
274
                        klog.Errorf("delete egress acl from port group %s: %v", pgName, err)
×
275
                        return err
×
276
                }
×
277
        }
278

279
        if err := c.CreateAcls(pgName, portGroupKey, acls...); err != nil {
1✔
280
                return fmt.Errorf("add node acls to port group %s: %w", pgName, err)
×
281
        }
×
282

283
        return nil
1✔
284
}
285

286
func (c *OVNNbClient) CreateSgDenyAllACL(sgName string) error {
1✔
287
        pgName := GetSgPortGroupName(sgName)
1✔
288

1✔
289
        ingressACL, err := c.newACL(pgName, ovnnb.ACLDirectionToLport, util.SecurityGroupDropPriority, fmt.Sprintf("outport == @%s && ip", pgName), ovnnb.ACLActionDrop, util.NetpolACLTier)
1✔
290
        if err != nil {
2✔
291
                klog.Error(err)
1✔
292
                return fmt.Errorf("new deny all ingress acl for security group %s: %w", sgName, err)
1✔
293
        }
1✔
294

295
        egressACL, err := c.newACL(pgName, ovnnb.ACLDirectionFromLport, util.SecurityGroupDropPriority, fmt.Sprintf("inport == @%s && ip", pgName), ovnnb.ACLActionDrop, util.NetpolACLTier)
1✔
296
        if err != nil {
1✔
297
                klog.Error(err)
×
298
                return fmt.Errorf("new deny all egress acl for security group %s: %w", sgName, err)
×
299
        }
×
300

301
        err = c.CreateAcls(pgName, portGroupKey, ingressACL, egressACL)
1✔
302
        if err != nil {
2✔
303
                klog.Error(err)
1✔
304
                return fmt.Errorf("add deny all acl to port group %s: %w", pgName, err)
1✔
305
        }
1✔
306

307
        return nil
1✔
308
}
309

310
// CreateSgACL create allow acl for security group
311
func (c *OVNNbClient) CreateSgBaseACL(sgName, direction string) error {
1✔
312
        pgName := GetSgPortGroupName(sgName)
1✔
313

1✔
314
        // ingress rule
1✔
315
        portDirection := "outport"
1✔
316
        dhcpv4UdpSrc, dhcpv4UdpDst := "67", "68"
1✔
317
        dhcpv6UdpSrc, dhcpv6UdpDst := "547", "546"
1✔
318
        icmpv6Type := "{130, 134, 135, 136}"
1✔
319
        // 130 group membership query
1✔
320
        // 133 router solicitation
1✔
321
        // 134 router advertisement
1✔
322
        // 135 neighbor solicitation
1✔
323
        // 136 neighbor advertisement
1✔
324

1✔
325
        if direction == ovnnb.ACLDirectionFromLport { // egress rule
2✔
326
                portDirection = "inport"
1✔
327
                dhcpv4UdpSrc, dhcpv4UdpDst = dhcpv4UdpDst, dhcpv4UdpSrc
1✔
328
                dhcpv6UdpSrc, dhcpv6UdpDst = dhcpv6UdpDst, dhcpv6UdpSrc
1✔
329
                icmpv6Type = "{130, 133, 135, 136}"
1✔
330
        }
1✔
331

332
        acls := make([]*ovnnb.ACL, 0)
1✔
333

1✔
334
        newACL := func(match string) {
2✔
335
                acl, err := c.newACL(pgName, direction, util.SecurityGroupBasePriority, match, ovnnb.ACLActionAllowRelated, util.NetpolACLTier)
1✔
336
                if err != nil {
2✔
337
                        klog.Error(err)
1✔
338
                        klog.Errorf("new base ingress acl for security group %s: %v", sgName, err)
1✔
339
                        return
1✔
340
                }
1✔
341
                acls = append(acls, acl)
1✔
342
        }
343

344
        // allow arp
345
        allArpMatch := NewAndACLMatch(
1✔
346
                NewACLMatch(portDirection, "==", "@"+pgName, ""),
1✔
347
                NewACLMatch("arp", "", "", ""),
1✔
348
        )
1✔
349
        newACL(allArpMatch.String())
1✔
350

1✔
351
        // icmpv6
1✔
352
        icmpv6Match := NewAndACLMatch(
1✔
353
                NewACLMatch(portDirection, "==", "@"+pgName, ""),
1✔
354
                NewACLMatch("icmp6.type", "==", icmpv6Type, ""),
1✔
355
                NewACLMatch("icmp6.code", "==", "0", ""),
1✔
356
                NewACLMatch("ip.ttl", "==", "255", ""),
1✔
357
        )
1✔
358
        newACL(icmpv6Match.String())
1✔
359

1✔
360
        // dhcpv4 offer
1✔
361
        dhcpv4Match := NewAndACLMatch(
1✔
362
                NewACLMatch(portDirection, "==", "@"+pgName, ""),
1✔
363
                NewACLMatch("udp.src", "==", dhcpv4UdpSrc, ""),
1✔
364
                NewACLMatch("udp.dst", "==", dhcpv4UdpDst, ""),
1✔
365
                NewACLMatch("ip4", "", "", ""),
1✔
366
        )
1✔
367
        newACL(dhcpv4Match.String())
1✔
368

1✔
369
        // dhcpv6 offer
1✔
370
        dhcpv6Match := NewAndACLMatch(
1✔
371
                NewACLMatch(portDirection, "==", "@"+pgName, ""),
1✔
372
                NewACLMatch("udp.src", "==", dhcpv6UdpSrc, ""),
1✔
373
                NewACLMatch("udp.dst", "==", dhcpv6UdpDst, ""),
1✔
374
                NewACLMatch("ip6", "", "", ""),
1✔
375
        )
1✔
376
        newACL(dhcpv6Match.String())
1✔
377

1✔
378
        // vrrp
1✔
379
        vrrpMatch := NewAndACLMatch(
1✔
380
                NewACLMatch(portDirection, "==", "@"+pgName, ""),
1✔
381
                NewACLMatch("ip.proto", "==", "112", ""),
1✔
382
        )
1✔
383
        newACL(vrrpMatch.String())
1✔
384

1✔
385
        if err := c.CreateAcls(pgName, portGroupKey, acls...); err != nil {
1✔
386
                klog.Error(err)
×
387
                return fmt.Errorf("add ingress acls to port group %s: %w", pgName, err)
×
388
        }
×
389
        return nil
1✔
390
}
391

392
func (c *OVNNbClient) UpdateSgACL(sg *kubeovnv1.SecurityGroup, direction string) error {
1✔
393
        pgName := GetSgPortGroupName(sg.Name)
1✔
394

1✔
395
        // clear acl
1✔
396
        if err := c.DeleteAcls(pgName, portGroupKey, direction, nil); err != nil {
2✔
397
                klog.Error(err)
1✔
398
                return fmt.Errorf("delete direction '%s' acls from port group %s: %w", direction, pgName, err)
1✔
399
        }
1✔
400

401
        acls := make([]*ovnnb.ACL, 0, 2)
1✔
402

1✔
403
        // ingress rule
1✔
404
        srcOrDst, portDirection, sgRules := "src", "outport", sg.Spec.IngressRules
1✔
405
        if direction == ovnnb.ACLDirectionFromLport { // egress rule
2✔
406
                srcOrDst = "dst"
1✔
407
                portDirection = "inport"
1✔
408
                sgRules = sg.Spec.EgressRules
1✔
409
        }
1✔
410

411
        /* create port_group associated acl */
412
        if sg.Spec.AllowSameGroupTraffic {
2✔
413
                asName := GetSgV4AssociatedName(sg.Name)
1✔
414
                for _, ipSuffix := range []string{"ip4", "ip6"} {
2✔
415
                        if ipSuffix == "ip6" {
2✔
416
                                asName = GetSgV6AssociatedName(sg.Name)
1✔
417
                        }
1✔
418

419
                        match := NewAndACLMatch(
1✔
420
                                NewACLMatch(portDirection, "==", "@"+pgName, ""),
1✔
421
                                NewACLMatch(ipSuffix, "", "", ""),
1✔
422
                                NewACLMatch(ipSuffix+"."+srcOrDst, "==", "$"+asName, ""),
1✔
423
                        )
1✔
424
                        acl, err := c.newACL(pgName, direction, util.SecurityGroupAllowPriority, match.String(), ovnnb.ACLActionAllowRelated, util.NetpolACLTier)
1✔
425
                        if err != nil {
1✔
426
                                klog.Error(err)
×
427
                                return fmt.Errorf("new allow acl for security group %s: %w", sg.Name, err)
×
428
                        }
×
429

430
                        acls = append(acls, acl)
1✔
431
                }
432
        }
433

434
        /* create rule acl */
435
        for _, rule := range sgRules {
2✔
436
                acl, err := c.newSgRuleACL(sg.Name, direction, rule)
1✔
437
                if err != nil {
1✔
438
                        klog.Error(err)
×
439
                        return fmt.Errorf("new rule acl for security group %s: %w", sg.Name, err)
×
440
                }
×
441
                acls = append(acls, acl)
1✔
442
        }
443

444
        if err := c.CreateAcls(pgName, portGroupKey, acls...); err != nil {
1✔
445
                klog.Error(err)
×
446
                return fmt.Errorf("add acl to port group %s: %w", pgName, err)
×
447
        }
×
448

449
        return nil
1✔
450
}
451

452
func (c *OVNNbClient) UpdateLogicalSwitchACL(lsName, cidrBlock string, subnetAcls []kubeovnv1.ACL, allowEWTraffic bool) error {
1✔
453
        if err := c.DeleteAcls(lsName, logicalSwitchKey, "", map[string]string{"subnet": lsName}); err != nil {
2✔
454
                klog.Error(err)
1✔
455
                return fmt.Errorf("delete subnet acls from %s: %w", lsName, err)
1✔
456
        }
1✔
457

458
        if len(subnetAcls) == 0 {
2✔
459
                return nil
1✔
460
        }
1✔
461
        acls := make([]*ovnnb.ACL, 0)
1✔
462

1✔
463
        options := func(acl *ovnnb.ACL) {
2✔
464
                if acl.ExternalIDs == nil {
1✔
465
                        acl.ExternalIDs = make(map[string]string)
×
466
                }
×
467
                acl.ExternalIDs["subnet"] = lsName
1✔
468
        }
469

470
        if allowEWTraffic {
2✔
471
                for cidr := range strings.SplitSeq(cidrBlock, ",") {
2✔
472
                        protocol := util.CheckProtocol(cidr)
1✔
473

1✔
474
                        ipSuffix := "ip4"
1✔
475
                        if protocol == kubeovnv1.ProtocolIPv6 {
2✔
476
                                ipSuffix = "ip6"
1✔
477
                        }
1✔
478

479
                        /* same subnet acl */
480
                        sameSubnetMatch := NewAndACLMatch(
1✔
481
                                NewACLMatch(ipSuffix+".src", "==", cidr, ""),
1✔
482
                                NewACLMatch(ipSuffix+".dst", "==", cidr, ""),
1✔
483
                        )
1✔
484

1✔
485
                        ingressSameSubnetACL, err := c.newACL(lsName, ovnnb.ACLDirectionToLport, util.AllowEWTrafficPriority, sameSubnetMatch.String(), ovnnb.ACLActionAllow, util.NetpolACLTier, options)
1✔
486
                        if err != nil {
1✔
487
                                klog.Error(err)
×
488
                                return fmt.Errorf("new same subnet ingress acl for logical switch %s: %w", lsName, err)
×
489
                        }
×
490
                        acls = append(acls, ingressSameSubnetACL)
1✔
491

1✔
492
                        egressSameSubnetACL, err := c.newACL(lsName, ovnnb.ACLDirectionFromLport, util.AllowEWTrafficPriority, sameSubnetMatch.String(), ovnnb.ACLActionAllow, util.NetpolACLTier, options)
1✔
493
                        if err != nil {
1✔
494
                                klog.Error(err)
×
495
                                return fmt.Errorf("new same subnet egress acl for logical switch %s: %w", lsName, err)
×
496
                        }
×
497
                        acls = append(acls, egressSameSubnetACL)
1✔
498
                }
499
        }
500

501
        /* recreate logical switch acl */
502
        for _, subnetACL := range subnetAcls {
2✔
503
                acl, err := c.newACL(lsName, subnetACL.Direction, strconv.Itoa(subnetACL.Priority), subnetACL.Match, subnetACL.Action, util.NetpolACLTier, options)
1✔
504
                if err != nil {
1✔
505
                        klog.Error(err)
×
506
                        return fmt.Errorf("new acl for logical switch %s: %w", lsName, err)
×
507
                }
×
508
                acls = append(acls, acl)
1✔
509
        }
510

511
        if err := c.CreateAcls(lsName, logicalSwitchKey, acls...); err != nil {
1✔
512
                klog.Error(err)
×
513
                return fmt.Errorf("add acls to logical switch %s: %w", lsName, err)
×
514
        }
×
515

516
        return nil
1✔
517
}
518

519
// UpdateACL update acl
520
func (c *OVNNbClient) UpdateACL(acl *ovnnb.ACL, fields ...any) error {
1✔
521
        if acl == nil {
2✔
522
                return errors.New("address_set is nil")
1✔
523
        }
1✔
524

525
        op, err := c.Where(acl).Update(acl, fields...)
1✔
526
        if err != nil {
1✔
527
                klog.Error(err)
×
528
                return fmt.Errorf("generate operations for updating acl with 'direction %s priority %d match %s': %w", acl.Direction, acl.Priority, acl.Match, err)
×
529
        }
×
530

531
        if err = c.Transact("acl-update", op); err != nil {
1✔
532
                klog.Error(err)
×
533
                return fmt.Errorf("update acl with 'direction %s priority %d match %s': %w", acl.Direction, acl.Priority, acl.Match, err)
×
534
        }
×
535

536
        return nil
1✔
537
}
538

539
// SetLogicalSwitchPrivate will drop all ingress traffic except allow subnets, same subnet and node subnet
540
func (c *OVNNbClient) SetLogicalSwitchPrivate(lsName, cidrBlock, nodeSwitchCIDR string, allowSubnets []string) error {
1✔
541
        // clear acls
1✔
542
        if err := c.DeleteAcls(lsName, logicalSwitchKey, "", nil); err != nil {
2✔
543
                klog.Error(err)
1✔
544
                return fmt.Errorf("clear logical switch %s acls: %w", lsName, err)
1✔
545
        }
1✔
546

547
        acls := make([]*ovnnb.ACL, 0)
1✔
548

1✔
549
        /* default drop acl */
1✔
550
        allIPMatch := NewACLMatch("ip", "", "", "")
1✔
551

1✔
552
        options := func(acl *ovnnb.ACL) {
2✔
553
                setACLName(acl, lsName)
1✔
554
                acl.Log = true
1✔
555
                acl.Severity = ptr.To(ovnnb.ACLSeverityWarning)
1✔
556
        }
1✔
557

558
        defaultDropACL, err := c.newACL(lsName, ovnnb.ACLDirectionToLport, util.DefaultDropPriority, allIPMatch.String(), ovnnb.ACLActionDrop, util.NetpolACLTier, options)
1✔
559
        if err != nil {
1✔
560
                klog.Error(err)
×
561
                return fmt.Errorf("new default drop ingress acl for logical switch %s: %w", lsName, err)
×
562
        }
×
563

564
        acls = append(acls, defaultDropACL)
1✔
565

1✔
566
        nodeSubnetACLFunc := func(protocol, ipSuffix string) error {
2✔
567
                for nodeCidr := range strings.SplitSeq(nodeSwitchCIDR, ",") {
2✔
568
                        // skip different address family
1✔
569
                        if protocol != util.CheckProtocol(nodeCidr) {
2✔
570
                                continue
1✔
571
                        }
572

573
                        match := NewACLMatch(ipSuffix+".src", "==", nodeCidr, "")
1✔
574

1✔
575
                        acl, err := c.newACL(lsName, ovnnb.ACLDirectionToLport, util.NodeAllowPriority, match.String(), ovnnb.ACLActionAllowRelated, util.NetpolACLTier)
1✔
576
                        if err != nil {
1✔
577
                                klog.Error(err)
×
578
                                return fmt.Errorf("new node subnet ingress acl for logical switch %s: %w", lsName, err)
×
579
                        }
×
580

581
                        acls = append(acls, acl)
1✔
582
                }
583

584
                return nil
1✔
585
        }
586

587
        allowSubnetACLFunc := func(protocol, ipSuffix, cidr string) error {
2✔
588
                for _, allowSubnet := range allowSubnets {
2✔
589
                        subnet := strings.TrimSpace(allowSubnet)
1✔
590
                        // skip empty subnet
1✔
591
                        if len(subnet) == 0 {
1✔
592
                                continue
×
593
                        }
594

595
                        // skip different address family
596
                        if util.CheckProtocol(subnet) != protocol {
2✔
597
                                continue
1✔
598
                        }
599

600
                        match := NewOrACLMatch(
1✔
601
                                NewAndACLMatch(
1✔
602
                                        NewACLMatch(ipSuffix+".src", "==", cidr, ""),
1✔
603
                                        NewACLMatch(ipSuffix+".dst", "==", subnet, ""),
1✔
604
                                ),
1✔
605
                                NewAndACLMatch(
1✔
606
                                        NewACLMatch(ipSuffix+".src", "==", subnet, ""),
1✔
607
                                        NewACLMatch(ipSuffix+".dst", "==", cidr, ""),
1✔
608
                                ),
1✔
609
                        )
1✔
610

1✔
611
                        acl, err := c.newACL(lsName, ovnnb.ACLDirectionToLport, util.SubnetAllowPriority, match.String(), ovnnb.ACLActionAllowRelated, util.NetpolACLTier)
1✔
612
                        if err != nil {
1✔
613
                                klog.Error(err)
×
614
                                return fmt.Errorf("new allow subnet ingress acl for logical switch %s: %w", lsName, err)
×
615
                        }
×
616

617
                        acls = append(acls, acl)
1✔
618
                }
619
                return nil
1✔
620
        }
621

622
        for cidr := range strings.SplitSeq(cidrBlock, ",") {
2✔
623
                protocol := util.CheckProtocol(cidr)
1✔
624

1✔
625
                ipSuffix := "ip4"
1✔
626
                if protocol == kubeovnv1.ProtocolIPv6 {
2✔
627
                        ipSuffix = "ip6"
1✔
628
                }
1✔
629

630
                /* same subnet acl */
631
                sameSubnetMatch := NewAndACLMatch(
1✔
632
                        NewACLMatch(ipSuffix+".src", "==", cidr, ""),
1✔
633
                        NewACLMatch(ipSuffix+".dst", "==", cidr, ""),
1✔
634
                )
1✔
635

1✔
636
                sameSubnetACL, err := c.newACL(lsName, ovnnb.ACLDirectionToLport, util.SubnetAllowPriority, sameSubnetMatch.String(), ovnnb.ACLActionAllowRelated, util.NetpolACLTier)
1✔
637
                if err != nil {
1✔
638
                        klog.Error(err)
×
639
                        return fmt.Errorf("new same subnet ingress acl for logical switch %s: %w", lsName, err)
×
640
                }
×
641

642
                acls = append(acls, sameSubnetACL)
1✔
643

1✔
644
                // node subnet acl
1✔
645
                if err := nodeSubnetACLFunc(protocol, ipSuffix); err != nil {
1✔
646
                        klog.Error(err)
×
647
                        return err
×
648
                }
×
649

650
                // allow subnet acl
651
                if err := allowSubnetACLFunc(protocol, ipSuffix, cidr); err != nil {
1✔
652
                        klog.Error(err)
×
653
                        return err
×
654
                }
×
655
        }
656

657
        if err := c.CreateAcls(lsName, logicalSwitchKey, acls...); err != nil {
1✔
658
                klog.Error(err)
×
659
                return fmt.Errorf("add ingress acls to logical switch %s: %w", lsName, err)
×
660
        }
×
661

662
        return nil
1✔
663
}
664

665
func (c *OVNNbClient) SetACLLog(pgName string, logEnable, isIngress bool) error {
1✔
666
        direction := ovnnb.ACLDirectionToLport
1✔
667
        portDirection := "outport"
1✔
668
        if !isIngress {
2✔
669
                direction = ovnnb.ACLDirectionFromLport
1✔
670
                portDirection = "inport"
1✔
671
        }
1✔
672

673
        // match all traffic to or from pgName
674
        allIPMatch := NewAndACLMatch(
1✔
675
                NewACLMatch(portDirection, "==", "@"+pgName, ""),
1✔
676
                NewACLMatch("ip", "", "", ""),
1✔
677
        )
1✔
678

1✔
679
        acl, err := c.GetACL(pgName, direction, util.IngressDefaultDrop, allIPMatch.String(), true)
1✔
680
        if err != nil {
2✔
681
                klog.Error(err)
1✔
682
                return err
1✔
683
        }
1✔
684

685
        if acl == nil {
2✔
686
                return nil // skip if acl not found
1✔
687
        }
1✔
688

689
        if acl.Log == logEnable {
2✔
690
                return nil
1✔
691
        }
1✔
692
        acl.Log = logEnable
1✔
693

1✔
694
        err = c.UpdateACL(acl, &acl.Log)
1✔
695
        if err != nil {
1✔
696
                klog.Error(err)
×
697
                return fmt.Errorf("update acl: %w", err)
×
698
        }
×
699

700
        return nil
1✔
701
}
702

703
// CreateAcls create several acl once
704
// parentType is 'ls' or 'pg'
705
func (c *OVNNbClient) CreateAcls(parentName, parentType string, acls ...*ovnnb.ACL) error {
1✔
706
        ops, err := c.CreateAclsOps(parentName, parentType, acls...)
1✔
707
        if err != nil {
2✔
708
                klog.Error(err)
1✔
709
                return err
1✔
710
        }
1✔
711

712
        if err = c.Transact("acls-add", ops); err != nil {
1✔
713
                return fmt.Errorf("add acls to type %s %s: %w", parentType, parentName, err)
×
714
        }
×
715

716
        return nil
1✔
717
}
718

719
func (c *OVNNbClient) CreateBareACL(parentName, direction, priority, match, action string) error {
1✔
720
        acl, err := c.newACL(parentName, direction, priority, match, action, util.NetpolACLTier)
1✔
721
        if err != nil {
2✔
722
                klog.Error(err)
1✔
723
                return fmt.Errorf("new acl direction %s priority %s match %s action %s: %w", direction, priority, match, action, err)
1✔
724
        }
1✔
725

726
        op, err := c.Create(acl)
1✔
727
        if err != nil {
1✔
728
                klog.Error(err)
×
729
                return fmt.Errorf("generate operations for creating acl direction %s priority %s match %s action %s: %w", direction, priority, match, action, err)
×
730
        }
×
731

732
        if err = c.Transact("acl-create", op); err != nil {
2✔
733
                klog.Error(err)
1✔
734
                return fmt.Errorf("create acl direction %s priority %s match %s action %s: %w", direction, priority, match, action, err)
1✔
735
        }
1✔
736

737
        return nil
1✔
738
}
739

740
// DeleteAcls delete several acl once,
741
// delete to-lport and from-lport direction acl when direction is empty, otherwise one-way
742
// parentType is 'ls' or 'pg'
743
func (c *OVNNbClient) DeleteAcls(parentName, parentType, direction string, externalIDs map[string]string) error {
1✔
744
        ops, err := c.DeleteAclsOps(parentName, parentType, direction, externalIDs)
1✔
745
        if err != nil {
2✔
746
                klog.Error(err)
1✔
747
                return err
1✔
748
        }
1✔
749

750
        if err = c.Transact("acls-del", ops); err != nil {
1✔
751
                klog.Error(err)
×
752
                return fmt.Errorf("del acls from type %s %s: %w", parentType, parentName, err)
×
753
        }
×
754

755
        return nil
1✔
756
}
757

758
func (c *OVNNbClient) DeleteACL(parentName, parentType, direction, priority, match string) error {
1✔
759
        acl, err := c.GetACL(parentName, direction, priority, match, true)
1✔
760
        if err != nil {
2✔
761
                klog.Error(err)
1✔
762
                return err
1✔
763
        }
1✔
764

765
        if acl == nil {
2✔
766
                return nil // skip if acl not exist
1✔
767
        }
1✔
768

769
        // the acls column has a strong reference to the ACL table, so there is no need to delete the ACL
770
        var removeACLOp []ovsdb.Operation
1✔
771
        if parentType == portGroupKey { // remove acl from port group
2✔
772
                removeACLOp, err = c.portGroupUpdateACLOp(parentName, []string{acl.UUID}, ovsdb.MutateOperationDelete)
1✔
773
                if err != nil {
1✔
774
                        klog.Error(err)
×
775
                        return fmt.Errorf("generate operations for deleting acl from port group %s: %w", parentName, err)
×
776
                }
×
777
        } else { // remove acl from logical switch
1✔
778
                removeACLOp, err = c.logicalSwitchUpdateACLOp(parentName, []string{acl.UUID}, ovsdb.MutateOperationDelete)
1✔
779
                if err != nil {
1✔
780
                        klog.Error(err)
×
781
                        return fmt.Errorf("generate operations for deleting acl from logical switch %s: %w", parentName, err)
×
782
                }
×
783
        }
784

785
        if err = c.Transact("acls-del", removeACLOp); err != nil {
1✔
786
                klog.Error(err)
×
787
                return fmt.Errorf("del acls from type %s %s: %w", parentType, parentName, err)
×
788
        }
×
789

790
        return nil
1✔
791
}
792

793
// GetACL get acl by direction, priority and match,
794
// be consistent with ovn-nbctl which direction, priority and match determine one acl in port group or logical switch
795
func (c *OVNNbClient) GetACL(parent, direction, priority, match string, ignoreNotFound bool) (*ovnnb.ACL, error) {
1✔
796
        // this is necessary because may exist same direction, priority and match acl in different port group or logical switch
1✔
797
        if len(parent) == 0 {
2✔
798
                return nil, errors.New("the port group name or logical switch name is required")
1✔
799
        }
1✔
800

801
        ctx, cancel := context.WithTimeout(context.Background(), c.Timeout)
1✔
802
        defer cancel()
1✔
803

1✔
804
        intPriority, _ := strconv.Atoi(priority)
1✔
805

1✔
806
        aclList := make([]ovnnb.ACL, 0)
1✔
807
        if err := c.ovsDbClient.WhereCache(func(acl *ovnnb.ACL) bool {
2✔
808
                return len(acl.ExternalIDs) != 0 && acl.ExternalIDs[aclParentKey] == parent && acl.Direction == direction && acl.Priority == intPriority && acl.Match == match
1✔
809
        }).List(ctx, &aclList); err != nil {
1✔
810
                klog.Error(err)
×
811
                return nil, fmt.Errorf("get acl with 'parent %s direction %s priority %s match %s': %w", parent, direction, priority, match, err)
×
812
        }
×
813

814
        // not found
815
        if len(aclList) == 0 {
2✔
816
                if ignoreNotFound {
2✔
817
                        return nil, nil
1✔
818
                }
1✔
819
                return nil, fmt.Errorf("not found acl with 'parent %s direction %s priority %s match %s'", parent, direction, priority, match)
1✔
820
        }
821

822
        if len(aclList) > 1 {
2✔
823
                return nil, fmt.Errorf("more than one acl with same 'parent %s direction %s priority %s match %s'", parent, direction, priority, match)
1✔
824
        }
1✔
825

826
        // #nosec G602
827
        return &aclList[0], nil
1✔
828
}
829

830
// ListAcls list acls which match the given externalIDs,
831
// result should include all to-lport and from-lport acls when direction is empty,
832
// result should include all acls when externalIDs is empty,
833
// result should include all acls which externalIDs[key] is not empty when externalIDs[key] is ""
834
// TODO: maybe add other filter conditions(priority or match)
835
func (c *OVNNbClient) ListAcls(direction string, externalIDs map[string]string) ([]ovnnb.ACL, error) {
1✔
836
        ctx, cancel := context.WithTimeout(context.Background(), c.Timeout)
1✔
837
        defer cancel()
1✔
838

1✔
839
        aclList := make([]ovnnb.ACL, 0)
1✔
840

1✔
841
        if err := c.WhereCache(aclFilter(direction, externalIDs)).List(ctx, &aclList); err != nil {
1✔
842
                klog.Error(err)
×
843
                return nil, fmt.Errorf("list acls: %w", err)
×
844
        }
×
845

846
        return aclList, nil
1✔
847
}
848

849
func (c *OVNNbClient) ACLExists(parent, direction, priority, match string) (bool, error) {
1✔
850
        acl, err := c.GetACL(parent, direction, priority, match, true)
1✔
851
        return acl != nil, err
1✔
852
}
1✔
853

854
// newACL return acl with basic information
855
func (c *OVNNbClient) newACL(parent, direction, priority, match, action string, tier int, options ...func(acl *ovnnb.ACL)) (*ovnnb.ACL, error) {
1✔
856
        if len(parent) == 0 {
2✔
857
                return nil, errors.New("the port group name or logical switch name is required")
1✔
858
        }
1✔
859

860
        if len(direction) == 0 || len(priority) == 0 || len(match) == 0 || len(action) == 0 {
2✔
861
                return nil, fmt.Errorf("acl 'direction %s' and 'priority %s' and 'match %s' and 'action %s' is required", direction, priority, match, action)
1✔
862
        }
1✔
863

864
        exists, err := c.ACLExists(parent, direction, priority, match)
1✔
865
        if err != nil {
1✔
866
                klog.Error(err)
×
867
                return nil, fmt.Errorf("get parent %s acl: %w", parent, err)
×
868
        }
×
869

870
        // found, ignore
871
        if exists {
2✔
872
                return nil, nil
1✔
873
        }
1✔
874

875
        intPriority, _ := strconv.Atoi(priority)
1✔
876

1✔
877
        acl := &ovnnb.ACL{
1✔
878
                UUID:      ovsclient.NamedUUID(),
1✔
879
                Action:    action,
1✔
880
                Direction: direction,
1✔
881
                Match:     match,
1✔
882
                Priority:  intPriority,
1✔
883
                ExternalIDs: map[string]string{
1✔
884
                        aclParentKey: parent,
1✔
885
                },
1✔
886
                Tier: tier,
1✔
887
        }
1✔
888

1✔
889
        for _, option := range options {
2✔
890
                option(acl)
1✔
891
        }
1✔
892

893
        return acl, nil
1✔
894
}
895

896
// newACLWithoutCheck return acl with basic information without check acl exists,
897
// this would cause duplicated acl, so don't use this function to create acl normally,
898
// but maybe used for updating network policy acl
899
func (c *OVNNbClient) newACLWithoutCheck(parent, direction, priority, match, action string, tier int, options ...func(acl *ovnnb.ACL)) (*ovnnb.ACL, error) {
1✔
900
        if len(parent) == 0 {
2✔
901
                return nil, errors.New("the port group name or logical switch name is required")
1✔
902
        }
1✔
903

904
        if len(direction) == 0 || len(priority) == 0 || len(match) == 0 || len(action) == 0 {
2✔
905
                return nil, fmt.Errorf("acl 'direction %s' and 'priority %s' and 'match %s' and 'action %s' is required", direction, priority, match, action)
1✔
906
        }
1✔
907

908
        intPriority, _ := strconv.Atoi(priority)
1✔
909

1✔
910
        acl := &ovnnb.ACL{
1✔
911
                UUID:      ovsclient.NamedUUID(),
1✔
912
                Action:    action,
1✔
913
                Direction: direction,
1✔
914
                Match:     match,
1✔
915
                Priority:  intPriority,
1✔
916
                ExternalIDs: map[string]string{
1✔
917
                        aclParentKey: parent,
1✔
918
                },
1✔
919
                Tier: tier,
1✔
920
        }
1✔
921

1✔
922
        for _, option := range options {
2✔
923
                option(acl)
1✔
924
        }
1✔
925

926
        return acl, nil
1✔
927
}
928

929
// createSgRuleACL create security group rule acl
930
func (c *OVNNbClient) newSgRuleACL(sgName, direction string, rule kubeovnv1.SecurityGroupRule) (*ovnnb.ACL, error) {
1✔
931
        ipSuffix := "ip4"
1✔
932
        if rule.IPVersion == "ipv6" {
2✔
933
                ipSuffix = "ip6"
1✔
934
        }
1✔
935

936
        pgName := GetSgPortGroupName(sgName)
1✔
937

1✔
938
        // ingress rule
1✔
939
        srcOrDst, portDirection := "src", "outport"
1✔
940
        if direction == ovnnb.ACLDirectionFromLport { // egress rule
2✔
941
                srcOrDst = "dst"
1✔
942
                portDirection = "inport"
1✔
943
        }
1✔
944

945
        ipKey := ipSuffix + "." + srcOrDst
1✔
946

1✔
947
        /* match all traffic to or from pgName */
1✔
948
        allIPMatch := NewAndACLMatch(
1✔
949
                NewACLMatch(portDirection, "==", "@"+pgName, ""),
1✔
950
                NewACLMatch(ipSuffix, "", "", ""),
1✔
951
        )
1✔
952

1✔
953
        /* allow allowed ip traffic */
1✔
954
        // type address
1✔
955
        allowedIPMatch := NewAndACLMatch(
1✔
956
                allIPMatch,
1✔
957
                NewACLMatch(ipKey, "==", rule.RemoteAddress, ""),
1✔
958
        )
1✔
959

1✔
960
        // type securityGroup
1✔
961
        remotePgName := GetSgV4AssociatedName(rule.RemoteSecurityGroup)
1✔
962
        if rule.IPVersion == "ipv6" {
2✔
963
                remotePgName = GetSgV6AssociatedName(rule.RemoteSecurityGroup)
1✔
964
        }
1✔
965
        if rule.RemoteType == kubeovnv1.SgRemoteTypeSg {
2✔
966
                allowedIPMatch = NewAndACLMatch(
1✔
967
                        allIPMatch,
1✔
968
                        NewACLMatch(ipKey, "==", "$"+remotePgName, ""),
1✔
969
                )
1✔
970
        }
1✔
971

972
        /* allow layer 4 traffic */
973
        // allow all layer 4 traffic
974
        match := allowedIPMatch
1✔
975

1✔
976
        switch rule.Protocol {
1✔
977
        case kubeovnv1.SgProtocolICMP:
1✔
978
                match = NewAndACLMatch(
1✔
979
                        allowedIPMatch,
1✔
980
                        NewACLMatch("icmp4", "", "", ""),
1✔
981
                )
1✔
982
                if ipSuffix == "ip6" {
2✔
983
                        match = NewAndACLMatch(
1✔
984
                                allowedIPMatch,
1✔
985
                                NewACLMatch("icmp6", "", "", ""),
1✔
986
                        )
1✔
987
                }
1✔
988
        case kubeovnv1.SgProtocolTCP, kubeovnv1.SgProtocolUDP:
1✔
989
                match = NewAndACLMatch(
1✔
990
                        allowedIPMatch,
1✔
991
                        NewACLMatch(string(rule.Protocol)+".dst", "<=", strconv.Itoa(rule.PortRangeMin), strconv.Itoa(rule.PortRangeMax)),
1✔
992
                )
1✔
993
        }
994

995
        action := ovnnb.ACLActionDrop
1✔
996
        if rule.Policy == kubeovnv1.SgPolicyAllow {
2✔
997
                action = ovnnb.ACLActionAllowRelated
1✔
998
        }
1✔
999

1000
        highestPriority, _ := strconv.Atoi(util.SecurityGroupHighestPriority)
1✔
1001

1✔
1002
        acl, err := c.newACL(pgName, direction, strconv.Itoa(highestPriority-rule.Priority), match.String(), action, util.NetpolACLTier)
1✔
1003
        if err != nil {
1✔
1004
                klog.Error(err)
×
1005
                return nil, fmt.Errorf("new security group acl for port group %s: %w", pgName, err)
×
1006
        }
×
1007

1008
        return acl, nil
1✔
1009
}
1010

1011
func newNetworkPolicyACLMatch(pgName, asAllowName, asExceptName, protocol, direction string, npp []netv1.NetworkPolicyPort, namedPortMap map[string]*util.NamedPortInfo) []string {
1✔
1012
        ipSuffix := "ip4"
1✔
1013
        if protocol == kubeovnv1.ProtocolIPv6 {
2✔
1014
                ipSuffix = "ip6"
1✔
1015
        }
1✔
1016

1017
        // ingress rule
1018
        srcOrDst, portDirection := "src", "outport"
1✔
1019
        if direction == ovnnb.ACLDirectionFromLport { // egress rule
2✔
1020
                srcOrDst = "dst"
1✔
1021
                portDirection = "inport"
1✔
1022
        }
1✔
1023

1024
        ipKey := ipSuffix + "." + srcOrDst
1✔
1025

1✔
1026
        // match all traffic to or from pgName
1✔
1027
        allIPMatch := NewAndACLMatch(
1✔
1028
                NewACLMatch(portDirection, "==", "@"+pgName, ""),
1✔
1029
                NewACLMatch("ip", "", "", ""),
1✔
1030
        )
1✔
1031

1✔
1032
        allowedIPMatch := NewAndACLMatch(
1✔
1033
                allIPMatch,
1✔
1034
                NewACLMatch(ipKey, "==", "$"+asAllowName, ""),
1✔
1035
                NewACLMatch(ipKey, "!=", "$"+asExceptName, ""),
1✔
1036
        )
1✔
1037

1✔
1038
        matches := make([]string, 0)
1✔
1039

1✔
1040
        // allow allowed ip traffic but except
1✔
1041
        if len(npp) == 0 {
2✔
1042
                return []string{allowedIPMatch.String()}
1✔
1043
        }
1✔
1044

1045
        for _, port := range npp {
2✔
1046
                protocol := strings.ToLower(string(*port.Protocol))
1✔
1047

1✔
1048
                // allow all tcp or udp traffic
1✔
1049
                if port.Port == nil {
2✔
1050
                        allLayer4Match := NewAndACLMatch(
1✔
1051
                                allowedIPMatch,
1✔
1052
                                NewACLMatch(protocol, "", "", ""),
1✔
1053
                        )
1✔
1054

1✔
1055
                        matches = append(matches, allLayer4Match.String())
1✔
1056
                        continue
1✔
1057
                }
1058

1059
                // allow one tcp or udp port traffic
1060
                if port.EndPort == nil {
2✔
1061
                        tcpKey := protocol + ".dst"
1✔
1062

1✔
1063
                        var portID int32
1✔
1064
                        if port.Port.Type == intstr.Int {
2✔
1065
                                portID = port.Port.IntVal
1✔
1066
                        } else if namedPortMap != nil {
3✔
1067
                                _, ok := namedPortMap[port.Port.StrVal]
1✔
1068
                                if !ok {
2✔
1069
                                        // for cyclonus network policy test case 'should allow ingress access on one named port'
1✔
1070
                                        // this case expect all-deny if no named port defined
1✔
1071
                                        klog.Errorf("no named port with name %s found", port.Port.StrVal)
1✔
1072
                                } else {
2✔
1073
                                        portID = namedPortMap[port.Port.StrVal].PortID
1✔
1074
                                }
1✔
1075
                        }
1076

1077
                        oneTCPMatch := NewAndACLMatch(
1✔
1078
                                allowedIPMatch,
1✔
1079
                                NewACLMatch(tcpKey, "==", strconv.Itoa(int(portID)), ""),
1✔
1080
                        )
1✔
1081

1✔
1082
                        matches = append(matches, oneTCPMatch.String())
1✔
1083

1✔
1084
                        continue
1✔
1085
                }
1086

1087
                // allow several tcp or udp port traffic
1088
                tcpKey := protocol + ".dst"
1✔
1089
                severalTCPMatch := NewAndACLMatch(
1✔
1090
                        allowedIPMatch,
1✔
1091
                        NewACLMatch(tcpKey, "<=", strconv.Itoa(int(port.Port.IntVal)), strconv.Itoa(int(*port.EndPort))),
1✔
1092
                )
1✔
1093
                matches = append(matches, severalTCPMatch.String())
1✔
1094
        }
1095

1096
        return matches
1✔
1097
}
1098

1099
// aclFilter filter acls which match the given externalIDs,
1100
// result should include all to-lport and from-lport acls when direction is empty,
1101
// result should include all acls when externalIDs is empty,
1102
// result should include all acls which externalIDs[key] is not empty when externalIDs[key] is ""
1103
// TODO: maybe add other filter conditions(priority or match)
1104
func aclFilter(direction string, externalIDs map[string]string) func(acl *ovnnb.ACL) bool {
1✔
1105
        return func(acl *ovnnb.ACL) bool {
2✔
1106
                if len(acl.ExternalIDs) < len(externalIDs) {
2✔
1107
                        return false
1✔
1108
                }
1✔
1109

1110
                if len(acl.ExternalIDs) != 0 {
2✔
1111
                        for k, v := range externalIDs {
2✔
1112
                                // if only key exist but not value in externalIDs, we should include this lsp,
1✔
1113
                                // it's equal to shell command `ovn-nbctl --columns=xx find acl external_ids:key!=\"\"`
1✔
1114
                                if len(v) == 0 {
2✔
1115
                                        if len(acl.ExternalIDs[k]) == 0 {
1✔
1116
                                                return false
×
1117
                                        }
×
1118
                                } else {
1✔
1119
                                        if acl.ExternalIDs[k] != v {
2✔
1120
                                                return false
1✔
1121
                                        }
1✔
1122
                                }
1123
                        }
1124
                }
1125

1126
                if len(direction) != 0 && acl.Direction != direction {
2✔
1127
                        return false
1✔
1128
                }
1✔
1129

1130
                return true
1✔
1131
        }
1132
}
1133

1134
// CreateAcls return operations which create several acl once
1135
// parentType is 'ls' or 'pg'
1136
func (c *OVNNbClient) CreateAclsOps(parentName, parentType string, acls ...*ovnnb.ACL) ([]ovsdb.Operation, error) {
1✔
1137
        if parentType != portGroupKey && parentType != logicalSwitchKey {
2✔
1138
                return nil, fmt.Errorf("acl parent type must be '%s' or '%s'", portGroupKey, logicalSwitchKey)
1✔
1139
        }
1✔
1140

1141
        if len(acls) == 0 {
2✔
1142
                return nil, nil
1✔
1143
        }
1✔
1144

1145
        models := make([]model.Model, 0, len(acls))
1✔
1146
        aclUUIDs := make([]string, 0, len(acls))
1✔
1147
        for _, acl := range acls {
2✔
1148
                if acl != nil {
2✔
1149
                        models = append(models, model.Model(acl))
1✔
1150
                        aclUUIDs = append(aclUUIDs, acl.UUID)
1✔
1151
                }
1✔
1152
        }
1153

1154
        createAclsOp, err := c.Create(models...)
1✔
1155
        if err != nil {
1✔
1156
                klog.Error(err)
×
1157
                return nil, fmt.Errorf("generate operations for creating acls: %w", err)
×
1158
        }
×
1159

1160
        var aclAddOp []ovsdb.Operation
1✔
1161
        if parentType == portGroupKey { // acl attach to port group
2✔
1162
                aclAddOp, err = c.portGroupUpdateACLOp(parentName, aclUUIDs, ovsdb.MutateOperationInsert)
1✔
1163
                if err != nil {
2✔
1164
                        klog.Error(err)
1✔
1165
                        return nil, fmt.Errorf("generate operations for adding acls to port group %s: %w", parentName, err)
1✔
1166
                }
1✔
1167
        } else { // acl attach to logical switch
1✔
1168
                aclAddOp, err = c.logicalSwitchUpdateACLOp(parentName, aclUUIDs, ovsdb.MutateOperationInsert)
1✔
1169
                if err != nil {
2✔
1170
                        klog.Error(err)
1✔
1171
                        return nil, fmt.Errorf("generate operations for adding acls to logical switch %s: %w", parentName, err)
1✔
1172
                }
1✔
1173
        }
1174

1175
        ops := make([]ovsdb.Operation, 0, len(createAclsOp)+len(aclAddOp))
1✔
1176
        ops = append(ops, createAclsOp...)
1✔
1177
        ops = append(ops, aclAddOp...)
1✔
1178

1✔
1179
        return ops, nil
1✔
1180
}
1181

1182
// DeleteAcls return operation which delete several acl once,
1183
// delete to-lport and from-lport direction acl when direction is empty, otherwise one-way
1184
// parentType is 'ls' or 'pg'
1185
func (c *OVNNbClient) DeleteAclsOps(parentName, parentType, direction string, externalIDs map[string]string) ([]ovsdb.Operation, error) {
1✔
1186
        if parentName == "" {
2✔
1187
                return nil, errors.New("the port group name or logical switch name is required")
1✔
1188
        }
1✔
1189

1190
        if externalIDs == nil {
2✔
1191
                externalIDs = make(map[string]string)
1✔
1192
        }
1✔
1193

1194
        externalIDs[aclParentKey] = parentName
1✔
1195

1✔
1196
        /* delete acls from port group or logical switch */
1✔
1197
        acls, err := c.ListAcls(direction, externalIDs)
1✔
1198
        if err != nil {
1✔
1199
                klog.Error(err)
×
1200
                return nil, fmt.Errorf("list type %s %s acls: %w", parentType, parentName, err)
×
1201
        }
×
1202

1203
        aclUUIDs := make([]string, 0, len(acls))
1✔
1204
        for _, acl := range acls {
2✔
1205
                aclUUIDs = append(aclUUIDs, acl.UUID)
1✔
1206
        }
1✔
1207

1208
        // the acls column has a strong reference to the ACL table, so there is no need to delete the ACL
1209
        var removeACLOp []ovsdb.Operation
1✔
1210
        if parentType == portGroupKey { // remove acl from port group
2✔
1211
                removeACLOp, err = c.portGroupUpdateACLOp(parentName, aclUUIDs, ovsdb.MutateOperationDelete)
1✔
1212
                if err != nil {
1✔
1213
                        klog.Error(err)
×
1214
                        return nil, fmt.Errorf("generate operations for deleting acls from port group %s: %w", parentName, err)
×
1215
                }
×
1216
        } else { // remove acl from logical switch
1✔
1217
                removeACLOp, err = c.logicalSwitchUpdateACLOp(parentName, aclUUIDs, ovsdb.MutateOperationDelete)
1✔
1218
                if err != nil {
1✔
1219
                        klog.Error(err)
×
1220
                        return nil, fmt.Errorf("generate operations for deleting acls from logical switch %s: %w", parentName, err)
×
1221
                }
×
1222
        }
1223

1224
        return removeACLOp, nil
1✔
1225
}
1226

1227
// sgRuleNoACL check if security group rule has acl
1228
func (c *OVNNbClient) sgRuleNoACL(sgName, direction string, rule kubeovnv1.SecurityGroupRule) (bool, error) {
1✔
1229
        ipSuffix := "ip4"
1✔
1230
        if rule.IPVersion == "ipv6" {
2✔
1231
                ipSuffix = "ip6"
1✔
1232
        }
1✔
1233

1234
        pgName := GetSgPortGroupName(sgName)
1✔
1235

1✔
1236
        // ingress rule
1✔
1237
        srcOrDst, portDirection := "src", "outport"
1✔
1238
        if direction == ovnnb.ACLDirectionFromLport { // egress rule
2✔
1239
                srcOrDst = "dst"
1✔
1240
                portDirection = "inport"
1✔
1241
        }
1✔
1242

1243
        ipKey := ipSuffix + "." + srcOrDst
1✔
1244

1✔
1245
        /* match all traffic to or from pgName */
1✔
1246
        allIPMatch := NewAndACLMatch(
1✔
1247
                NewACLMatch(portDirection, "==", "@"+pgName, ""),
1✔
1248
                NewACLMatch(ipSuffix, "", "", ""),
1✔
1249
        )
1✔
1250

1✔
1251
        /* allow allowed ip traffic */
1✔
1252
        // type address
1✔
1253
        allowedIPMatch := NewAndACLMatch(
1✔
1254
                allIPMatch,
1✔
1255
                NewACLMatch(ipKey, "==", rule.RemoteAddress, ""),
1✔
1256
        )
1✔
1257

1✔
1258
        // type securityGroup
1✔
1259
        remotePgName := GetSgV4AssociatedName(rule.RemoteSecurityGroup)
1✔
1260
        if rule.IPVersion == "ipv6" {
2✔
1261
                remotePgName = GetSgV6AssociatedName(rule.RemoteSecurityGroup)
1✔
1262
        }
1✔
1263
        if rule.RemoteType == kubeovnv1.SgRemoteTypeSg {
2✔
1264
                allowedIPMatch = NewAndACLMatch(
1✔
1265
                        allIPMatch,
1✔
1266
                        NewACLMatch(ipKey, "==", "$"+remotePgName, ""),
1✔
1267
                )
1✔
1268
        }
1✔
1269

1270
        /* allow layer 4 traffic */
1271
        // allow all layer 4 traffic
1272
        match := allowedIPMatch
1✔
1273

1✔
1274
        switch rule.Protocol {
1✔
1275
        case kubeovnv1.SgProtocolICMP:
1✔
1276
                match = NewAndACLMatch(
1✔
1277
                        allowedIPMatch,
1✔
1278
                        NewACLMatch("icmp4", "", "", ""),
1✔
1279
                )
1✔
1280
                if ipSuffix == "ip6" {
1✔
1281
                        match = NewAndACLMatch(
×
1282
                                allowedIPMatch,
×
1283
                                NewACLMatch("icmp6", "", "", ""),
×
1284
                        )
×
1285
                }
×
1286
        case kubeovnv1.SgProtocolTCP, kubeovnv1.SgProtocolUDP:
1✔
1287
                match = NewAndACLMatch(
1✔
1288
                        allowedIPMatch,
1✔
1289
                        NewACLMatch(string(rule.Protocol)+".dst", "<=", strconv.Itoa(rule.PortRangeMin), strconv.Itoa(rule.PortRangeMax)),
1✔
1290
                )
1✔
1291
        }
1292

1293
        securityGroupHighestPriority, _ := strconv.Atoi(util.SecurityGroupHighestPriority)
1✔
1294
        priority := securityGroupHighestPriority - rule.Priority
1✔
1295
        exists, err := c.ACLExists(pgName, direction, strconv.Itoa(priority), match.String())
1✔
1296
        if err != nil {
1✔
1297
                err = fmt.Errorf("failed to check acl rule for security group %s: %w", sgName, err)
×
1298
                klog.Error(err)
×
1299
                return false, err
×
1300
        }
×
1301

1302
        // sg rule no acl, need to sync
1303
        if !exists {
2✔
1304
                return true, nil
1✔
1305
        }
1✔
1306
        return false, nil
1✔
1307
}
1308

1309
// SGLostACL check if security group lost an acl
1310
func (c *OVNNbClient) SGLostACL(sg *kubeovnv1.SecurityGroup) (bool, error) {
1✔
1311
        ingressRules := sg.Spec.IngressRules
1✔
1312
        for _, rule := range ingressRules {
2✔
1313
                no, err := c.sgRuleNoACL(sg.Name, ovnnb.ACLDirectionToLport, rule)
1✔
1314
                if err != nil {
1✔
1315
                        klog.Error(err)
×
1316
                        return false, err
×
1317
                }
×
1318
                if no {
2✔
1319
                        klog.Infof("security group %s lost ingress rule: %v", sg.Name, rule)
1✔
1320
                        return true, nil
1✔
1321
                }
1✔
1322
        }
1323
        egressRules := sg.Spec.EgressRules
1✔
1324
        for _, rule := range egressRules {
2✔
1325
                no, err := c.sgRuleNoACL(sg.Name, ovnnb.ACLDirectionFromLport, rule)
1✔
1326
                if err != nil {
1✔
1327
                        klog.Error(err)
×
1328
                        return false, err
×
1329
                }
×
1330
                if no {
2✔
1331
                        klog.Infof("security group %s lost egress rule: %v", sg.Name, rule)
1✔
1332
                        return true, nil
1✔
1333
                }
1✔
1334
        }
1335
        return false, nil
1✔
1336
}
1337

1338
// UpdateAnpRuleACLOps return operation that creates an ingress/egress ACL
1339
func (c *OVNNbClient) UpdateAnpRuleACLOps(pgName, asName, protocol, aclName string, priority int, aclAction ovnnb.ACLAction, logACLActions []ovnnb.ACLAction, rulePorts []v1alpha1.AdminNetworkPolicyPort, isIngress, isBanp bool) ([]ovsdb.Operation, error) {
1✔
1340
        acls := make([]*ovnnb.ACL, 0, 10)
1✔
1341

1✔
1342
        options := func(acl *ovnnb.ACL) {
2✔
1343
                setACLName(acl, aclName)
1✔
1344

1✔
1345
                if acl.ExternalIDs == nil {
1✔
1346
                        acl.ExternalIDs = make(map[string]string)
×
1347
                }
×
1348
                acl.ExternalIDs[aclParentKey] = pgName
1✔
1349

1✔
1350
                if acl.Options == nil {
2✔
1351
                        acl.Options = make(map[string]string)
1✔
1352
                }
1✔
1353
                acl.Options["apply-after-lb"] = "true"
1✔
1354

1✔
1355
                if slices.Contains(logACLActions, aclAction) {
2✔
1356
                        acl.Log = true
1✔
1357
                        if aclAction == ovnnb.ACLActionDrop {
2✔
1358
                                acl.Severity = ptr.To(ovnnb.ACLSeverityWarning)
1✔
1359
                        }
1✔
1360
                }
1361
        }
1362

1363
        var direction ovnnb.ACLDirection
1✔
1364
        if isIngress {
2✔
1365
                direction = ovnnb.ACLDirectionToLport
1✔
1366
        } else {
2✔
1367
                direction = ovnnb.ACLDirectionFromLport
1✔
1368
        }
1✔
1369

1370
        var tier int
1✔
1371
        if isBanp {
2✔
1372
                tier = util.BanpACLTier
1✔
1373
        } else {
2✔
1374
                tier = util.AnpACLTier
1✔
1375
        }
1✔
1376

1377
        matches := newAnpACLMatch(pgName, asName, protocol, direction, rulePorts)
1✔
1378
        for _, m := range matches {
2✔
1379
                strPriority := strconv.Itoa(priority)
1✔
1380
                setACL, err := c.newACLWithoutCheck(pgName, direction, strPriority, m, aclAction, tier, options)
1✔
1381
                if err != nil {
1✔
1382
                        klog.Error(err)
×
1383
                        return nil, fmt.Errorf("new ingress acl for port group %s: %w", pgName, err)
×
1384
                }
×
1385

1386
                acls = append(acls, setACL)
1✔
1387
        }
1388

1389
        ops, err := c.CreateAclsOps(pgName, portGroupKey, acls...)
1✔
1390
        if err != nil {
1✔
1391
                klog.Error(err)
×
1392
                return nil, err
×
1393
        }
×
1394

1395
        return ops, nil
1✔
1396
}
1397

1398
func newAnpACLMatch(pgName, asName, protocol, direction string, rulePorts []v1alpha1.AdminNetworkPolicyPort) []string {
1✔
1399
        ipSuffix := "ip4"
1✔
1400
        if protocol == kubeovnv1.ProtocolIPv6 {
2✔
1401
                ipSuffix = "ip6"
1✔
1402
        }
1✔
1403

1404
        // ingress rule
1405
        srcOrDst, portDirection := "src", "outport"
1✔
1406
        if direction == ovnnb.ACLDirectionFromLport { // egress rule
2✔
1407
                srcOrDst = "dst"
1✔
1408
                portDirection = "inport"
1✔
1409
        }
1✔
1410

1411
        ipKey := ipSuffix + "." + srcOrDst
1✔
1412

1✔
1413
        // match all traffic to or from pgName
1✔
1414
        allIPMatch := NewAndACLMatch(
1✔
1415
                NewACLMatch(portDirection, "==", "@"+pgName, ""),
1✔
1416
                NewACLMatch("ip", "", "", ""),
1✔
1417
        )
1✔
1418

1✔
1419
        selectIPMatch := NewAndACLMatch(
1✔
1420
                allIPMatch,
1✔
1421
                NewACLMatch(ipKey, "==", "$"+asName, ""),
1✔
1422
        )
1✔
1423
        if len(rulePorts) == 0 {
2✔
1424
                return []string{selectIPMatch.String()}
1✔
1425
        }
1✔
1426

1427
        matches := make([]string, 0, 10)
1✔
1428
        for _, port := range rulePorts {
2✔
1429
                // Exactly one field must be set.
1✔
1430
                // Do not support NamedPort now
1✔
1431
                switch {
1✔
1432
                case port.PortNumber != nil:
1✔
1433
                        protocol := strings.ToLower(string(port.PortNumber.Protocol))
1✔
1434
                        protocolKey := protocol + ".dst"
1✔
1435

1✔
1436
                        oneMatch := NewAndACLMatch(
1✔
1437
                                selectIPMatch,
1✔
1438
                                NewACLMatch(protocolKey, "==", strconv.Itoa(int(port.PortNumber.Port)), ""),
1✔
1439
                        )
1✔
1440
                        matches = append(matches, oneMatch.String())
1✔
1441
                case port.PortRange != nil:
1✔
1442
                        protocol := strings.ToLower(string(port.PortRange.Protocol))
1✔
1443
                        protocolKey := protocol + ".dst"
1✔
1444

1✔
1445
                        severalMatch := NewAndACLMatch(
1✔
1446
                                selectIPMatch,
1✔
1447
                                NewACLMatch(protocolKey, "<=", strconv.Itoa(int(port.PortRange.Start)), strconv.Itoa(int(port.PortRange.End))),
1✔
1448
                        )
1✔
1449
                        matches = append(matches, severalMatch.String())
1✔
1450
                default:
×
1451
                        klog.Errorf("failed to check port for anp ingress rule, pg %s, as %s", pgName, asName)
×
1452
                }
1453
        }
1454
        return matches
1✔
1455
}
1456

1457
func (c *OVNNbClient) MigrateACLTier() error {
×
1458
        ctx, cancel := context.WithTimeout(context.Background(), c.Timeout)
×
1459
        defer cancel()
×
1460

×
1461
        var aclList []ovnnb.ACL
×
1462
        if err := c.ovsDbClient.WhereCache(func(acl *ovnnb.ACL) bool { return acl.Tier == 0 }).List(ctx, &aclList); err != nil {
×
1463
                err = fmt.Errorf("failed to list acls with tier 0: %w", err)
×
1464
                klog.Error(err)
×
1465
                return err
×
1466
        }
×
1467

1468
        ops := make([]ovsdb.Operation, 0, len(aclList))
×
1469
        for _, acl := range aclList {
×
1470
                acl.Tier = util.NetpolACLTier
×
1471
                op, err := c.Where(&acl).Update(&acl, &acl.Tier)
×
1472
                if err != nil {
×
1473
                        klog.Error(err)
×
1474
                        return fmt.Errorf("failed to generate operations for updating acl %s tier: %w", acl.UUID, err)
×
1475
                }
×
1476
                ops = append(ops, op...)
×
1477
        }
1478
        if len(ops) == 0 {
×
1479
                return nil
×
1480
        }
×
1481

1482
        if err := c.Transact("acl-migrate-tier", ops); err != nil {
×
1483
                klog.Error(err)
×
1484
                return fmt.Errorf("failed to migrate acl tier: %w", err)
×
1485
        }
×
1486

1487
        return nil
×
1488
}
1489

NEW
1490
func (c *OVNNbClient) CleanNoParentKeyAcls() error {
×
NEW
1491
        ctx, cancel := context.WithTimeout(context.Background(), c.Timeout)
×
NEW
1492
        defer cancel()
×
NEW
1493

×
NEW
1494
        var aclList []ovnnb.ACL
×
NEW
1495
        if err := c.ovsDbClient.WhereCache(func(acl *ovnnb.ACL) bool {
×
NEW
1496
                _, ok := acl.ExternalIDs[aclParentKey]
×
NEW
1497
                return !ok
×
NEW
1498
        }).List(ctx, &aclList); err != nil {
×
NEW
1499
                err = fmt.Errorf("failed to list acls without parent: %w", err)
×
NEW
1500
                klog.Error(err)
×
NEW
1501
                return err
×
NEW
1502
        }
×
1503

NEW
1504
        ops := make([]ovsdb.Operation, 0, len(aclList))
×
NEW
1505
        for _, acl := range aclList {
×
NEW
1506
                var portGroups []ovnnb.PortGroup
×
NEW
1507
                if err := c.ovsDbClient.WhereCache(func(pg *ovnnb.PortGroup) bool {
×
NEW
1508
                        for _, aclUUID := range pg.ACLs {
×
NEW
1509
                                if aclUUID == acl.UUID {
×
NEW
1510
                                        return true
×
NEW
1511
                                }
×
1512
                        }
NEW
1513
                        return false
×
NEW
1514
                }).List(ctx, &portGroups); err == nil {
×
NEW
1515
                        for _, pg := range portGroups {
×
NEW
1516
                                op, err := c.portGroupUpdateACLOp(pg.Name, []string{acl.UUID}, ovsdb.MutateOperationDelete)
×
NEW
1517
                                if err == nil {
×
NEW
1518
                                        ops = append(ops, op...)
×
NEW
1519
                                }
×
1520
                        }
1521
                }
NEW
1522
                var logicalSwitches []ovnnb.LogicalSwitch
×
NEW
1523
                if err := c.ovsDbClient.WhereCache(func(ls *ovnnb.LogicalSwitch) bool {
×
NEW
1524
                        for _, aclUUID := range ls.ACLs {
×
NEW
1525
                                if aclUUID == acl.UUID {
×
NEW
1526
                                        return true
×
NEW
1527
                                }
×
1528
                        }
NEW
1529
                        return false
×
NEW
1530
                }).List(ctx, &logicalSwitches); err == nil {
×
NEW
1531
                        for _, ls := range logicalSwitches {
×
NEW
1532
                                op, err := c.logicalSwitchUpdateACLOp(ls.Name, []string{acl.UUID}, ovsdb.MutateOperationDelete)
×
NEW
1533
                                if err == nil {
×
NEW
1534
                                        ops = append(ops, op...)
×
NEW
1535
                                }
×
1536
                        }
1537
                }
NEW
1538
                delOp, err := c.Where(&acl).Delete()
×
NEW
1539
                if err == nil {
×
NEW
1540
                        ops = append(ops, delOp...)
×
NEW
1541
                }
×
1542
        }
NEW
1543
        if len(ops) == 0 {
×
NEW
UNCOV
1544
                return nil
×
NEW
UNCOV
1545
        }
×
1546

NEW
UNCOV
1547
        if err := c.Transact("acl-clean-no-parent", ops); err != nil {
×
NEW
UNCOV
1548
                klog.Error(err)
×
NEW
UNCOV
1549
                return fmt.Errorf("failed to clean acls without parent: %w", err)
×
NEW
UNCOV
1550
        }
×
1551

NEW
UNCOV
1552
        return nil
×
1553
}
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