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

kubeovn / kube-ovn / 22522896888

28 Feb 2026 02:47PM UTC coverage: 22.949% (+0.06%) from 22.886%
22522896888

push

github

oilbeater
fix: prevent subnet from getting permanently stuck when VLAN is not ready (#6352)

Fix two bugs that combine to cause underlay subnets to get permanently
stuck during controller startup when the VLAN is created after the subnet.

Bug 1: In handleAddOrUpdateSubnet, variable shadowing (err :=) and
overwriting (err =) in the VLAN/subnet validation error paths caused
patchSubnetStatus success to zero out the original validation error.
The handler returned nil, making the work queue forget the item instead
of retrying it. Fix by using a separate patchErr variable for the patch
call and using = instead of := for the error wrapping.

Bug 2: handleAddVlan did not re-enqueue subnets that reference the
newly created VLAN. Once a subnet's validation failed and was forgotten
by the queue, no event would trigger it to be reprocessed. Fix by
iterating over subnets at the end of handleAddVlan and adding those
referencing the VLAN back to the addOrUpdateSubnetQueue.

Signed-off-by: Mengxin Liu <liumengxinfly@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit e9b65ce70)

2 of 11 new or added lines in 2 files covered. (18.18%)

3 existing lines in 2 files now uncovered.

12395 of 54011 relevant lines covered (22.95%)

0.27 hits per line

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

7.57
/pkg/controller/subnet.go
1
package controller
2

3
import (
4
        "context"
5
        "errors"
6
        "fmt"
7
        "maps"
8
        "net"
9
        "reflect"
10
        "slices"
11
        "sort"
12
        "strings"
13

14
        "github.com/ovn-kubernetes/libovsdb/ovsdb"
15
        v1 "k8s.io/api/core/v1"
16
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
17
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
18
        "k8s.io/apimachinery/pkg/labels"
19
        "k8s.io/apimachinery/pkg/types"
20
        "k8s.io/client-go/tools/cache"
21
        "k8s.io/klog/v2"
22
        "sigs.k8s.io/controller-runtime/pkg/client"
23
        "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
24

25
        kubeovnv1 "github.com/kubeovn/kube-ovn/pkg/apis/kubeovn/v1"
26
        "github.com/kubeovn/kube-ovn/pkg/ipam"
27
        "github.com/kubeovn/kube-ovn/pkg/ovs"
28
        "github.com/kubeovn/kube-ovn/pkg/ovsdb/ovnnb"
29
        "github.com/kubeovn/kube-ovn/pkg/util"
30
)
31

32
func (c *Controller) enqueueAddSubnet(obj any) {
×
33
        key := cache.MetaObjectToName(obj.(*kubeovnv1.Subnet)).String()
×
34
        klog.V(3).Infof("enqueue add subnet %s", key)
×
35
        c.addOrUpdateSubnetQueue.Add(key)
×
36
}
×
37

38
func (c *Controller) enqueueDeleteSubnet(obj any) {
×
39
        var subnet *kubeovnv1.Subnet
×
40
        switch t := obj.(type) {
×
41
        case *kubeovnv1.Subnet:
×
42
                subnet = t
×
43
        case cache.DeletedFinalStateUnknown:
×
44
                s, ok := t.Obj.(*kubeovnv1.Subnet)
×
45
                if !ok {
×
46
                        klog.Warningf("unexpected object type: %T", t.Obj)
×
47
                        return
×
48
                }
×
49
                subnet = s
×
50
        default:
×
51
                klog.Warningf("unexpected type: %T", obj)
×
52
                return
×
53
        }
54

55
        klog.V(3).Infof("enqueue delete subnet %s", subnet.Name)
×
56
        c.deleteSubnetQueue.Add(subnet)
×
57
}
58

59
func readyToRemoveFinalizer(subnet *kubeovnv1.Subnet) bool {
×
60
        if subnet.DeletionTimestamp.IsZero() {
×
61
                return false
×
62
        }
×
63

64
        if subnet.Status.V4UsingIPs+subnet.Status.V6UsingIPs == 0 {
×
65
                return true
×
66
        }
×
67

68
        if subnet.Status.U2OInterconnectionIP != "" {
×
69
                return int(subnet.Status.V4UsingIPs+subnet.Status.V6UsingIPs) == len(strings.Split(subnet.Status.U2OInterconnectionIP, ","))
×
70
        }
×
71

72
        return false
×
73
}
74

75
func (c *Controller) enqueueUpdateSubnet(oldObj, newObj any) {
×
76
        oldSubnet := oldObj.(*kubeovnv1.Subnet)
×
77
        newSubnet := newObj.(*kubeovnv1.Subnet)
×
78
        key := cache.MetaObjectToName(newSubnet).String()
×
79

×
80
        if readyToRemoveFinalizer(newSubnet) {
×
81
                klog.Infof("enqueue update subnet %s triggered by ready to remove finalizer", key)
×
82
                c.addOrUpdateSubnetQueue.Add(key)
×
83
                return
×
84
        }
×
85

86
        if !reflect.DeepEqual(oldSubnet.Spec, newSubnet.Spec) {
×
87
                klog.V(3).Infof("enqueue update subnet %s", key)
×
88

×
89
                if oldSubnet.Spec.U2OInterconnection != newSubnet.Spec.U2OInterconnection {
×
90
                        klog.Infof("enqueue update vpc %s to update always-lear-from-arp option triggered by u2o interconnection change of subnet %s", newSubnet.Spec.Vpc, key)
×
91
                        c.addOrUpdateVpcQueue.Add(newSubnet.Spec.Vpc)
×
92
                }
×
93

94
                if oldSubnet.Spec.GatewayType != newSubnet.Spec.GatewayType {
×
95
                        c.recorder.Eventf(newSubnet, v1.EventTypeNormal, "SubnetGatewayTypeChanged",
×
96
                                "subnet gateway type changes from %q to %q", oldSubnet.Spec.GatewayType, newSubnet.Spec.GatewayType)
×
97
                }
×
98

99
                if oldSubnet.Spec.GatewayNode != newSubnet.Spec.GatewayNode {
×
100
                        c.recorder.Eventf(newSubnet, v1.EventTypeNormal, "SubnetGatewayNodeChanged",
×
101
                                "gateway node changes from %q to %q", oldSubnet.Spec.GatewayNode, newSubnet.Spec.GatewayNode)
×
102
                }
×
103

104
                c.addOrUpdateSubnetQueue.Add(key)
×
105
        }
106
}
107

108
func (c *Controller) formatSubnet(subnet *kubeovnv1.Subnet) (*kubeovnv1.Subnet, error) {
1✔
109
        newSubnet := subnet.DeepCopy()
1✔
110
        if err := formatAddress(newSubnet); err != nil {
1✔
111
                klog.Error(err)
×
112
                return nil, err
×
113
        }
×
114

115
        if newSubnet.Spec.Provider == "" {
2✔
116
                newSubnet.Spec.Provider = util.OvnProvider
1✔
117
        }
1✔
118

119
        if newSubnet.Spec.Vpc == "" {
2✔
120
                if isOvnSubnet(newSubnet) {
2✔
121
                        newSubnet.Spec.Vpc = c.config.ClusterRouter
1✔
122
                }
1✔
123
        }
124

125
        if newSubnet.Spec.Vpc == c.config.ClusterRouter && newSubnet.Name != c.config.NodeSwitch {
2✔
126
                // Some format only needed in the default VPC
1✔
127
                if newSubnet.Spec.GatewayType == "" {
2✔
128
                        newSubnet.Spec.GatewayType = kubeovnv1.GWDistributedType
1✔
129
                }
1✔
130
                if newSubnet.Spec.Default && newSubnet.Name != c.config.DefaultLogicalSwitch {
1✔
131
                        newSubnet.Spec.Default = false
×
132
                }
×
133
        }
134

135
        if newSubnet.Spec.EnableLb == nil && newSubnet.Name != c.config.NodeSwitch {
2✔
136
                newSubnet.Spec.EnableLb = &c.config.EnableLb
1✔
137
        }
1✔
138
        // set join subnet Spec.EnableLb to nil
139
        if newSubnet.Spec.EnableLb != nil && newSubnet.Name == c.config.NodeSwitch {
1✔
140
                newSubnet.Spec.EnableLb = nil
×
141
        }
×
142

143
        if newSubnet.Spec.U2OInterconnectionIP != "" && !newSubnet.Spec.U2OInterconnection {
1✔
144
                newSubnet.Spec.U2OInterconnectionIP = ""
×
145
        }
×
146

147
        if newSubnet.Spec.Vlan == "" && newSubnet.Spec.U2OInterconnection {
1✔
148
                newSubnet.Spec.U2OInterconnection = false
×
149
        }
×
150

151
        changed := !reflect.DeepEqual(subnet, newSubnet)
1✔
152
        klog.Infof("format subnet %v, changed %v", subnet.Name, changed)
1✔
153
        if changed {
2✔
154
                ret, err := c.config.KubeOvnClient.KubeovnV1().Subnets().Update(context.Background(), newSubnet, metav1.UpdateOptions{})
1✔
155
                if err != nil {
1✔
156
                        klog.Errorf("failed to update subnet %s, %v", subnet.Name, err)
×
157
                        return nil, err
×
158
                }
×
159
                return ret, nil
1✔
160
        }
161
        return subnet, nil
1✔
162
}
163

164
func (c *Controller) validateSubnetVlan(subnet *kubeovnv1.Subnet) error {
1✔
165
        if subnet.Spec.Vlan == "" {
1✔
166
                return nil
×
167
        }
×
168

169
        vlan, err := c.vlansLister.Get(subnet.Spec.Vlan)
1✔
170
        if err != nil {
2✔
171
                err = fmt.Errorf("failed to get vlan %s: %w", subnet.Spec.Vlan, err)
1✔
172
                klog.Error(err)
1✔
173
                return err
1✔
174
        }
1✔
175

176
        if vlan.Status.Conflict {
×
177
                err = fmt.Errorf("subnet %s has invalid conflict vlan %s", subnet.Name, vlan.Name)
×
178
                klog.Error(err)
×
179
                return err
×
180
        }
×
181
        return nil
×
182
}
183

184
func formatAddress(subnet *kubeovnv1.Subnet) error {
1✔
185
        if err := formatCIDR(subnet); err != nil {
1✔
186
                klog.Error(err)
×
187
                return err
×
188
        }
×
189

190
        if err := formatGateway(subnet); err != nil {
1✔
191
                klog.Error(err)
×
192
                return err
×
193
        }
×
194

195
        formatExcludeIPs(subnet)
1✔
196

1✔
197
        subnet.Spec.Protocol = util.CheckProtocol(subnet.Spec.CIDRBlock)
1✔
198

1✔
199
        return nil
1✔
200
}
201

202
func formatCIDR(subnet *kubeovnv1.Subnet) error {
1✔
203
        var cidrBlocks []string
1✔
204

1✔
205
        for cidr := range strings.SplitSeq(subnet.Spec.CIDRBlock, ",") {
2✔
206
                _, ipNet, err := net.ParseCIDR(cidr)
1✔
207
                if err != nil {
1✔
208
                        klog.Error(err)
×
209
                        return fmt.Errorf("subnet %s cidr %s is invalid", subnet.Name, cidr)
×
210
                }
×
211
                cidrBlocks = append(cidrBlocks, ipNet.String())
1✔
212
        }
213
        subnet.Spec.CIDRBlock = strings.Join(cidrBlocks, ",")
1✔
214
        return nil
1✔
215
}
216

217
func formatGateway(subnet *kubeovnv1.Subnet) error {
1✔
218
        var (
1✔
219
                gw  string
1✔
220
                err error
1✔
221
        )
1✔
222

1✔
223
        switch {
1✔
224
        case subnet.Spec.Gateway == "":
1✔
225
                gw, err = util.GetGwByCidr(subnet.Spec.CIDRBlock)
1✔
226
        case subnet.Spec.Protocol == kubeovnv1.ProtocolDual && util.CheckProtocol(subnet.Spec.Gateway) != util.CheckProtocol(subnet.Spec.CIDRBlock):
×
227
                gw, err = util.AppendGwByCidr(subnet.Spec.Gateway, subnet.Spec.CIDRBlock)
×
228
        default:
1✔
229
                gw = subnet.Spec.Gateway
1✔
230
        }
231
        if err != nil {
1✔
232
                klog.Error(err)
×
233
                return err
×
234
        }
×
235
        subnet.Spec.Gateway = gw
1✔
236

1✔
237
        return nil
1✔
238
}
239

240
func formatExcludeIPs(subnet *kubeovnv1.Subnet) {
1✔
241
        var excludeIPs []string
1✔
242
        excludeIPs = append(excludeIPs, strings.Split(subnet.Spec.Gateway, ",")...)
1✔
243
        sort.Strings(excludeIPs)
1✔
244
        if len(subnet.Spec.ExcludeIps) == 0 {
2✔
245
                subnet.Spec.ExcludeIps = excludeIPs
1✔
246
        } else {
2✔
247
                formatExcludeIPRanges(subnet)
1✔
248
                for _, gw := range excludeIPs {
2✔
249
                        gwExists := false
1✔
250
                        for _, excludeIP := range subnet.Spec.ExcludeIps {
2✔
251
                                if util.ContainsIPs(excludeIP, gw) {
2✔
252
                                        gwExists = true
1✔
253
                                        break
1✔
254
                                }
255
                        }
256
                        if !gwExists {
1✔
257
                                subnet.Spec.ExcludeIps = append(subnet.Spec.ExcludeIps, gw)
×
258
                                sort.Strings(subnet.Spec.ExcludeIps)
×
259
                        }
×
260
                }
261
        }
262
}
263

264
func (c *Controller) syncSubnetFinalizer(cl client.Client) error {
×
265
        // migrate depreciated finalizer to new finalizer
×
266
        subnets := &kubeovnv1.SubnetList{}
×
267
        return migrateFinalizers(cl, subnets, func(i int) (client.Object, client.Object) {
×
268
                if i < 0 || i >= len(subnets.Items) {
×
269
                        return nil, nil
×
270
                }
×
271
                return subnets.Items[i].DeepCopy(), subnets.Items[i].DeepCopy()
×
272
        })
273
}
274

275
func (c *Controller) handleSubnetFinalizer(subnet *kubeovnv1.Subnet) (*kubeovnv1.Subnet, bool, error) {
×
276
        if subnet.DeletionTimestamp.IsZero() && !slices.Contains(subnet.GetFinalizers(), util.KubeOVNControllerFinalizer) {
×
277
                newSubnet := subnet.DeepCopy()
×
278
                controllerutil.RemoveFinalizer(newSubnet, util.DepreciatedFinalizerName)
×
279
                controllerutil.AddFinalizer(newSubnet, util.KubeOVNControllerFinalizer)
×
280
                patch, err := util.GenerateMergePatchPayload(subnet, newSubnet)
×
281
                if err != nil {
×
282
                        klog.Errorf("failed to generate patch payload for subnet '%s', %v", subnet.Name, err)
×
283
                        return newSubnet, false, err
×
284
                }
×
285
                patchSubnet, err := c.config.KubeOvnClient.KubeovnV1().Subnets().Patch(context.Background(), subnet.Name, types.MergePatchType, patch, metav1.PatchOptions{}, "")
×
286
                if err != nil {
×
287
                        klog.Errorf("failed to add finalizer to subnet %s, %v", subnet.Name, err)
×
288
                        return patchSubnet, false, err
×
289
                }
×
290

291
                return patchSubnet, false, nil
×
292
        }
293

294
        usingIPs := subnet.Status.V4UsingIPs
×
295
        if util.CheckProtocol(subnet.Spec.CIDRBlock) == kubeovnv1.ProtocolIPv6 {
×
296
                usingIPs = subnet.Status.V6UsingIPs
×
297
        }
×
298

299
        u2oInterconnIP := subnet.Status.U2OInterconnectionIP
×
300
        if !subnet.DeletionTimestamp.IsZero() && (usingIPs == 0 || (usingIPs == 1 && u2oInterconnIP != "")) {
×
301
                newSubnet := subnet.DeepCopy()
×
302
                controllerutil.RemoveFinalizer(newSubnet, util.DepreciatedFinalizerName)
×
303
                controllerutil.RemoveFinalizer(newSubnet, util.KubeOVNControllerFinalizer)
×
304
                patch, err := util.GenerateMergePatchPayload(subnet, newSubnet)
×
305
                if err != nil {
×
306
                        klog.Errorf("failed to generate patch payload for subnet '%s', %v", subnet.Name, err)
×
307
                        return newSubnet, false, err
×
308
                }
×
309
                if _, err := c.config.KubeOvnClient.KubeovnV1().Subnets().Patch(context.Background(), subnet.Name,
×
310
                        types.MergePatchType, patch, metav1.PatchOptions{}, ""); err != nil {
×
311
                        klog.Errorf("failed to remove finalizer from subnet %s, %v", subnet.Name, err)
×
312
                        return newSubnet, false, err
×
313
                }
×
314
                return newSubnet, true, nil
×
315
        }
316
        return subnet, false, nil
×
317
}
318

319
func (c *Controller) validateVpcBySubnet(subnet *kubeovnv1.Subnet) (*kubeovnv1.Vpc, error) {
×
320
        vpc, err := c.vpcsLister.Get(subnet.Spec.Vpc)
×
321
        if err != nil {
×
322
                klog.Errorf("failed to get subnet's vpc '%s', %v", subnet.Spec.Vpc, err)
×
323
                return vpc, err
×
324
        }
×
325

326
        if !vpc.Status.Standby {
×
327
                err = fmt.Errorf("the vpc '%s' not standby yet", vpc.Name)
×
328
                klog.Error(err)
×
329
                return vpc, err
×
330
        }
×
331

332
        if !vpc.Status.Default {
×
333
                for _, ns := range subnet.Spec.Namespaces {
×
334
                        if !slices.Contains(vpc.Spec.Namespaces, ns) {
×
335
                                err = fmt.Errorf("namespace '%s' is out of range to custom vpc '%s'", ns, vpc.Name)
×
336
                                klog.Error(err)
×
337
                                return vpc, err
×
338
                        }
×
339
                }
340
        } else {
×
341
                vpcs, err := c.vpcsLister.List(labels.Everything())
×
342
                if err != nil {
×
343
                        klog.Errorf("failed to list vpc, %v", err)
×
344
                        return vpc, err
×
345
                }
×
346

347
                for _, vpc := range vpcs {
×
348
                        if subnet.Spec.Vpc != vpc.Name &&
×
349
                                !vpc.Status.Default && util.IsStringsOverlap(vpc.Spec.Namespaces, subnet.Spec.Namespaces) {
×
350
                                err = fmt.Errorf("namespaces %v are overlap with vpc '%s'", subnet.Spec.Namespaces, vpc.Name)
×
351
                                klog.Error(err)
×
352
                                return vpc, err
×
353
                        }
×
354
                }
355
        }
356
        return vpc, nil
×
357
}
358

359
func (c *Controller) checkSubnetConflict(subnet *kubeovnv1.Subnet) error {
×
360
        subnetList, err := c.subnetsLister.List(labels.Everything())
×
361
        if err != nil {
×
362
                klog.Errorf("failed to list subnets %v", err)
×
363
                return err
×
364
        }
×
365

366
        for _, sub := range subnetList {
×
367
                if sub.Spec.Vpc != subnet.Spec.Vpc || sub.Spec.Vlan != subnet.Spec.Vlan || sub.Name == subnet.Name {
×
368
                        continue
×
369
                }
370

371
                if util.CIDROverlap(sub.Spec.CIDRBlock, subnet.Spec.CIDRBlock) {
×
372
                        err = fmt.Errorf("subnet %s cidr %s is conflict with subnet %s cidr %s", subnet.Name, subnet.Spec.CIDRBlock, sub.Name, sub.Spec.CIDRBlock)
×
373
                        klog.Error(err)
×
374
                        if err = c.patchSubnetStatus(subnet, "ValidateLogicalSwitchFailed", err.Error()); err != nil {
×
375
                                klog.Error(err)
×
376
                                return err
×
377
                        }
×
378
                        return err
×
379
                }
380

381
                if subnet.Spec.ExternalEgressGateway != "" && sub.Spec.ExternalEgressGateway != "" &&
×
382
                        subnet.Spec.PolicyRoutingTableID == sub.Spec.PolicyRoutingTableID {
×
383
                        err = fmt.Errorf("subnet %s policy routing table ID %d is conflict with subnet %s policy routing table ID %d", subnet.Name, subnet.Spec.PolicyRoutingTableID, sub.Name, sub.Spec.PolicyRoutingTableID)
×
384
                        klog.Error(err)
×
385
                        if err = c.patchSubnetStatus(subnet, "ValidateLogicalSwitchFailed", err.Error()); err != nil {
×
386
                                klog.Error(err)
×
387
                                return err
×
388
                        }
×
389
                        return err
×
390
                }
391
        }
392

393
        if subnet.Spec.Vlan == "" && subnet.Spec.Vpc == c.config.ClusterRouter {
×
394
                nodes, err := c.nodesLister.List(labels.Everything())
×
395
                if err != nil {
×
396
                        klog.Errorf("failed to list nodes: %v", err)
×
397
                        return err
×
398
                }
×
399
                for _, node := range nodes {
×
400
                        for _, addr := range node.Status.Addresses {
×
401
                                if addr.Type == v1.NodeInternalIP && util.CIDRContainIP(subnet.Spec.CIDRBlock, addr.Address) {
×
402
                                        err = fmt.Errorf("subnet %s cidr %s conflict with node %s address %s", subnet.Name, subnet.Spec.CIDRBlock, node.Name, addr.Address)
×
403
                                        klog.Error(err)
×
404
                                        if err = c.patchSubnetStatus(subnet, "ValidateLogicalSwitchFailed", err.Error()); err != nil {
×
405
                                                klog.Error(err)
×
406
                                                return err
×
407
                                        }
×
408
                                        return err
×
409
                                }
410
                        }
411
                }
412
        }
413
        return nil
×
414
}
415

416
func (c *Controller) updateSubnetDHCPOption(subnet *kubeovnv1.Subnet, needRouter bool) error {
×
417
        var mtu int
×
418
        if subnet.Spec.Mtu > 0 {
×
419
                mtu = int(subnet.Spec.Mtu)
×
420
        } else {
×
421
                mtu = util.DefaultMTU
×
422
                if subnet.Spec.Vlan == "" {
×
423
                        switch c.config.NetworkType {
×
424
                        case util.NetworkTypeVlan:
×
425
                                // default to geneve
×
426
                                fallthrough
×
427
                        case util.NetworkTypeGeneve:
×
428
                                mtu -= util.GeneveHeaderLength
×
429
                        case util.NetworkTypeVxlan:
×
430
                                mtu -= util.VxlanHeaderLength
×
431
                        case util.NetworkTypeStt:
×
432
                                mtu -= util.SttHeaderLength
×
433
                        default:
×
434
                                return fmt.Errorf("invalid network type: %s", c.config.NetworkType)
×
435
                        }
436
                }
437
        }
438

439
        dhcpOptionsUUIDs, err := c.OVNNbClient.UpdateDHCPOptions(subnet, mtu)
×
440
        if err != nil {
×
441
                klog.Errorf("failed to update dhcp options for switch %s, %v", subnet.Name, err)
×
442
                return err
×
443
        }
×
444

445
        vpc, err := c.vpcsLister.Get(subnet.Spec.Vpc)
×
446
        if err != nil {
×
447
                klog.Errorf("failed to get subnet's vpc '%s', %v", subnet.Spec.Vpc, err)
×
448
                return err
×
449
        }
×
450

451
        if needRouter {
×
452
                lrpName := fmt.Sprintf("%s-%s", vpc.Status.Router, subnet.Name)
×
453
                if err := c.OVNNbClient.UpdateLogicalRouterPortRA(lrpName, subnet.Spec.IPv6RAConfigs, subnet.Spec.EnableIPv6RA); err != nil {
×
454
                        klog.Errorf("update ipv6 ra configs for logical router port %s, %v", lrpName, err)
×
455
                        return err
×
456
                }
×
457
        }
458

459
        if subnet.Status.DHCPv4OptionsUUID != dhcpOptionsUUIDs.DHCPv4OptionsUUID || subnet.Status.DHCPv6OptionsUUID != dhcpOptionsUUIDs.DHCPv6OptionsUUID {
×
460
                subnet.Status.DHCPv4OptionsUUID = dhcpOptionsUUIDs.DHCPv4OptionsUUID
×
461
                subnet.Status.DHCPv6OptionsUUID = dhcpOptionsUUIDs.DHCPv6OptionsUUID
×
462
                bytes, err := subnet.Status.Bytes()
×
463
                if err != nil {
×
464
                        klog.Error(err)
×
465
                        return err
×
466
                }
×
467
                if _, err := c.config.KubeOvnClient.KubeovnV1().Subnets().Patch(context.Background(), subnet.Name, types.MergePatchType, bytes, metav1.PatchOptions{}, "status"); err != nil {
×
468
                        klog.Errorf("patch subnet %s dhcp options failed: %v", subnet.Name, err)
×
469
                        return err
×
470
                }
×
471
        }
472

473
        return nil
×
474
}
475

476
func (c *Controller) handleAddOrUpdateSubnet(key string) error {
1✔
477
        c.subnetKeyMutex.LockKey(key)
1✔
478
        defer func() { _ = c.subnetKeyMutex.UnlockKey(key) }()
2✔
479

480
        cachedSubnet, err := c.subnetsLister.Get(key)
1✔
481
        if err != nil {
1✔
482
                if k8serrors.IsNotFound(err) {
×
483
                        return nil
×
484
                }
×
485
                klog.Error(err)
×
486
                return err
×
487
        }
488
        klog.V(3).Infof("handle add or update subnet %s", cachedSubnet.Name)
1✔
489
        subnet, err := c.formatSubnet(cachedSubnet)
1✔
490
        if err != nil {
1✔
491
                err := fmt.Errorf("failed to format subnet %s, %w", key, err)
×
492
                klog.Error(err)
×
493
                return err
×
494
        }
×
495

496
        err = c.validateSubnetVlan(subnet)
1✔
497
        if err != nil {
2✔
498
                err = fmt.Errorf("failed to validate vlan for subnet %s, %w", key, err)
1✔
499
                klog.Error(err)
1✔
500
                if patchErr := c.patchSubnetStatus(subnet, "ValidateSubnetVlanFailed", err.Error()); patchErr != nil {
1✔
NEW
501
                        klog.Error(patchErr)
×
NEW
502
                        return patchErr
×
503
                }
×
504
                return err
1✔
505
        }
506

507
        if err = util.ValidateSubnet(*subnet); err != nil {
×
508
                klog.Errorf("failed to validate subnet %s, %v", subnet.Name, err)
×
NEW
509
                if patchErr := c.patchSubnetStatus(subnet, "ValidateLogicalSwitchFailed", err.Error()); patchErr != nil {
×
NEW
510
                        klog.Error(patchErr)
×
NEW
511
                        return patchErr
×
512
                }
×
513
                return err
×
514
        }
515
        if err = c.patchSubnetStatus(subnet, "ValidateLogicalSwitchSuccess", ""); err != nil {
×
516
                klog.Error(err)
×
517
                return err
×
518
        }
×
519

520
        if err := c.ipam.AddOrUpdateSubnet(subnet.Name, subnet.Spec.CIDRBlock, subnet.Spec.Gateway, subnet.Spec.ExcludeIps); err != nil {
×
521
                klog.Error(err)
×
522
                return err
×
523
        }
×
524

525
        // availableIPStr valued from ipam, so leave update subnet.status after ipam process
526
        subnet, err = c.calcSubnetStatusIP(subnet)
×
527
        if err != nil {
×
528
                klog.Errorf("calculate subnet %s used ip failed, %v", cachedSubnet.Name, err)
×
529
                return err
×
530
        }
×
531

532
        subnet, deleted, err := c.handleSubnetFinalizer(subnet)
×
533
        if err != nil {
×
534
                klog.Errorf("handle subnet finalizer failed %v", err)
×
535
                return err
×
536
        }
×
537
        if deleted {
×
538
                return nil
×
539
        }
×
540

541
        if !isOvnSubnet(subnet) {
×
542
                // subnet provider is not ovn, and vpc is empty, should not reconcile
×
543
                if err = c.patchSubnetStatus(subnet, "SetNonOvnSubnetSuccess", ""); err != nil {
×
544
                        klog.Error(err)
×
545
                        return err
×
546
                }
×
547

548
                subnet.Status.EnsureStandardConditions()
×
549
                klog.Infof("non ovn subnet %s is ready", subnet.Name)
×
550
                return nil
×
551
        }
552

553
        // This validate should be processed after isOvnSubnet, since maybe there's no vpc for subnet not managed by kube-ovn
554
        vpc, err := c.validateVpcBySubnet(subnet)
×
555
        if err != nil {
×
556
                klog.Errorf("failed to get subnet's vpc '%s', %v", subnet.Spec.Vpc, err)
×
557
                return err
×
558
        }
×
559
        _, isMcastQuerierChanged, err := c.reconcileSubnetSpecialIPs(subnet)
×
560
        if err != nil {
×
561
                klog.Errorf("failed to reconcile subnet %s Custom IPs %v", subnet.Name, err)
×
562
                return err
×
563
        }
×
564

565
        needRouter := subnet.Spec.Vlan == "" || subnet.Spec.LogicalGateway ||
×
566
                (subnet.Status.U2OInterconnectionIP != "" && subnet.Spec.U2OInterconnection)
×
567
        // 1. overlay subnet, should add lrp, lrp ip is subnet gw
×
568
        // 2. underlay subnet use logical gw, should add lrp, lrp ip is subnet gw
×
569
        randomAllocateGW := !subnet.Spec.LogicalGateway && vpc.Spec.EnableExternal && subnet.Name == c.config.ExternalGatewaySwitch
×
570
        // 3. underlay subnet use physical gw, vpc has eip, lrp managed in vpc process, lrp ip is random allocation, not subnet gw
×
571

×
572
        gateway := subnet.Spec.Gateway
×
573
        var gatewayMAC string
×
574
        if subnet.Status.U2OInterconnectionIP != "" && subnet.Spec.U2OInterconnection {
×
575
                gateway = subnet.Status.U2OInterconnectionIP
×
576
                gatewayMAC = subnet.Status.U2OInterconnectionMAC
×
577
        }
×
578

579
        if err := c.clearOldU2OResource(subnet); err != nil {
×
580
                klog.Errorf("clear subnet %s old u2o resource failed: %v", subnet.Name, err)
×
581
                return err
×
582
        }
×
583

584
        // Lock VPC to prevent CIDR conflict between concurrent subnet creations in the same VPC
585
        c.vpcKeyMutex.LockKey(subnet.Spec.Vpc)
×
586
        if err := c.checkSubnetConflict(subnet); err != nil {
×
587
                _ = c.vpcKeyMutex.UnlockKey(subnet.Spec.Vpc)
×
588
                klog.Errorf("failed to check subnet %s, %v", subnet.Name, err)
×
589
                return err
×
590
        }
×
591
        // create or update logical switch
592
        if err := c.OVNNbClient.CreateLogicalSwitch(subnet.Name, vpc.Status.Router, subnet.Spec.CIDRBlock, gateway, gatewayMAC, needRouter, randomAllocateGW); err != nil {
×
593
                _ = c.vpcKeyMutex.UnlockKey(subnet.Spec.Vpc)
×
594
                klog.Errorf("create logical switch %s: %v", subnet.Name, err)
×
595
                return err
×
596
        }
×
597
        _ = c.vpcKeyMutex.UnlockKey(subnet.Spec.Vpc)
×
598

×
599
        // Record the gateway MAC in ipam if router port exists
×
600
        if needRouter {
×
601
                routerPortName := ovs.LogicalRouterPortName(vpc.Status.Router, subnet.Name)
×
602
                if lrp, err := c.OVNNbClient.GetLogicalRouterPort(routerPortName, true); err == nil && lrp != nil && lrp.MAC != "" {
×
603
                        if err := c.ipam.RecordGatewayMAC(subnet.Name, lrp.MAC); err != nil {
×
604
                                klog.Warningf("failed to record gateway MAC %s for subnet %s: %v", lrp.MAC, subnet.Name, err)
×
605
                        }
×
606
                } else {
×
607
                        klog.V(3).Infof("router port %s not found or has no MAC, skipping gateway MAC record", routerPortName)
×
608
                }
×
609
        }
610

611
        if isMcastQuerierChanged {
×
612
                if err := c.handleMcastQuerierChange(subnet); err != nil {
×
613
                        klog.Errorf("failed to handle mcast querier IP change for subnet %s: %v", subnet.Name, err)
×
614
                        return err
×
615
                }
×
616
        }
617

618
        subnet.Status.EnsureStandardConditions()
×
619

×
620
        if err := c.updateSubnetDHCPOption(subnet, needRouter); err != nil {
×
621
                klog.Errorf("failed to update subnet %s dhcpOptions: %v", subnet.Name, err)
×
622
                return err
×
623
        }
×
624

625
        if c.config.EnableLb && subnet.Name != c.config.NodeSwitch {
×
626
                lbs := []string{
×
627
                        vpc.Status.TCPLoadBalancer,
×
628
                        vpc.Status.TCPSessionLoadBalancer,
×
629
                        vpc.Status.UDPLoadBalancer,
×
630
                        vpc.Status.UDPSessionLoadBalancer,
×
631
                        vpc.Status.SctpLoadBalancer,
×
632
                        vpc.Status.SctpSessionLoadBalancer,
×
633
                }
×
634
                if subnet.Spec.EnableLb != nil && *subnet.Spec.EnableLb {
×
635
                        if err := c.OVNNbClient.LogicalSwitchUpdateLoadBalancers(subnet.Name, ovsdb.MutateOperationInsert, lbs...); err != nil {
×
636
                                if err = c.patchSubnetStatus(subnet, "AddLbToLogicalSwitchFailed", err.Error()); err != nil {
×
637
                                        klog.Error(err)
×
638
                                        return err
×
639
                                }
×
640
                                klog.Error(err)
×
641
                                return err
×
642
                        }
643
                } else {
×
644
                        if err := c.OVNNbClient.LogicalSwitchUpdateLoadBalancers(subnet.Name, ovsdb.MutateOperationDelete, lbs...); err != nil {
×
645
                                klog.Errorf("remove load-balancer from subnet %s failed: %v", subnet.Name, err)
×
646
                                return err
×
647
                        }
×
648
                }
649
        }
650

651
        if err := c.reconcileSubnet(subnet); err != nil {
×
652
                klog.Errorf("reconcile subnet for %s failed, %v", subnet.Name, err)
×
653
                return err
×
654
        }
×
655

656
        subnet.Status.U2OInterconnectionVPC = ""
×
657
        if subnet.Spec.U2OInterconnection {
×
658
                subnet.Status.U2OInterconnectionVPC = vpc.Status.Router
×
659
        }
×
660

661
        if err = c.updateNatOutgoingPolicyRulesStatus(subnet); err != nil {
×
662
                klog.Errorf("failed to update NAT outgoing policy status for subnet %s: %v", subnet.Name, err)
×
663
                return err
×
664
        }
×
665

666
        if subnet.Spec.Private {
×
667
                if err := c.OVNNbClient.SetLogicalSwitchPrivate(subnet.Name, subnet.Spec.CIDRBlock, c.config.NodeSwitchCIDR, subnet.Spec.AllowSubnets); err != nil {
×
668
                        if err = c.patchSubnetStatus(subnet, "SetPrivateLogicalSwitchFailed", err.Error()); err != nil {
×
669
                                klog.Error(err)
×
670
                                return err
×
671
                        }
×
672
                        klog.Error(err)
×
673
                        return err
×
674
                }
675

676
                if err = c.patchSubnetStatus(subnet, "SetPrivateLogicalSwitchSuccess", ""); err != nil {
×
677
                        klog.Error(err)
×
678
                        return err
×
679
                }
×
680
        } else {
×
681
                // clear acl when direction is ""
×
682
                if err = c.OVNNbClient.DeleteAcls(subnet.Name, logicalSwitchKey, "", nil); err != nil {
×
683
                        if err = c.patchSubnetStatus(subnet, "ResetLogicalSwitchAclFailed", err.Error()); err != nil {
×
684
                                klog.Error(err)
×
685
                                return err
×
686
                        }
×
687
                        klog.Error(err)
×
688
                        return err
×
689
                }
690

691
                if err = c.patchSubnetStatus(subnet, "ResetLogicalSwitchAclSuccess", ""); err != nil {
×
692
                        klog.Error(err)
×
693
                        return err
×
694
                }
×
695
        }
696

697
        if err := c.OVNNbClient.UpdateLogicalSwitchACL(subnet.Name, subnet.Spec.CIDRBlock, subnet.Spec.Acls, subnet.Spec.AllowEWTraffic); err != nil {
×
698
                if err = c.patchSubnetStatus(subnet, "SetLogicalSwitchAclsFailed", err.Error()); err != nil {
×
699
                        klog.Error(err)
×
700
                        return err
×
701
                }
×
702
                klog.Error(err)
×
703
                return err
×
704
        }
705

706
        c.updateVpcStatusQueue.Add(subnet.Spec.Vpc)
×
707

×
708
        ippools, err := c.ippoolLister.List(labels.Everything())
×
709
        if err != nil {
×
710
                klog.Errorf("failed to list ippools: %v", err)
×
711
                return err
×
712
        }
×
713

714
        for _, p := range ippools {
×
715
                if p.Spec.Subnet == subnet.Name {
×
716
                        c.addOrUpdateIPPoolQueue.Add(p.Name)
×
717
                }
×
718
        }
719

720
        return nil
×
721
}
722

723
func (c *Controller) handleDeleteLogicalSwitch(key string) (err error) {
×
724
        c.ipam.DeleteSubnet(key)
×
725

×
726
        exist, err := c.OVNNbClient.LogicalSwitchExists(key)
×
727
        if err != nil {
×
728
                klog.Errorf("check logical switch %s exist: %v", key, err)
×
729
                return err
×
730
        }
×
731

732
        // not found, skip
733
        if !exist {
×
734
                return nil
×
735
        }
×
736

737
        // clear acl when direction is ""
738
        if err = c.OVNNbClient.DeleteAcls(key, logicalSwitchKey, "", nil); err != nil {
×
739
                klog.Errorf("clear logical switch %s acls: %v", key, err)
×
740
                return err
×
741
        }
×
742

743
        if err = c.OVNNbClient.DeleteDHCPOptions(key, kubeovnv1.ProtocolDual); err != nil {
×
744
                klog.Errorf("failed to delete dhcp options of logical switch %s %v", key, err)
×
745
                return err
×
746
        }
×
747

748
        if err = c.OVNNbClient.DeleteLogicalSwitch(key); err != nil {
×
749
                klog.Errorf("delete logical switch %s: %v", key, err)
×
750
                return err
×
751
        }
×
752

753
        nss, err := c.namespacesLister.List(labels.Everything())
×
754
        if err != nil {
×
755
                klog.Errorf("failed to list namespaces, %v", err)
×
756
                return err
×
757
        }
×
758

759
        // re-annotate namespace
760
        for _, ns := range nss {
×
761
                annotations := ns.GetAnnotations()
×
762
                if annotations == nil {
×
763
                        continue
×
764
                }
765

766
                if slices.Contains(strings.Split(annotations[util.LogicalSwitchAnnotation], ","), key) {
×
767
                        c.enqueueAddNamespace(ns)
×
768
                }
×
769
        }
770

771
        return c.delLocalnet(key)
×
772
}
773

774
func (c *Controller) handleDeleteSubnet(subnet *kubeovnv1.Subnet) error {
×
775
        c.subnetKeyMutex.LockKey(subnet.Name)
×
776
        defer func() { _ = c.subnetKeyMutex.UnlockKey(subnet.Name) }()
×
777

778
        c.updateVpcStatusQueue.Add(subnet.Spec.Vpc)
×
779
        klog.Infof("delete u2o interconnection policy route for subnet %s", subnet.Name)
×
780
        if err := c.deletePolicyRouteForU2OInterconn(subnet); err != nil {
×
781
                klog.Errorf("failed to delete policy route for underlay to overlay subnet interconnection %s, %v", subnet.Name, err)
×
782
                return err
×
783
        }
×
784
        if subnet.Spec.Vpc != c.config.ClusterRouter {
×
785
                if err := c.deleteStaticRouteForU2OInterconn(subnet); err != nil {
×
786
                        klog.Errorf("failed to delete static route for underlay to overlay subnet interconnection %s, %v", subnet.Name, err)
×
787
                        return err
×
788
                }
×
789
        }
790

791
        u2oInterconnName := fmt.Sprintf(util.U2OInterconnName, subnet.Spec.Vpc, subnet.Name)
×
792
        if err := c.config.KubeOvnClient.KubeovnV1().IPs().Delete(context.Background(), u2oInterconnName, metav1.DeleteOptions{}); err != nil {
×
793
                if !k8serrors.IsNotFound(err) {
×
794
                        klog.Errorf("failed to delete ip %s, %v", u2oInterconnName, err)
×
795
                        return err
×
796
                }
×
797
        }
798

799
        if subnet.Spec.Vpc != c.config.ClusterRouter {
×
800
                if err := c.deleteCustomVPCPolicyRoutesForSubnet(subnet); err != nil {
×
801
                        klog.Errorf("failed to delete custom vpc routes subnet %s, %v", subnet.Name, err)
×
802
                        return err
×
803
                }
×
804
        }
805

806
        klog.Infof("delete policy route for %s subnet %s", subnet.Spec.GatewayType, subnet.Name)
×
807
        if err := c.deletePolicyRouteByGatewayType(subnet, subnet.Spec.GatewayType, true); err != nil {
×
808
                klog.Errorf("failed to delete policy route for overlay subnet %s, %v", subnet.Name, err)
×
809
                return err
×
810
        }
×
811

812
        err := c.handleDeleteLogicalSwitch(subnet.Name)
×
813
        if err != nil {
×
814
                klog.Errorf("failed to delete logical switch %s %v", subnet.Name, err)
×
815
                return err
×
816
        }
×
817

818
        var router string
×
819
        vpc, err := c.vpcsLister.Get(subnet.Spec.Vpc)
×
820
        if err != nil {
×
821
                if !k8serrors.IsNotFound(err) {
×
822
                        klog.Errorf("get vpc %s: %v", vpc.Name, err)
×
823
                        return err
×
824
                }
×
825
                router = c.config.ClusterRouter
×
826
        } else {
×
827
                router = vpc.Status.Router
×
828
        }
×
829

830
        lspName := fmt.Sprintf("%s-%s", subnet.Name, router)
×
831
        lrpName := fmt.Sprintf("%s-%s", router, subnet.Name)
×
832
        if err = c.OVNNbClient.RemoveLogicalPatchPort(lspName, lrpName); err != nil {
×
833
                klog.Errorf("delete router port %s and %s:%v", lspName, lrpName, err)
×
834
                return err
×
835
        }
×
836

837
        vlans, err := c.vlansLister.List(labels.Everything())
×
838
        if err != nil && !k8serrors.IsNotFound(err) {
×
839
                klog.Errorf("failed to list vlans: %v", err)
×
840
                return err
×
841
        }
×
842

843
        for _, vlan := range vlans {
×
844
                if err = c.updateVlanStatusForSubnetDeletion(vlan, subnet.Name); err != nil {
×
845
                        klog.Error(err)
×
846
                        return err
×
847
                }
×
848
        }
849

850
        return nil
×
851
}
852

853
func (c *Controller) updateVlanStatusForSubnetDeletion(vlan *kubeovnv1.Vlan, subnet string) error {
×
854
        if !slices.Contains(vlan.Status.Subnets, subnet) {
×
855
                return nil
×
856
        }
×
857

858
        newVlan := vlan.DeepCopy()
×
859
        newVlan.Status.Subnets = util.RemoveString(newVlan.Status.Subnets, subnet)
×
860
        _, err := c.config.KubeOvnClient.KubeovnV1().Vlans().UpdateStatus(context.Background(), newVlan, metav1.UpdateOptions{})
×
861
        if err != nil {
×
862
                klog.Errorf("failed to update status of vlan %s: %v", vlan.Name, err)
×
863
                return err
×
864
        }
×
865

866
        return nil
×
867
}
868

869
func (c *Controller) reconcileSubnet(subnet *kubeovnv1.Subnet) error {
×
870
        if err := c.reconcileNamespaces(subnet); err != nil {
×
871
                klog.Errorf("reconcile namespaces for subnet %s failed, %v", subnet.Name, err)
×
872
                return err
×
873
        }
×
874

875
        if err := c.reconcileRouteTableForSubnet(subnet); err != nil {
×
876
                klog.Errorf("reconcile route table for subnet %s failed, %v", subnet.Name, err)
×
877
                return err
×
878
        }
×
879

880
        if subnet.Spec.Vpc == c.config.ClusterRouter {
×
881
                if err := c.reconcileOvnDefaultVpcRoute(subnet); err != nil {
×
882
                        klog.Errorf("reconcile default vpc ovn route for subnet %s failed: %v", subnet.Name, err)
×
883
                        return err
×
884
                }
×
885
        } else if err := c.reconcileCustomVpcStaticRoute(subnet); err != nil {
×
886
                klog.Errorf("reconcile custom vpc ovn route for subnet %s failed: %v", subnet.Name, err)
×
887
                return err
×
888
        }
×
889

890
        if err := c.reconcileVlan(subnet); err != nil {
×
891
                klog.Errorf("reconcile vlan for subnet %s failed, %v", subnet.Name, err)
×
892
                return err
×
893
        }
×
894

895
        if err := c.reconcileVips(subnet); err != nil {
×
896
                klog.Errorf("reconcile vips for subnet %s failed, %v", subnet.Name, err)
×
897
                return err
×
898
        }
×
899
        return nil
×
900
}
901

902
func (c *Controller) reconcileVips(subnet *kubeovnv1.Subnet) error {
1✔
903
        /* get all virtual port belongs to this logical switch */
1✔
904
        lsps, err := c.OVNNbClient.ListLogicalSwitchPorts(true, map[string]string{logicalSwitchKey: subnet.Name}, func(lsp *ovnnb.LogicalSwitchPort) bool {
1✔
905
                return lsp.Type == "virtual"
×
906
        })
×
907
        if err != nil {
1✔
908
                klog.Errorf("failed to find virtual port for subnet %s: %v", subnet.Name, err)
×
909
                return err
×
910
        }
×
911

912
        /* filter all invalid virtual port */
913
        existVips := make(map[string]string) // key is vip, value is port name
1✔
914
        for _, lsp := range lsps {
2✔
915
                vip, ok := lsp.Options["virtual-ip"]
1✔
916
                if !ok {
1✔
917
                        continue // ignore vip which is empty
×
918
                }
919

920
                if net.ParseIP(vip) == nil {
1✔
921
                        continue // ignore invalid vip
×
922
                }
923

924
                existVips[vip] = lsp.Name
1✔
925
        }
926

927
        /* filter virtual port to be added and old virtual port to be deleted */
928
        var newVips []string
1✔
929
        for _, vip := range subnet.Spec.Vips {
2✔
930
                if _, ok := existVips[vip]; !ok {
2✔
931
                        // new virtual port to be added
1✔
932
                        newVips = append(newVips, vip)
1✔
933
                } else {
2✔
934
                        // delete old virtual port that do not need to be deleted
1✔
935
                        delete(existVips, vip)
1✔
936
                }
1✔
937
        }
938

939
        // delete old virtual ports
940
        for _, lspName := range existVips {
2✔
941
                if err = c.OVNNbClient.DeleteLogicalSwitchPort(lspName); err != nil {
1✔
942
                        klog.Errorf("delete virtual port %s lspName from logical switch %s: %v", lspName, subnet.Name, err)
×
943
                        return err
×
944
                }
×
945
        }
946

947
        // add new virtual port
948
        if err = c.OVNNbClient.CreateVirtualLogicalSwitchPorts(subnet.Name, newVips...); err != nil {
1✔
949
                klog.Errorf("create virtual port with vips %v from logical switch %s: %v", newVips, subnet.Name, err)
×
950
                return err
×
951
        }
×
952

953
        c.syncVirtualPortsQueue.Add(subnet.Name)
1✔
954
        return nil
1✔
955
}
956

957
func (c *Controller) syncVirtualPort(key string) error {
1✔
958
        subnet, err := c.subnetsLister.Get(key)
1✔
959
        if err != nil {
1✔
960
                if k8serrors.IsNotFound(err) {
×
961
                        return nil
×
962
                }
×
963
                klog.Errorf("failed to get subnet %s, %v", key, err)
×
964
                return err
×
965
        }
966
        if len(subnet.Spec.Vips) == 0 {
1✔
967
                return nil
×
968
        }
×
969

970
        externalIDs := map[string]string{
1✔
971
                logicalSwitchKey: subnet.Name,
1✔
972
                "attach-vips":    "true",
1✔
973
        }
1✔
974

1✔
975
        lsps, err := c.OVNNbClient.ListNormalLogicalSwitchPorts(true, externalIDs)
1✔
976
        if err != nil {
1✔
977
                klog.Errorf("list logical switch %s ports: %v", subnet.Name, err)
×
978
                return err
×
979
        }
×
980

981
        for _, vip := range subnet.Spec.Vips {
2✔
982
                if !util.CIDRContainIP(subnet.Spec.CIDRBlock, vip) {
1✔
983
                        klog.Errorf("vip %s is out of range to subnet %s", vip, subnet.Name)
×
984
                        continue
×
985
                }
986

987
                var virtualParents []string
1✔
988
                for _, lsp := range lsps {
2✔
989
                        vips, ok := lsp.ExternalIDs["vips"]
1✔
990
                        if !ok {
1✔
991
                                continue // ignore vips which is empty
×
992
                        }
993

994
                        if strings.Contains(vips, vip) {
2✔
995
                                virtualParents = append(virtualParents, lsp.Name)
1✔
996
                        }
1✔
997
                }
998

999
                // logical switch port has no valid vip
1000
                if len(virtualParents) == 0 {
2✔
1001
                        continue
1✔
1002
                }
1003

1004
                if err = c.OVNNbClient.SetLogicalSwitchPortVirtualParents(subnet.Name, strings.Join(virtualParents, ","), vip); err != nil {
1✔
1005
                        klog.Errorf("set vip %s virtual parents %v: %v", vip, virtualParents, err)
×
1006
                        return err
×
1007
                }
×
1008
        }
1009

1010
        return nil
1✔
1011
}
1012

1013
func (c *Controller) reconcileNamespaces(subnet *kubeovnv1.Subnet) error {
×
1014
        var (
×
1015
                namespaces []*v1.Namespace
×
1016
                err        error
×
1017
        )
×
1018

×
1019
        // 1. get all namespaces should be updated
×
1020
        expectNss, err := c.getNamespacesBySelector(subnet.Spec.NamespaceSelectors)
×
1021
        if err != nil {
×
1022
                klog.Errorf("failed to list namespaces by selector, %v", err)
×
1023
                return err
×
1024
        }
×
1025
        for _, ns := range subnet.Spec.Namespaces {
×
1026
                if !slices.Contains(expectNss, ns) {
×
1027
                        expectNss = append(expectNss, ns)
×
1028
                }
×
1029
        }
1030

1031
        // 2. update namespaces
1032
        for _, expectNs := range expectNss {
×
1033
                checkNs, err := c.namespacesLister.Get(expectNs)
×
1034
                if err != nil {
×
1035
                        if k8serrors.IsNotFound(err) {
×
1036
                                continue
×
1037
                        }
1038
                        klog.Error(err)
×
1039
                        return err
×
1040
                }
1041
                if checkNs.Annotations != nil && slices.Contains(strings.Split(checkNs.Annotations[util.LogicalSwitchAnnotation], ","), subnet.Name) {
×
1042
                        // when subnet cidr changed, the ns annotation with the subnet should be updated
×
1043
                        if !slices.Contains(strings.Split(checkNs.Annotations[util.CidrAnnotation], ";"), subnet.Spec.CIDRBlock) {
×
1044
                                c.addNamespaceQueue.Add(checkNs.Name)
×
1045
                        }
×
1046
                        continue
×
1047
                }
1048
                c.addNamespaceQueue.Add(expectNs)
×
1049
        }
1050

1051
        // 3. update unbind namespace annotation
1052
        if namespaces, err = c.namespacesLister.List(labels.Everything()); err != nil {
×
1053
                klog.Errorf("failed to list namespaces, %v", err)
×
1054
                return err
×
1055
        }
×
1056

1057
        for _, ns := range namespaces {
×
1058
                if ns.Annotations != nil && slices.Contains(strings.Split(ns.Annotations[util.LogicalSwitchAnnotation], ","), subnet.Name) {
×
1059
                        if slices.Contains(expectNss, ns.Name) {
×
1060
                                continue
×
1061
                        }
1062
                        // ns deleted from subnet.Spec.Namespaces or subnet delete namespaceSelectors which match the checked namespace
1063
                        c.addNamespaceQueue.Add(ns.Name)
×
1064
                }
1065
        }
1066

1067
        return nil
×
1068
}
1069

1070
func (c *Controller) getNamespacesBySelector(nsSelectors []metav1.LabelSelector) ([]string, error) {
×
1071
        var expectNss []string
×
1072
        for _, nsSelector := range nsSelectors {
×
1073
                matchSelector, err := metav1.LabelSelectorAsSelector(&nsSelector)
×
1074
                if err != nil {
×
1075
                        klog.Errorf("failed to convert label selector, %v", err)
×
1076
                        return expectNss, err
×
1077
                }
×
1078

1079
                nss, err := c.namespacesLister.List(matchSelector)
×
1080
                if err != nil {
×
1081
                        klog.Errorf("failed to list namespaces by selector, %v", err)
×
1082
                        return expectNss, err
×
1083
                }
×
1084
                for _, ns := range nss {
×
1085
                        expectNss = append(expectNss, ns.Name)
×
1086
                }
×
1087
        }
1088
        return expectNss, nil
×
1089
}
1090

1091
func (c *Controller) reconcileCustomVpcBfdStaticRoute(vpcName, subnetName string) error {
×
1092
        // vpc enable bfd and subnet enable ecmp
×
1093
        // use static ecmp route with bfd
×
1094
        ovnEips, err := c.ovnEipsLister.List(labels.SelectorFromSet(labels.Set{util.OvnEipTypeLabel: util.OvnEipTypeLSP}))
×
1095
        if err != nil {
×
1096
                klog.Errorf("failed to list node external ovn eip, %v", err)
×
1097
                return err
×
1098
        }
×
1099
        if len(ovnEips) < 2 {
×
1100
                err := fmt.Errorf("ecmp route with bfd for HA, which need two %s type eips at least, has %d", util.OvnEipTypeLSP, len(ovnEips))
×
1101
                klog.Error(err)
×
1102
                return err
×
1103
        }
×
1104

1105
        subnet, err := c.subnetsLister.Get(subnetName)
×
1106
        if err != nil {
×
1107
                klog.Errorf("failed to get subnet %s, %v", subnetName, err)
×
1108
                return err
×
1109
        }
×
1110
        cachedVpc, err := c.vpcsLister.Get(vpcName)
×
1111
        if err != nil {
×
1112
                if k8serrors.IsNotFound(err) {
×
1113
                        return nil
×
1114
                }
×
1115
                klog.Errorf("failed to get vpc %s, %v", vpcName, err)
×
1116
                return err
×
1117
        }
1118

1119
        var (
×
1120
                needUpdate, v4Exist bool
×
1121
                lrpEipName          string
×
1122
        )
×
1123

×
1124
        lrpEipName = fmt.Sprintf("%s-%s", vpcName, c.config.ExternalGatewaySwitch)
×
1125
        lrpEip, err := c.ovnEipsLister.Get(lrpEipName)
×
1126
        if err != nil {
×
1127
                err := fmt.Errorf("failed to get lrp eip %s, %w", lrpEipName, err)
×
1128
                klog.Error(err)
×
1129
                return err
×
1130
        }
×
1131
        if !lrpEip.Status.Ready || lrpEip.Status.V4Ip == "" {
×
1132
                err := fmt.Errorf("lrp eip %q not ready", lrpEipName)
×
1133
                klog.Error(err)
×
1134
                return err
×
1135
        }
×
1136
        vpc := cachedVpc.DeepCopy()
×
1137

×
1138
        for _, eip := range ovnEips {
×
1139
                if !eip.Status.Ready || eip.Status.V4Ip == "" {
×
1140
                        err := fmt.Errorf("ovn eip %q not ready", eip.Name)
×
1141
                        klog.Error(err)
×
1142
                        return err
×
1143
                }
×
1144
                bfd, err := c.OVNNbClient.CreateBFD(lrpEipName, eip.Status.V4Ip, c.config.BfdMinRx, c.config.BfdMinTx, c.config.BfdDetectMult, nil)
×
1145
                if err != nil {
×
1146
                        klog.Error(err)
×
1147
                        return err
×
1148
                }
×
1149
                // TODO:// support v6
1150
                v4Exist = false
×
1151
                for _, route := range vpc.Spec.StaticRoutes {
×
1152
                        if route.Policy == kubeovnv1.PolicySrc &&
×
1153
                                route.NextHopIP == eip.Status.V4Ip &&
×
1154
                                route.ECMPMode == util.StaticRouteBfdEcmp &&
×
1155
                                route.CIDR == subnet.Spec.CIDRBlock &&
×
1156
                                route.RouteTable == subnet.Spec.RouteTable {
×
1157
                                v4Exist = true
×
1158
                                break
×
1159
                        }
1160
                }
1161
                if !v4Exist {
×
1162
                        // add ecmp type static route with bfd
×
1163
                        route := &kubeovnv1.StaticRoute{
×
1164
                                Policy:     kubeovnv1.PolicySrc,
×
1165
                                CIDR:       subnet.Spec.CIDRBlock,
×
1166
                                NextHopIP:  eip.Status.V4Ip,
×
1167
                                ECMPMode:   util.StaticRouteBfdEcmp,
×
1168
                                BfdID:      bfd.UUID,
×
1169
                                RouteTable: subnet.Spec.RouteTable,
×
1170
                        }
×
1171
                        klog.Infof("add ecmp bfd static route %v", route)
×
1172
                        vpc.Spec.StaticRoutes = append(vpc.Spec.StaticRoutes, route)
×
1173
                        needUpdate = true
×
1174
                }
×
1175
        }
1176
        if needUpdate {
×
1177
                if _, err = c.config.KubeOvnClient.KubeovnV1().Vpcs().Update(context.Background(), vpc, metav1.UpdateOptions{}); err != nil {
×
1178
                        klog.Errorf("failed to update vpc spec static route %s, %v", vpc.Name, err)
×
1179
                        return err
×
1180
                }
×
1181
                if err = c.patchVpcBfdStatus(vpc.Name); err != nil {
×
1182
                        klog.Errorf("failed to patch vpc %s, %v", vpc.Name, err)
×
1183
                        return err
×
1184
                }
×
1185
        }
1186
        return nil
×
1187
}
1188

1189
func (c *Controller) reconcileCustomVpcDelNormalStaticRoute(vpcName string) error {
×
1190
        // normal static route is prior than ecmp bfd static route
×
1191
        // if use ecmp bfd static route, normal static route should not exist
×
1192
        defaultExternalSubnet, err := c.subnetsLister.Get(c.config.ExternalGatewaySwitch)
×
1193
        if err != nil {
×
1194
                klog.Errorf("failed to get default external switch subnet %s: %v", c.config.ExternalGatewaySwitch, err)
×
1195
                return err
×
1196
        }
×
1197
        gatewayV4, gatewayV6 := util.SplitStringIP(defaultExternalSubnet.Spec.Gateway)
×
1198
        needUpdate := false
×
1199
        vpc, err := c.vpcsLister.Get(vpcName)
×
1200
        if err != nil {
×
1201
                if k8serrors.IsNotFound(err) {
×
1202
                        return nil
×
1203
                }
×
1204
                klog.Errorf("failed to get vpc %s, %v", vpcName, err)
×
1205
                return err
×
1206
        }
1207
        routeTotal := len(vpc.Spec.StaticRoutes)
×
1208
        routes := make([]*kubeovnv1.StaticRoute, 0, routeTotal)
×
1209
        for _, route := range vpc.Spec.StaticRoutes {
×
1210
                if route.Policy == kubeovnv1.PolicyDst &&
×
1211
                        (route.NextHopIP == gatewayV4 || route.NextHopIP == gatewayV6) &&
×
1212
                        (route.CIDR == "0.0.0.0/0" || route.CIDR == "::/0") {
×
1213
                        klog.Infof("in order to use ecmp bfd route, need remove normal static route %v", route)
×
1214
                        needUpdate = true
×
1215
                } else {
×
1216
                        routes = append(routes, route)
×
1217
                }
×
1218
        }
1219

1220
        if needUpdate {
×
1221
                vpc.Spec.StaticRoutes = routes
×
1222
                if _, err = c.config.KubeOvnClient.KubeovnV1().Vpcs().Update(context.Background(), vpc, metav1.UpdateOptions{}); err != nil {
×
1223
                        klog.Errorf("failed to update vpc spec static route %s, %v", vpc.Name, err)
×
1224
                        return err
×
1225
                }
×
1226
        }
1227

1228
        if err = c.patchVpcBfdStatus(vpc.Name); err != nil {
×
1229
                klog.Errorf("failed to patch vpc %s, %v", vpc.Name, err)
×
1230
                return err
×
1231
        }
×
1232

1233
        return nil
×
1234
}
1235

1236
func (c *Controller) reconcileDistributedSubnetRouteInDefaultVpc(subnet *kubeovnv1.Subnet) error {
×
1237
        if subnet.Spec.GatewayNode != "" || subnet.Status.ActivateGateway != "" {
×
1238
                klog.Infof("delete old centralized policy route for subnet %s", subnet.Name)
×
1239
                if err := c.deletePolicyRouteForCentralizedSubnet(subnet); err != nil {
×
1240
                        klog.Errorf("failed to delete policy route for subnet %s, %v", subnet.Name, err)
×
1241
                        return err
×
1242
                }
×
1243

1244
                subnet.Spec.GatewayNode = ""
×
1245
                if _, err := c.config.KubeOvnClient.KubeovnV1().Subnets().Update(context.Background(), subnet, metav1.UpdateOptions{}); err != nil {
×
1246
                        klog.Errorf("failed to remove gatewayNode or activateGateway from subnet %s, %v", subnet.Name, err)
×
1247
                        return err
×
1248
                }
×
1249
                subnet.Status.ActivateGateway = ""
×
1250
                if err := c.patchSubnetStatus(subnet, "ChangeToDistributedGw", ""); err != nil {
×
1251
                        klog.Error(err)
×
1252
                        return err
×
1253
                }
×
1254
        }
1255

1256
        nodes, err := c.nodesLister.List(labels.Everything())
×
1257
        if err != nil {
×
1258
                klog.Errorf("failed to list nodes: %v", err)
×
1259
                return err
×
1260
        }
×
1261
        for _, node := range nodes {
×
1262
                if err = c.createPortGroupForDistributedSubnet(node, subnet); err != nil {
×
1263
                        klog.Errorf("failed to create port group %v", err)
×
1264
                        return err
×
1265
                }
×
1266
                if node.Annotations[util.AllocatedAnnotation] != "true" {
×
1267
                        klog.Warningf("node %s has not been successfully initialized, skip adding policy route for subnet %s", node.Name, subnet.Name)
×
1268
                        continue
×
1269
                }
1270
                nodeIP, err := getNodeTunlIP(node)
×
1271
                if err != nil {
×
1272
                        klog.Errorf("failed to get node %s tunnel ip, %v", node.Name, err)
×
1273
                        return err
×
1274
                }
×
1275
                nextHop := getNextHopByTunnelIP(nodeIP)
×
1276
                v4IP, v6IP := util.SplitStringIP(nextHop)
×
1277
                if err = c.addPolicyRouteForDistributedSubnet(subnet, node.Name, v4IP, v6IP); err != nil {
×
1278
                        klog.Errorf("failed to add policy router for node %s and subnet %s: %v", node.Name, subnet.Name, err)
×
1279
                        return err
×
1280
                }
×
1281
        }
1282

1283
        portGroups, err := c.OVNNbClient.ListPortGroups(map[string]string{"subnet": subnet.Name, "node": "", networkPolicyKey: ""})
×
1284
        if err != nil {
×
1285
                klog.Errorf("failed to list port groups for subnet %s: %v", subnet.Name, err)
×
1286
                return err
×
1287
        }
×
1288

1289
        pods, err := c.podsLister.Pods(metav1.NamespaceAll).List(labels.Everything())
×
1290
        if err != nil {
×
1291
                klog.Errorf("failed to list pods %v", err)
×
1292
                return err
×
1293
        }
×
1294
        for _, pod := range pods {
×
1295
                if !isPodAlive(pod) || pod.Spec.NodeName == "" {
×
1296
                        continue
×
1297
                }
1298

1299
                podNets, err := c.getPodKubeovnNets(pod)
×
1300
                if err != nil {
×
1301
                        klog.Errorf("failed to get pod nets %v", err)
×
1302
                        continue
×
1303
                }
1304

1305
                podPorts := make([]string, 0, 1)
×
1306
                for _, podNet := range podNets {
×
1307
                        if !isOvnSubnet(podNet.Subnet) {
×
1308
                                continue
×
1309
                        }
1310

1311
                        if pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, podNet.ProviderName)] == "" || pod.Annotations[fmt.Sprintf(util.LogicalSwitchAnnotationTemplate, podNet.ProviderName)] != subnet.Name {
×
1312
                                continue
×
1313
                        }
1314

1315
                        podName := c.getNameByPod(pod)
×
1316
                        portName := ovs.PodNameToPortName(podName, pod.Namespace, podNet.ProviderName)
×
1317
                        podPorts = append(podPorts, portName)
×
1318
                }
1319

1320
                pgName := getOverlaySubnetsPortGroupName(subnet.Name, pod.Spec.NodeName)
×
1321
                portsToAdd := make([]string, 0, len(podPorts))
×
1322
                for _, port := range podPorts {
×
1323
                        exist, err := c.OVNNbClient.LogicalSwitchPortExists(port)
×
1324
                        if err != nil {
×
1325
                                klog.Error(err)
×
1326
                                return err
×
1327
                        }
×
1328

1329
                        if !exist {
×
1330
                                klog.Errorf("lsp does not exist for pod %v, please delete the pod and retry", port)
×
1331
                                continue
×
1332
                        }
1333

1334
                        portsToAdd = append(portsToAdd, port)
×
1335
                }
1336

1337
                // remove lsp from other port groups
1338
                // we need to do this because the pod, e.g. a sts/vm, can be rescheduled to another node
1339
                for _, pg := range portGroups {
×
1340
                        if pg.Name == pgName {
×
1341
                                continue
×
1342
                        }
1343
                        if err = c.OVNNbClient.PortGroupRemovePorts(pg.Name, podPorts...); err != nil {
×
1344
                                klog.Errorf("remove ports from port group %s: %v", pg.Name, err)
×
1345
                                return err
×
1346
                        }
×
1347
                }
1348
                // add ports to the port group
1349
                if err = c.OVNNbClient.PortGroupAddPorts(pgName, portsToAdd...); err != nil {
×
1350
                        klog.Errorf("add ports to port group %s: %v", pgName, err)
×
1351
                        return err
×
1352
                }
×
1353
        }
1354
        return nil
×
1355
}
1356

1357
func (c *Controller) reconcileDefaultCentralizedSubnetRouteInDefaultVpc(subnet *kubeovnv1.Subnet) error {
×
1358
        gatewayNodes, err := c.getGatewayNodes(subnet)
×
1359
        if err != nil {
×
1360
                klog.Errorf("failed to get gateway nodes for subnet %s: %v", subnet.Name, err)
×
1361
                return err
×
1362
        }
×
1363

1364
        // check if activateGateway still ready
1365
        if subnet.Status.ActivateGateway != "" && slices.Contains(gatewayNodes, subnet.Status.ActivateGateway) {
×
1366
                node, err := c.nodesLister.Get(subnet.Status.ActivateGateway)
×
1367
                if err == nil && nodeReady(node) {
×
1368
                        klog.Infof("subnet %s uses the old activate gw %s", subnet.Name, node.Name)
×
1369

×
1370
                        nodeTunlIPAddr, err := getNodeTunlIP(node)
×
1371
                        if err != nil {
×
1372
                                klog.Errorf("failed to get gatewayNode tunnel ip for subnet %s", subnet.Name)
×
1373
                                return err
×
1374
                        }
×
1375
                        nextHop := getNextHopByTunnelIP(nodeTunlIPAddr)
×
1376
                        if err = c.addPolicyRouteForCentralizedSubnet(subnet, subnet.Status.ActivateGateway, nil, strings.Split(nextHop, ",")); err != nil {
×
1377
                                klog.Errorf("failed to add active-backup policy route for centralized subnet %s: %v", subnet.Name, err)
×
1378
                                return err
×
1379
                        }
×
1380
                        return nil
×
1381
                }
1382
        }
1383

1384
        klog.Info("find a new activate node")
×
1385
        // need a new activate gateway
×
1386
        newActivateNode := ""
×
1387
        var nodeTunlIPAddr []net.IP
×
1388
        for _, gw := range gatewayNodes {
×
1389
                node, err := c.nodesLister.Get(gw)
×
1390
                if err == nil && nodeReady(node) {
×
1391
                        newActivateNode = node.Name
×
1392
                        nodeTunlIPAddr, err = getNodeTunlIP(node)
×
1393
                        if err != nil {
×
1394
                                klog.Error(err)
×
1395
                                return err
×
1396
                        }
×
1397
                        klog.Infof("subnet %s uses a new activate gw %s", subnet.Name, node.Name)
×
1398
                        break
×
1399
                }
1400
        }
1401
        if newActivateNode == "" {
×
1402
                klog.Warningf("all gateways of subnet %s are not ready", subnet.Name)
×
1403
                subnet.Status.ActivateGateway = newActivateNode
×
1404
                if err := c.patchSubnetStatus(subnet, "NoActiveGatewayFound", fmt.Sprintf("subnet %s gws are not ready", subnet.Name)); err != nil {
×
1405
                        klog.Error(err)
×
1406
                        return err
×
1407
                }
×
1408

1409
                return fmt.Errorf("subnet %s gws are not ready", subnet.Name)
×
1410
        }
1411

1412
        nextHop := getNextHopByTunnelIP(nodeTunlIPAddr)
×
1413
        klog.Infof("subnet %s configure new gateway node, nextHop %s", subnet.Name, nextHop)
×
1414
        if err := c.addPolicyRouteForCentralizedSubnet(subnet, newActivateNode, nil, strings.Split(nextHop, ",")); err != nil {
×
1415
                klog.Errorf("failed to add policy route for active-backup centralized subnet %s: %v", subnet.Name, err)
×
1416
                return err
×
1417
        }
×
1418
        subnet.Status.ActivateGateway = newActivateNode
×
1419
        if err := c.patchSubnetStatus(subnet, "ReconcileCentralizedGatewaySuccess", ""); err != nil {
×
1420
                klog.Error(err)
×
1421
                return err
×
1422
        }
×
1423

1424
        klog.Infof("delete old distributed policy route for subnet %s", subnet.Name)
×
1425
        if err := c.deletePolicyRouteByGatewayType(subnet, kubeovnv1.GWDistributedType, false); err != nil {
×
1426
                klog.Errorf("failed to delete policy route for overlay subnet %s, %v", subnet.Name, err)
×
1427
                return err
×
1428
        }
×
1429
        return nil
×
1430
}
1431

1432
func (c *Controller) reconcileEcmpCentralizedSubnetRouteInDefaultVpc(subnet *kubeovnv1.Subnet) error {
×
1433
        gatewayNodes, err := c.getGatewayNodes(subnet)
×
1434
        if err != nil {
×
1435
                klog.Errorf("failed to get gateway nodes for subnet %s: %v", subnet.Name, err)
×
1436
                return err
×
1437
        }
×
1438

1439
        nodeIPs := [2][]string{make([]string, 0, len(gatewayNodes)), make([]string, 0, len(gatewayNodes))}
×
1440
        nameIPMaps := [2]map[string]string{make(map[string]string, len(gatewayNodes)), make(map[string]string, len(gatewayNodes))}
×
1441

×
1442
        for _, gw := range gatewayNodes {
×
1443
                node, err := c.nodesLister.Get(gw)
×
1444
                if err != nil {
×
1445
                        klog.Errorf("failed to get gw node %s, %v", gw, err)
×
1446
                        continue
×
1447
                }
1448
                if !nodeReady(node) {
×
1449
                        klog.Errorf("gateway node %v is not ready", gw)
×
1450
                        continue
×
1451
                }
1452
                nexthopNodeIP := strings.TrimSpace(node.Annotations[util.IPAddressAnnotation])
×
1453
                if nexthopNodeIP == "" {
×
1454
                        klog.Errorf("gateway node %v has no ip annotation", node.Name)
×
1455
                        continue
×
1456
                }
1457
                nexthopV4, nexthopV6 := util.SplitStringIP(nexthopNodeIP)
×
1458
                if nexthopV4 != "" {
×
1459
                        nameIPMaps[0][node.Name] = nexthopV4
×
1460
                        nodeIPs[0] = append(nodeIPs[0], nexthopV4)
×
1461
                }
×
1462
                if nexthopV6 != "" {
×
1463
                        nameIPMaps[1][node.Name] = nexthopV6
×
1464
                        nodeIPs[1] = append(nodeIPs[1], nexthopV6)
×
1465
                }
×
1466
        }
1467

1468
        v4CIDR, v6CIDR := util.SplitStringIP(subnet.Spec.CIDRBlock)
×
1469
        cidrs := [2]string{v4CIDR, v6CIDR}
×
1470
        for i, cidr := range cidrs {
×
1471
                if len(nodeIPs[i]) == 0 || cidr == "" { // #nosec G602
×
1472
                        continue
×
1473
                }
1474
                klog.Infof("delete old distributed policy route for subnet %s", subnet.Name)
×
1475
                if err := c.deletePolicyRouteByGatewayType(subnet, kubeovnv1.GWDistributedType, false); err != nil {
×
1476
                        klog.Errorf("failed to delete policy route for overlay subnet %s, %v", subnet.Name, err)
×
1477
                        return err
×
1478
                }
×
1479
                klog.Infof("subnet %s configure ecmp policy route, nexthops %v", subnet.Name, nodeIPs[i])                     // #nosec G602
×
1480
                if err := c.updatePolicyRouteForCentralizedSubnet(subnet.Name, cidr, nodeIPs[i], nameIPMaps[i]); err != nil { // #nosec G602
×
1481
                        klog.Errorf("failed to add ecmp policy route for centralized subnet %s: %v", subnet.Name, err)
×
1482
                        return err
×
1483
                }
×
1484
        }
1485
        return nil
×
1486
}
1487

1488
func (c *Controller) reconcileOvnDefaultVpcRoute(subnet *kubeovnv1.Subnet) error {
×
1489
        if subnet.Name == c.config.NodeSwitch {
×
1490
                if err := c.addCommonRoutesForSubnet(subnet); err != nil {
×
1491
                        klog.Error(err)
×
1492
                        return err
×
1493
                }
×
1494
                return nil
×
1495
        }
1496

1497
        if subnet.Spec.Vlan != "" && !subnet.Spec.LogicalGateway {
×
1498
                // physical switch provide gw for this underlay subnet
×
1499
                pods, err := c.podsLister.Pods(metav1.NamespaceAll).List(labels.Everything())
×
1500
                if err != nil {
×
1501
                        klog.Errorf("failed to list pods %v", err)
×
1502
                        return err
×
1503
                }
×
1504
                for _, pod := range pods {
×
1505
                        if pod.Annotations[util.LogicalSwitchAnnotation] == subnet.Name && pod.Annotations[util.IPAddressAnnotation] != "" {
×
1506
                                if err := c.deleteStaticRoute(
×
1507
                                        pod.Annotations[util.IPAddressAnnotation], c.config.ClusterRouter, subnet.Spec.RouteTable); err != nil {
×
1508
                                        klog.Errorf("failed to delete static route %v", err)
×
1509
                                        return err
×
1510
                                }
×
1511
                        }
1512
                }
1513

1514
                if !subnet.Spec.LogicalGateway && subnet.Name != c.config.ExternalGatewaySwitch && !subnet.Spec.U2OInterconnection {
×
1515
                        lspName := fmt.Sprintf("%s-%s", subnet.Name, c.config.ClusterRouter)
×
1516
                        klog.Infof("delete logical switch port %s", lspName)
×
1517
                        if err := c.OVNNbClient.DeleteLogicalSwitchPort(lspName); err != nil {
×
1518
                                klog.Errorf("failed to delete lsp %s-%s, %v", subnet.Name, c.config.ClusterRouter, err)
×
1519
                                return err
×
1520
                        }
×
1521
                        lrpName := fmt.Sprintf("%s-%s", c.config.ClusterRouter, subnet.Name)
×
1522
                        klog.Infof("delete logical router port %s", lrpName)
×
1523
                        if err := c.OVNNbClient.DeleteLogicalRouterPort(lrpName); err != nil {
×
1524
                                klog.Errorf("failed to delete lrp %s: %v", lrpName, err)
×
1525
                                return err
×
1526
                        }
×
1527
                }
1528

1529
                if subnet.Spec.U2OInterconnection && subnet.Status.U2OInterconnectionIP != "" {
×
1530
                        if err := c.addPolicyRouteForU2OInterconn(subnet); err != nil {
×
1531
                                klog.Errorf("failed to add policy route for underlay to overlay subnet interconnection %s %v", subnet.Name, err)
×
1532
                                return err
×
1533
                        }
×
1534
                } else {
×
1535
                        if err := c.deletePolicyRouteForU2OInterconn(subnet); err != nil {
×
1536
                                klog.Errorf("failed to delete policy route for underlay to overlay subnet interconnection %s, %v", subnet.Name, err)
×
1537
                                return err
×
1538
                        }
×
1539
                }
1540

1541
                if (!c.config.EnableLb || (subnet.Spec.EnableLb == nil || !*subnet.Spec.EnableLb)) &&
×
1542
                        subnet.Spec.U2OInterconnection && subnet.Status.U2OInterconnectionIP != "" {
×
1543
                        if err := c.addPolicyRouteForU2ONoLoadBalancer(subnet); err != nil {
×
1544
                                klog.Errorf("failed to add policy route for underlay to overlay subnet interconnection without enabling loadbalancer %s %v", subnet.Name, err)
×
1545
                                return err
×
1546
                        }
×
1547
                } else {
×
1548
                        if err := c.deletePolicyRouteForU2ONoLoadBalancer(subnet); err != nil {
×
1549
                                klog.Errorf("failed to delete policy route for underlay to overlay subnet interconnection without enabling loadbalancer %s, %v", subnet.Name, err)
×
1550
                                return err
×
1551
                        }
×
1552
                }
1553
        } else {
×
1554
                // It's difficult to update policy route when subnet cidr is changed, add check for cidr changed situation
×
1555
                if err := c.reconcilePolicyRouteForCidrChangedSubnet(subnet, true); err != nil {
×
1556
                        klog.Error(err)
×
1557
                        return err
×
1558
                }
×
1559

1560
                if err := c.addCommonRoutesForSubnet(subnet); err != nil {
×
1561
                        klog.Error(err)
×
1562
                        return err
×
1563
                }
×
1564

1565
                // distributed subnet, only add distributed policy route
1566
                if subnet.Spec.GatewayType == kubeovnv1.GWDistributedType {
×
1567
                        if err := c.reconcileDistributedSubnetRouteInDefaultVpc(subnet); err != nil {
×
1568
                                klog.Error(err)
×
1569
                                return err
×
1570
                        }
×
1571
                } else {
×
1572
                        // centralized subnet
×
1573
                        if subnet.Spec.GatewayNode == "" && len(subnet.Spec.GatewayNodeSelectors) == 0 {
×
1574
                                subnet.Status.NotReady("NoReadyGateway", "")
×
1575
                                if err := c.patchSubnetStatus(subnet, "NoReadyGateway", ""); err != nil {
×
1576
                                        klog.Error(err)
×
1577
                                        return err
×
1578
                                }
×
1579
                                err := fmt.Errorf("subnet %s Spec.GatewayNode or Spec.GatewayNodeSelectors must be specified for centralized gateway type", subnet.Name)
×
1580
                                klog.Error(err)
×
1581
                                return err
×
1582
                        }
1583

1584
                        gwNodeExists := c.checkSubnetGwNodesExist(subnet)
×
1585
                        if !gwNodeExists {
×
1586
                                klog.Errorf("failed to init centralized gateway for subnet %s, no gateway node exists", subnet.Name)
×
1587
                                return errors.New("failed to add ecmp policy route, no gateway node exists")
×
1588
                        }
×
1589

1590
                        if err := c.reconcilePolicyRouteForCidrChangedSubnet(subnet, false); err != nil {
×
1591
                                klog.Error(err)
×
1592
                                return err
×
1593
                        }
×
1594

1595
                        if subnet.Spec.EnableEcmp {
×
1596
                                if err := c.reconcileEcmpCentralizedSubnetRouteInDefaultVpc(subnet); err != nil {
×
1597
                                        klog.Error(err)
×
1598
                                        return err
×
1599
                                }
×
1600
                        } else {
×
1601
                                if err := c.reconcileDefaultCentralizedSubnetRouteInDefaultVpc(subnet); err != nil {
×
1602
                                        klog.Error(err)
×
1603
                                        return err
×
1604
                                }
×
1605
                        }
1606
                }
1607
        }
1608
        return nil
×
1609
}
1610

1611
func (c *Controller) reconcileCustomVpcStaticRoute(subnet *kubeovnv1.Subnet) error {
×
1612
        // in custom vpc, subnet gw type is unmeaning
×
1613
        // 1. vpc out to public network through vpc nat gw pod, the static route is auto managed by admin user
×
1614
        // 2. vpc out to public network through ovn nat lrp, whose nexthop rely on bfd ecmp, the vpc spec bfd static route is auto managed here
×
1615
        // 3. vpc out to public network through ovn nat lrp, without bfd ecmp, the vpc spec static route is auto managed here
×
1616

×
1617
        vpc, err := c.vpcsLister.Get(subnet.Spec.Vpc)
×
1618
        if err != nil {
×
1619
                if k8serrors.IsNotFound(err) {
×
1620
                        return nil
×
1621
                }
×
1622
                klog.Errorf("failed to get vpc %s, %v", subnet.Spec.Vpc, err)
×
1623
                return err
×
1624
        }
1625

1626
        if vpc.Spec.EnableExternal && vpc.Spec.EnableBfd && subnet.Spec.EnableEcmp {
×
1627
                klog.Infof("add bfd and external static ecmp route for vpc %s, subnet %s", vpc.Name, subnet.Name)
×
1628
                // handle vpc static route
×
1629
                // use static ecmp route with bfd
×
1630
                // bfd ecmp static route depend on subnet cidr
×
1631
                if err := c.reconcileCustomVpcBfdStaticRoute(vpc.Name, subnet.Name); err != nil {
×
1632
                        klog.Errorf("failed to reconcile vpc %q bfd static route", vpc.Name)
×
1633
                        return err
×
1634
                }
×
1635
        }
1636

1637
        if subnet.Spec.Vlan == "" || subnet.Spec.LogicalGateway || subnet.Spec.U2OInterconnection {
×
1638
                if err = c.addCustomVPCStaticRouteForSubnet(subnet); err != nil {
×
1639
                        klog.Errorf("failed to add static route for underlay to overlay subnet interconnection %s %v", subnet.Name, err)
×
1640
                        return err
×
1641
                }
×
1642
                if err = c.addCommonRoutesForSubnet(subnet); err != nil {
×
1643
                        klog.Error(err)
×
1644
                        return err
×
1645
                }
×
1646
        }
1647

1648
        if subnet.Spec.Vlan != "" && !subnet.Spec.LogicalGateway && subnet.Spec.U2OInterconnection && subnet.Status.U2OInterconnectionIP != "" {
×
1649
                if err := c.addPolicyRouteForU2OInterconn(subnet); err != nil {
×
1650
                        klog.Errorf("failed to add policy route for underlay to overlay subnet interconnection %s %v", subnet.Name, err)
×
1651
                        return err
×
1652
                }
×
1653
        }
1654

1655
        return nil
×
1656
}
1657

1658
func (c *Controller) deleteStaticRoute(ip, router, routeTable string) error {
×
1659
        for ipStr := range strings.SplitSeq(ip, ",") {
×
1660
                if err := c.deleteStaticRouteFromVpc(
×
1661
                        router,
×
1662
                        routeTable,
×
1663
                        ipStr,
×
1664
                        "",
×
1665
                        kubeovnv1.PolicyDst,
×
1666
                ); err != nil {
×
1667
                        klog.Errorf("failed to delete static route %s, %v", ipStr, err)
×
1668
                        return err
×
1669
                }
×
1670
        }
1671

1672
        return nil
×
1673
}
1674

1675
func (c *Controller) reconcileVlan(subnet *kubeovnv1.Subnet) error {
×
1676
        if subnet.Spec.Vlan == "" {
×
1677
                return nil
×
1678
        }
×
1679
        klog.Infof("reconcile vlan %v", subnet.Spec.Vlan)
×
1680

×
1681
        vlan, err := c.vlansLister.Get(subnet.Spec.Vlan)
×
1682
        if err != nil {
×
1683
                klog.Errorf("failed to get vlan %s: %v", subnet.Spec.Vlan, err)
×
1684
                return err
×
1685
        }
×
1686
        if vlan.Status.Conflict {
×
1687
                err = fmt.Errorf("subnet %s has invalid conflict vlan %s", subnet.Name, vlan.Name)
×
1688
                klog.Error(err)
×
1689
                return err
×
1690
        }
×
1691

1692
        localnetPort := ovs.GetLocalnetName(subnet.Name)
×
1693
        if err := c.OVNNbClient.CreateLocalnetLogicalSwitchPort(subnet.Name, localnetPort, vlan.Spec.Provider, subnet.Spec.CIDRBlock, vlan.Spec.ID); err != nil {
×
1694
                klog.Errorf("create localnet port for subnet %s: %v", subnet.Name, err)
×
1695
                return err
×
1696
        }
×
1697

1698
        if !slices.Contains(vlan.Status.Subnets, subnet.Name) {
×
1699
                newVlan := vlan.DeepCopy()
×
1700
                newVlan.Status.Subnets = append(newVlan.Status.Subnets, subnet.Name)
×
1701
                _, err = c.config.KubeOvnClient.KubeovnV1().Vlans().UpdateStatus(context.Background(), newVlan, metav1.UpdateOptions{})
×
1702
                if err != nil {
×
1703
                        klog.Errorf("failed to update status of vlan %s: %v", vlan.Name, err)
×
1704
                        return err
×
1705
                }
×
1706
        }
1707

1708
        return nil
×
1709
}
1710

1711
func (c *Controller) reconcileSubnetSpecialIPs(subnet *kubeovnv1.Subnet) (bool, bool, error) {
×
1712
        isU2OIPChanged := false
×
1713
        isMcastQuerierIPChanged := false
×
1714
        var err error
×
1715

×
1716
        // reconcile u2o IP
×
1717
        if subnet.Spec.Vlan != "" && !subnet.Spec.LogicalGateway {
×
1718
                u2oInterconnName := fmt.Sprintf(util.U2OInterconnName, subnet.Spec.Vpc, subnet.Name)
×
1719
                u2oInterconnLrpName := fmt.Sprintf("%s-%s", subnet.Spec.Vpc, subnet.Name)
×
1720
                var v4ip, v6ip string
×
1721
                if subnet.Spec.U2OInterconnection {
×
1722
                        v4ip, v6ip, _, err = c.acquireU2OIP(subnet, u2oInterconnName, u2oInterconnLrpName)
×
1723
                        if err != nil {
×
1724
                                return isU2OIPChanged, isMcastQuerierIPChanged, err
×
1725
                        }
×
1726

1727
                        if v4ip != "" || v6ip != "" {
×
1728
                                isU2OIPChanged = true
×
1729
                        }
×
1730
                } else if subnet.Status.U2OInterconnectionIP != "" {
×
1731
                        err = c.releaseU2OIP(subnet, u2oInterconnName)
×
1732
                        if err != nil {
×
1733
                                return isU2OIPChanged, isMcastQuerierIPChanged, err
×
1734
                        }
×
1735
                        isU2OIPChanged = true
×
1736
                }
1737

1738
                if isU2OIPChanged {
×
1739
                        klog.Infof("reconcile underlay subnet %s to overlay interconnection with U2OInterconnection %v U2OInterconnectionIP %s",
×
1740
                                subnet.Name, subnet.Spec.U2OInterconnection, subnet.Status.U2OInterconnectionIP)
×
1741
                }
×
1742
        }
1743

1744
        // reconcile mcast querier IP
1745
        if subnet.Spec.EnableMulticastSnoop {
×
1746
                isMcastQuerierIPChanged, err = c.acquireMcastQuerierIP(subnet)
×
1747
                if err != nil {
×
1748
                        return isU2OIPChanged, isMcastQuerierIPChanged, err
×
1749
                }
×
1750
        } else {
×
1751
                isMcastQuerierIPChanged, err = c.releaseMcastQuerierIP(subnet)
×
1752
                if err != nil {
×
1753
                        return isU2OIPChanged, isMcastQuerierIPChanged, err
×
1754
                }
×
1755
        }
1756

1757
        // calculate subnet status
1758
        if isU2OIPChanged || isMcastQuerierIPChanged {
×
1759
                if _, err := c.calcSubnetStatusIP(subnet); err != nil {
×
1760
                        klog.Error(err)
×
1761
                        return isU2OIPChanged, isMcastQuerierIPChanged, err
×
1762
                }
×
1763
        }
1764

1765
        return isU2OIPChanged, isMcastQuerierIPChanged, nil
×
1766
}
1767

1768
func (c *Controller) acquireU2OIP(subnet *kubeovnv1.Subnet, u2oInterconnName, u2oInterconnLrpName string) (string, string, string, error) {
×
1769
        var v4ip, v6ip, mac string
×
1770
        var err error
×
1771
        if subnet.Spec.U2OInterconnectionIP == "" && (subnet.Status.U2OInterconnectionIP == "" || subnet.Status.U2OInterconnectionMAC == "") {
×
1772
                v4ip, v6ip, mac, err = c.acquireIPAddress(subnet.Name, u2oInterconnName, u2oInterconnLrpName)
×
1773
                if err != nil {
×
1774
                        klog.Errorf("failed to acquire underlay to overlay interconnection ip address for subnet %s, %v", subnet.Name, err)
×
1775
                        return "", "", "", err
×
1776
                }
×
1777
        } else if subnet.Spec.U2OInterconnectionIP != "" && subnet.Status.U2OInterconnectionIP != subnet.Spec.U2OInterconnectionIP {
×
1778
                if subnet.Status.U2OInterconnectionIP != "" {
×
1779
                        klog.Infof("release underlay to overlay interconnection ip address %s for subnet %s", subnet.Status.U2OInterconnectionIP, subnet.Name)
×
1780
                        c.ipam.ReleaseAddressByPod(u2oInterconnName, subnet.Name)
×
1781
                }
×
1782
                v4ip, v6ip, mac, err = c.acquireStaticIPAddress(subnet.Name, u2oInterconnName, u2oInterconnLrpName, subnet.Spec.U2OInterconnectionIP, nil)
×
1783
                if err != nil {
×
1784
                        klog.Errorf("failed to acquire static underlay to overlay interconnection ip address for subnet %s, %v", subnet.Name, err)
×
1785
                        return "", "", "", err
×
1786
                }
×
1787
        }
1788
        if v4ip != "" || v6ip != "" {
×
1789
                switch subnet.Spec.Protocol {
×
1790
                case kubeovnv1.ProtocolIPv4:
×
1791
                        subnet.Status.U2OInterconnectionIP = v4ip
×
1792
                case kubeovnv1.ProtocolIPv6:
×
1793
                        subnet.Status.U2OInterconnectionIP = v6ip
×
1794
                case kubeovnv1.ProtocolDual:
×
1795
                        subnet.Status.U2OInterconnectionIP = fmt.Sprintf("%s,%s", v4ip, v6ip)
×
1796
                }
1797
                err = c.createOrUpdateIPCR("", u2oInterconnName, subnet.Status.U2OInterconnectionIP, mac, subnet.Name, "default", "", "")
×
1798
                if err != nil {
×
1799
                        klog.Errorf("failed to create or update IPs of %s : %v", u2oInterconnLrpName, err)
×
1800
                        return "", "", "", err
×
1801
                }
×
1802
                subnet.Status.U2OInterconnectionMAC = mac
×
1803
        }
1804
        return v4ip, v6ip, mac, nil
×
1805
}
1806

1807
func (c *Controller) releaseU2OIP(subnet *kubeovnv1.Subnet, u2oInterconnName string) error {
×
1808
        klog.Infof("release underlay to overlay interconnection ip address %s for subnet %s", subnet.Status.U2OInterconnectionIP, subnet.Name)
×
1809
        c.ipam.ReleaseAddressByPod(u2oInterconnName, subnet.Name)
×
1810
        subnet.Status.U2OInterconnectionIP = ""
×
1811
        subnet.Status.U2OInterconnectionMAC = ""
×
1812
        subnet.Status.U2OInterconnectionVPC = ""
×
1813

×
1814
        err := c.config.KubeOvnClient.KubeovnV1().IPs().Delete(context.Background(), u2oInterconnName, metav1.DeleteOptions{})
×
1815
        if err != nil && !k8serrors.IsNotFound(err) {
×
1816
                klog.Errorf("failed to delete ip %s, %v", u2oInterconnName, err)
×
1817
                return err
×
1818
        }
×
1819

1820
        return nil
×
1821
}
1822

1823
func (c *Controller) acquireMcastQuerierIP(subnet *kubeovnv1.Subnet) (bool, error) {
×
1824
        isMcastQuerierChanged := false
×
1825
        mcastQuerierLspName := fmt.Sprintf(util.McastQuerierName, subnet.Name)
×
1826
        var v4ip, v6ip, mac string
×
1827
        var err error
×
1828

×
1829
        if subnet.Status.McastQuerierIP == "" || subnet.Status.McastQuerierMAC == "" {
×
1830
                v4ip, v6ip, mac, err = c.acquireIPAddress(subnet.Name, mcastQuerierLspName, mcastQuerierLspName)
×
1831
                if err != nil {
×
1832
                        klog.Errorf("failed to acquire mcast querier ip address for subnet %s, %v", subnet.Name, err)
×
1833
                        return isMcastQuerierChanged, err
×
1834
                }
×
1835
        }
1836

1837
        if v4ip != "" || v6ip != "" {
×
1838
                switch subnet.Spec.Protocol {
×
1839
                case kubeovnv1.ProtocolIPv4:
×
1840
                        subnet.Status.McastQuerierIP = v4ip
×
1841
                case kubeovnv1.ProtocolIPv6:
×
1842
                        subnet.Status.McastQuerierIP = v6ip
×
1843
                case kubeovnv1.ProtocolDual:
×
1844
                        subnet.Status.McastQuerierIP = fmt.Sprintf("%s,%s", v4ip, v6ip)
×
1845
                }
1846

1847
                err := c.createOrUpdateIPCR("", mcastQuerierLspName, subnet.Status.McastQuerierIP, mac, subnet.Name, "default", "", "")
×
1848
                if err != nil {
×
1849
                        klog.Errorf("failed to create or update IPs of %s : %v", mcastQuerierLspName, err)
×
1850
                        return isMcastQuerierChanged, err
×
1851
                }
×
1852

1853
                subnet.Status.McastQuerierMAC = mac
×
1854
                klog.Infof("reconcile subnet %s mcast querier IP %s mac %s",
×
1855
                        subnet.Name, subnet.Status.McastQuerierIP, subnet.Status.McastQuerierMAC)
×
1856
                isMcastQuerierChanged = true
×
1857
        }
1858

1859
        return isMcastQuerierChanged, nil
×
1860
}
1861

1862
func (c *Controller) releaseMcastQuerierIP(subnet *kubeovnv1.Subnet) (bool, error) {
×
1863
        isMcastQuerierChanged := false
×
1864
        if subnet.Status.McastQuerierIP != "" {
×
1865
                mcastQuerierLspName := fmt.Sprintf(util.McastQuerierName, subnet.Name)
×
1866
                klog.Infof("release mcast querier ip address %s for subnet %s", subnet.Status.McastQuerierIP, subnet.Name)
×
1867
                c.ipam.ReleaseAddressByPod(mcastQuerierLspName, subnet.Name)
×
1868
                subnet.Status.McastQuerierIP = ""
×
1869
                subnet.Status.McastQuerierMAC = ""
×
1870

×
1871
                if err := c.config.KubeOvnClient.KubeovnV1().IPs().Delete(context.Background(), mcastQuerierLspName, metav1.DeleteOptions{}); err != nil {
×
1872
                        if !k8serrors.IsNotFound(err) {
×
1873
                                klog.Errorf("failed to delete ip %s, %v", mcastQuerierLspName, err)
×
1874
                                return isMcastQuerierChanged, err
×
1875
                        }
×
1876
                }
1877
                isMcastQuerierChanged = true
×
1878
                klog.Infof("reconcile subnet %s mcast querier IP %s mac %s",
×
1879
                        subnet.Name, subnet.Status.McastQuerierIP, subnet.Status.McastQuerierMAC)
×
1880
        }
1881
        return isMcastQuerierChanged, nil
×
1882
}
1883

1884
func isOvnSubnet(subnet *kubeovnv1.Subnet) bool {
1✔
1885
        return subnet != nil && util.IsOvnProvider(subnet.Spec.Provider)
1✔
1886
}
1✔
1887

1888
func formatExcludeIPRanges(subnet *kubeovnv1.Subnet) {
1✔
1889
        var excludeIPs []string
1✔
1890
        mapIPs := make(map[string]*ipam.IPRange, len(subnet.Spec.ExcludeIps))
1✔
1891
        for _, excludeIP := range subnet.Spec.ExcludeIps {
2✔
1892
                if _, ok := mapIPs[excludeIP]; !ok {
2✔
1893
                        ips := strings.Split(excludeIP, "..")
1✔
1894
                        start, _ := ipam.NewIP(ips[0])
1✔
1895
                        end := start
1✔
1896
                        if len(ips) != 1 {
1✔
1897
                                end, _ = ipam.NewIP(ips[1])
×
1898
                        }
×
1899
                        mapIPs[excludeIP] = ipam.NewIPRange(start, end)
1✔
1900
                }
1901
        }
1902
        newMap := filterRepeatIPRange(mapIPs)
1✔
1903
        for _, v := range newMap {
2✔
1904
                if v.Start().Equal(v.End()) {
2✔
1905
                        excludeIPs = append(excludeIPs, v.Start().String())
1✔
1906
                } else {
1✔
1907
                        excludeIPs = append(excludeIPs, v.Start().String()+".."+v.End().String())
×
1908
                }
×
1909
        }
1910
        sort.Strings(excludeIPs)
1✔
1911
        if !slices.Equal(subnet.Spec.ExcludeIps, excludeIPs) {
1✔
1912
                klog.V(3).Infof("excludeips before format is %v, after format is %v", subnet.Spec.ExcludeIps, excludeIPs)
×
1913
                subnet.Spec.ExcludeIps = excludeIPs
×
1914
        }
×
1915
}
1916

1917
func filterRepeatIPRange(mapIPs map[string]*ipam.IPRange) map[string]*ipam.IPRange {
1✔
1918
        for ka, a := range mapIPs {
2✔
1919
                for kb, b := range mapIPs {
2✔
1920
                        if ka == kb && a == b {
2✔
1921
                                continue
1✔
1922
                        }
1923

1924
                        if b.End().LessThan(a.Start()) || b.Start().GreaterThan(a.End()) {
2✔
1925
                                continue
1✔
1926
                        }
1927

1928
                        if (a.Start().Equal(b.Start()) || a.Start().GreaterThan(b.Start())) &&
×
1929
                                (a.End().Equal(b.End()) || a.End().LessThan(b.End())) {
×
1930
                                delete(mapIPs, ka)
×
1931
                                continue
×
1932
                        }
1933

1934
                        if (a.Start().Equal(b.Start()) || a.Start().GreaterThan(b.Start())) &&
×
1935
                                a.End().GreaterThan(b.End()) {
×
1936
                                delete(mapIPs, ka)
×
1937
                                mapIPs[kb] = ipam.NewIPRange(b.Start(), a.End())
×
1938
                                continue
×
1939
                        }
1940

1941
                        if (a.End().Equal(b.End()) || a.End().LessThan(b.End())) &&
×
1942
                                a.Start().LessThan(b.Start()) {
×
1943
                                delete(mapIPs, ka)
×
1944
                                mapIPs[kb] = ipam.NewIPRange(a.Start(), b.End())
×
1945
                                continue
×
1946
                        }
1947

1948
                        // a contains b
1949
                        mapIPs[kb] = a
×
1950
                        delete(mapIPs, ka)
×
1951
                }
1952
        }
1953
        return mapIPs
1✔
1954
}
1955

1956
func (c *Controller) checkGwNodeExists(gatewayNode string) bool {
×
1957
        found := false
×
1958
        for gwName := range strings.SplitSeq(gatewayNode, ",") {
×
1959
                // the format of gatewayNode can be like 'kube-ovn-worker:172.18.0.2, kube-ovn-control-plane:172.18.0.3', which consists of node name and designative egress ip
×
1960
                if strings.Contains(gwName, ":") {
×
1961
                        gwName = strings.TrimSpace(strings.Split(gwName, ":")[0])
×
1962
                } else {
×
1963
                        gwName = strings.TrimSpace(gwName)
×
1964
                }
×
1965

1966
                gwNode, err := c.nodesLister.Get(gwName)
×
1967
                if err != nil {
×
1968
                        if k8serrors.IsNotFound(err) {
×
1969
                                klog.Errorf("gw node %s does not exist, %v", gwName, err)
×
1970
                                continue
×
1971
                        }
1972
                }
1973
                if gwNode != nil {
×
1974
                        found = true
×
1975
                        break
×
1976
                }
1977
        }
1978
        return found
×
1979
}
1980

1981
func (c *Controller) getGatewayNodes(subnet *kubeovnv1.Subnet) ([]string, error) {
×
1982
        if subnet.Spec.GatewayNode != "" {
×
1983
                var nodes []string
×
1984
                for gw := range strings.SplitSeq(subnet.Spec.GatewayNode, ",") {
×
1985
                        if strings.Contains(gw, ":") {
×
1986
                                gw = strings.TrimSpace(strings.Split(gw, ":")[0])
×
1987
                        } else {
×
1988
                                gw = strings.TrimSpace(gw)
×
1989
                        }
×
1990
                        if gw != "" {
×
1991
                                nodes = append(nodes, gw)
×
1992
                        }
×
1993
                }
1994
                return nodes, nil
×
1995
        }
1996

1997
        if len(subnet.Spec.GatewayNodeSelectors) > 0 {
×
1998
                return c.getNodesBySelectors(subnet.Spec.GatewayNodeSelectors)
×
1999
        }
×
2000

2001
        return nil, nil
×
2002
}
2003

2004
func (c *Controller) getNodesBySelectors(selectors []metav1.LabelSelector) ([]string, error) {
×
2005
        nodeSet := make(map[string]struct{})
×
2006
        for _, selector := range selectors {
×
2007
                labelSelector, err := metav1.LabelSelectorAsSelector(&selector)
×
2008
                if err != nil {
×
2009
                        klog.Errorf("failed to convert label selector: %v", err)
×
2010
                        continue
×
2011
                }
2012
                nodes, err := c.nodesLister.List(labelSelector)
×
2013
                if err != nil {
×
2014
                        return nil, fmt.Errorf("failed to list nodes with selector %s: %w", labelSelector.String(), err)
×
2015
                }
×
2016
                for _, node := range nodes {
×
2017
                        nodeSet[node.Name] = struct{}{}
×
2018
                }
×
2019
        }
2020

2021
        matchedNodes := make([]string, 0, len(nodeSet))
×
2022
        for name := range nodeSet {
×
2023
                matchedNodes = append(matchedNodes, name)
×
2024
        }
×
2025
        return matchedNodes, nil
×
2026
}
2027

2028
func (c *Controller) checkSubnetGwNodesExist(subnet *kubeovnv1.Subnet) bool {
×
2029
        if subnet.Spec.GatewayNode != "" {
×
2030
                return c.checkGwNodeExists(subnet.Spec.GatewayNode)
×
2031
        }
×
2032

2033
        if len(subnet.Spec.GatewayNodeSelectors) > 0 {
×
2034
                nodes, err := c.getNodesBySelectors(subnet.Spec.GatewayNodeSelectors)
×
2035
                if err != nil {
×
2036
                        klog.Errorf("failed to get nodes by selectors: %v", err)
×
2037
                        return false
×
2038
                }
×
2039
                return len(nodes) > 0
×
2040
        }
2041

2042
        return false
×
2043
}
2044

2045
func getIPSuffix(protocol string) string {
×
2046
        if protocol == kubeovnv1.ProtocolIPv6 {
×
2047
                return "ip6"
×
2048
        }
×
2049
        return "ip4"
×
2050
}
2051

2052
func buildPolicyRouteExternalIDs(subnetName string, extraIDs map[string]string) map[string]string {
×
2053
        externalIDs := map[string]string{
×
2054
                "vendor": util.CniTypeName,
×
2055
                "subnet": subnetName,
×
2056
        }
×
2057
        maps.Copy(externalIDs, extraIDs)
×
2058
        return externalIDs
×
2059
}
×
2060

2061
func (c *Controller) logicalRouterExists(vpcName string) bool {
×
2062
        lr, err := c.OVNNbClient.GetLogicalRouter(vpcName, true)
×
2063
        if err == nil && lr == nil {
×
2064
                klog.Infof("logical router %s already deleted", vpcName)
×
2065
                return false
×
2066
        }
×
2067
        return true
×
2068
}
2069

2070
func (c *Controller) addCommonRoutesForSubnet(subnet *kubeovnv1.Subnet) error {
×
2071
        for cidr := range strings.SplitSeq(subnet.Spec.CIDRBlock, ",") {
×
2072
                if cidr == "" {
×
2073
                        continue
×
2074
                }
2075

2076
                var gateway string
×
2077
                protocol := util.CheckProtocol(cidr)
×
2078
                for gw := range strings.SplitSeq(subnet.Spec.Gateway, ",") {
×
2079
                        if util.CheckProtocol(gw) == protocol {
×
2080
                                gateway = gw
×
2081
                                break
×
2082
                        }
2083
                }
2084
                if gateway == "" {
×
2085
                        return fmt.Errorf("failed to get gateway of CIDR %s", cidr)
×
2086
                }
×
2087

2088
                ipSuffix := getIPSuffix(protocol)
×
2089
                match := fmt.Sprintf("%s.dst == %s", ipSuffix, cidr)
×
2090
                action := kubeovnv1.PolicyRouteActionAllow
×
2091
                externalIDs := buildPolicyRouteExternalIDs(subnet.Name, nil)
×
2092

×
2093
                klog.Infof("add common policy route for router: %s, match %s, action %s, externalID %v", subnet.Spec.Vpc, match, action, externalIDs)
×
2094
                if err := c.addPolicyRouteToVpc(
×
2095
                        subnet.Spec.Vpc,
×
2096
                        &kubeovnv1.PolicyRoute{
×
2097
                                Priority: util.SubnetRouterPolicyPriority,
×
2098
                                Match:    match,
×
2099
                                Action:   action,
×
2100
                        },
×
2101
                        externalIDs,
×
2102
                ); err != nil {
×
2103
                        klog.Errorf("failed to add logical router policy for CIDR %s of subnet %s: %v", cidr, subnet.Name, err)
×
2104
                        return err
×
2105
                }
×
2106
        }
2107
        return nil
×
2108
}
2109

2110
func getOverlaySubnetsPortGroupName(subnetName, nodeName string) string {
×
2111
        return strings.ReplaceAll(fmt.Sprintf("%s.%s", subnetName, nodeName), "-", ".")
×
2112
}
×
2113

2114
func (c *Controller) createPortGroupForDistributedSubnet(node *v1.Node, subnet *kubeovnv1.Subnet) error {
×
2115
        if subnet.Spec.Vlan != "" && !subnet.Spec.LogicalGateway {
×
2116
                return nil
×
2117
        }
×
2118
        if subnet.Spec.Vpc != c.config.ClusterRouter || subnet.Name == c.config.NodeSwitch {
×
2119
                return nil
×
2120
        }
×
2121

2122
        pgName := getOverlaySubnetsPortGroupName(subnet.Name, node.Name)
×
2123
        externalIDs := map[string]string{
×
2124
                "subnet":         subnet.Name,
×
2125
                "node":           node.Name,
×
2126
                "vendor":         util.CniTypeName,
×
2127
                networkPolicyKey: subnet.Name + "/" + node.Name,
×
2128
        }
×
2129
        if err := c.OVNNbClient.CreatePortGroup(pgName, externalIDs); err != nil {
×
2130
                klog.Errorf("create port group for subnet %s and node %s: %v", subnet.Name, node.Name, err)
×
2131
                return err
×
2132
        }
×
2133

2134
        return nil
×
2135
}
2136

2137
func (c *Controller) updatePolicyRouteForCentralizedSubnet(subnetName, cidr string, nextHops []string, nameIPMap map[string]string) error {
×
2138
        ipSuffix := getIPSuffix(util.CheckProtocol(cidr))
×
2139
        match := fmt.Sprintf("%s.src == %s", ipSuffix, cidr)
×
2140
        action := kubeovnv1.PolicyRouteActionReroute
×
2141
        externalIDs := buildPolicyRouteExternalIDs(subnetName, nameIPMap)
×
2142

×
2143
        klog.Infof("add policy route for router: %s, match %s, action %s, nexthops %v, externalID %s", c.config.ClusterRouter, match, action, nextHops, externalIDs)
×
2144
        if err := c.addPolicyRouteToVpc(
×
2145
                c.config.ClusterRouter,
×
2146
                &kubeovnv1.PolicyRoute{
×
2147
                        Priority:  util.GatewayRouterPolicyPriority,
×
2148
                        Match:     match,
×
2149
                        Action:    action,
×
2150
                        NextHopIP: strings.Join(nextHops, ","),
×
2151
                },
×
2152
                externalIDs,
×
2153
        ); err != nil {
×
2154
                klog.Errorf("failed to add policy route for centralized subnet %s: %v", subnetName, err)
×
2155
                return err
×
2156
        }
×
2157
        return nil
×
2158
}
2159

2160
func (c *Controller) addPolicyRouteForCentralizedSubnet(subnet *kubeovnv1.Subnet, nodeName string, ipNameMap map[string]string, nodeIPs []string) error {
×
2161
        for _, nodeIP := range nodeIPs {
×
2162
                // node v4ip v6ip
×
2163
                for cidrBlock := range strings.SplitSeq(subnet.Spec.CIDRBlock, ",") {
×
2164
                        if util.CheckProtocol(cidrBlock) != util.CheckProtocol(nodeIP) {
×
2165
                                continue
×
2166
                        }
2167
                        // Check for repeat policy route is processed in AddPolicyRoute
2168

2169
                        var nextHops []string
×
2170
                        nameIPMap := map[string]string{}
×
2171
                        nextHops = append(nextHops, nodeIP)
×
2172
                        tmpName := nodeName
×
2173
                        if nodeName == "" {
×
2174
                                tmpName = ipNameMap[nodeIP]
×
2175
                        }
×
2176
                        nameIPMap[tmpName] = nodeIP
×
2177
                        if err := c.updatePolicyRouteForCentralizedSubnet(subnet.Name, cidrBlock, nextHops, nameIPMap); err != nil {
×
2178
                                klog.Error(err)
×
2179
                                return err
×
2180
                        }
×
2181
                }
2182
        }
2183
        return nil
×
2184
}
2185

2186
func (c *Controller) deletePolicyRouteForCentralizedSubnet(subnet *kubeovnv1.Subnet) error {
×
2187
        for cidr := range strings.SplitSeq(subnet.Spec.CIDRBlock, ",") {
×
2188
                ipSuffix := getIPSuffix(util.CheckProtocol(cidr))
×
2189
                match := fmt.Sprintf("%s.src == %s", ipSuffix, cidr)
×
2190
                klog.Infof("delete policy route for router: %s, priority: %d, match %s", c.config.ClusterRouter, util.GatewayRouterPolicyPriority, match)
×
2191
                if err := c.deletePolicyRouteFromVpc(c.config.ClusterRouter, util.GatewayRouterPolicyPriority, match); err != nil {
×
2192
                        klog.Errorf("failed to delete policy route for centralized subnet %s: %v", subnet.Name, err)
×
2193
                        return err
×
2194
                }
×
2195
        }
2196
        return nil
×
2197
}
2198

2199
func (c *Controller) addPolicyRouteForDistributedSubnet(subnet *kubeovnv1.Subnet, nodeName, nodeIPv4, nodeIPv6 string) error {
×
2200
        if subnet.Spec.Vlan != "" && !subnet.Spec.LogicalGateway {
×
2201
                return nil
×
2202
        }
×
2203
        if subnet.Spec.Vpc != c.config.ClusterRouter || subnet.Name == c.config.NodeSwitch {
×
2204
                return nil
×
2205
        }
×
2206

2207
        pgName := getOverlaySubnetsPortGroupName(subnet.Name, nodeName)
×
2208
        for cidrBlock := range strings.SplitSeq(subnet.Spec.CIDRBlock, ",") {
×
2209
                ipSuffix := getIPSuffix(util.CheckProtocol(cidrBlock))
×
2210
                nodeIP := nodeIPv4
×
2211
                if ipSuffix == "ip6" {
×
2212
                        nodeIP = nodeIPv6
×
2213
                }
×
2214
                if nodeIP == "" {
×
2215
                        continue
×
2216
                }
2217

2218
                pgAs := fmt.Sprintf("%s_%s", pgName, ipSuffix)
×
2219
                match := fmt.Sprintf("%s.src == $%s", ipSuffix, pgAs)
×
2220
                action := kubeovnv1.PolicyRouteActionReroute
×
2221
                externalIDs := buildPolicyRouteExternalIDs(subnet.Name, map[string]string{"node": nodeName})
×
2222

×
2223
                klog.Infof("add policy route for router: %s, match %s, action %s, externalID %v", c.config.ClusterRouter, match, action, externalIDs)
×
2224
                if err := c.addPolicyRouteToVpc(
×
2225
                        c.config.ClusterRouter,
×
2226
                        &kubeovnv1.PolicyRoute{
×
2227
                                Priority:  util.GatewayRouterPolicyPriority,
×
2228
                                Match:     match,
×
2229
                                Action:    action,
×
2230
                                NextHopIP: nodeIP,
×
2231
                        },
×
2232
                        externalIDs,
×
2233
                ); err != nil {
×
2234
                        klog.Errorf("failed to add logical router policy for port-group address-set %s: %v", pgAs, err)
×
2235
                        return err
×
2236
                }
×
2237
        }
2238
        return nil
×
2239
}
2240

2241
func (c *Controller) deletePolicyRouteForDistributedSubnet(subnet *kubeovnv1.Subnet, nodeName string) error {
×
2242
        pgName := getOverlaySubnetsPortGroupName(subnet.Name, nodeName)
×
2243
        for cidrBlock := range strings.SplitSeq(subnet.Spec.CIDRBlock, ",") {
×
2244
                ipSuffix := getIPSuffix(util.CheckProtocol(cidrBlock))
×
2245
                pgAs := fmt.Sprintf("%s_%s", pgName, ipSuffix)
×
2246
                match := fmt.Sprintf("%s.src == $%s", ipSuffix, pgAs)
×
2247
                klog.Infof("delete policy route for router: %s, priority: %d, match: %q", c.config.ClusterRouter, util.GatewayRouterPolicyPriority, match)
×
2248
                if err := c.deletePolicyRouteFromVpc(c.config.ClusterRouter, util.GatewayRouterPolicyPriority, match); err != nil {
×
2249
                        klog.Errorf("failed to delete policy route for subnet %s: %v", subnet.Name, err)
×
2250
                        return err
×
2251
                }
×
2252
        }
2253
        return nil
×
2254
}
2255

2256
func (c *Controller) deletePolicyRouteByGatewayType(subnet *kubeovnv1.Subnet, gatewayType string, isDelete bool) error {
×
2257
        if (subnet.Spec.Vlan != "" && !subnet.Spec.LogicalGateway) || subnet.Spec.Vpc != c.config.ClusterRouter {
×
2258
                return nil
×
2259
        }
×
2260

2261
        for cidr := range strings.SplitSeq(subnet.Spec.CIDRBlock, ",") {
×
2262
                if cidr == "" || !isDelete {
×
2263
                        continue
×
2264
                }
2265

2266
                ipSuffix := getIPSuffix(util.CheckProtocol(cidr))
×
2267
                match := fmt.Sprintf("%s.dst == %s", ipSuffix, cidr)
×
2268
                klog.Infof("delete policy route for router: %s, priority: %d, match %s", c.config.ClusterRouter, util.SubnetRouterPolicyPriority, match)
×
2269
                if err := c.deletePolicyRouteFromVpc(c.config.ClusterRouter, util.SubnetRouterPolicyPriority, match); err != nil {
×
2270
                        klog.Errorf("failed to delete logical router policy for CIDR %s of subnet %s: %v", cidr, subnet.Name, err)
×
2271
                        return err
×
2272
                }
×
2273
        }
2274
        if subnet.Name == c.config.NodeSwitch {
×
2275
                return nil
×
2276
        }
×
2277

2278
        if gatewayType == kubeovnv1.GWDistributedType {
×
2279
                nodes, err := c.nodesLister.List(labels.Everything())
×
2280
                if err != nil {
×
2281
                        klog.Errorf("list nodes: %v", err)
×
2282
                        return err
×
2283
                }
×
2284
                for _, node := range nodes {
×
2285
                        pgName := getOverlaySubnetsPortGroupName(subnet.Name, node.Name)
×
2286
                        if err = c.OVNNbClient.DeletePortGroup(pgName); err != nil {
×
2287
                                klog.Errorf("delete port group for subnet %s and node %s: %v", subnet.Name, node.Name, err)
×
2288
                                return err
×
2289
                        }
×
2290

2291
                        if err = c.deletePolicyRouteForDistributedSubnet(subnet, node.Name); err != nil {
×
2292
                                klog.Errorf("delete policy route for subnet %s and node %s: %v", subnet.Name, node.Name, err)
×
2293
                                return err
×
2294
                        }
×
2295
                }
2296
        }
2297

2298
        if gatewayType == kubeovnv1.GWCentralizedType {
×
2299
                klog.Infof("delete policy route for centralized subnet %s", subnet.Name)
×
2300
                if err := c.deletePolicyRouteForCentralizedSubnet(subnet); err != nil {
×
2301
                        klog.Errorf("delete policy route for subnet %s: %v", subnet.Name, err)
×
2302
                        return err
×
2303
                }
×
2304
        }
2305

2306
        return nil
×
2307
}
2308

2309
func (c *Controller) addPolicyRouteForU2OInterconn(subnet *kubeovnv1.Subnet) error {
×
2310
        v4Gw, v6Gw := util.SplitStringIP(subnet.Spec.Gateway)
×
2311

×
2312
        externalIDs := buildPolicyRouteExternalIDs(subnet.Name, map[string]string{"isU2ORoutePolicy": "true"})
×
2313

×
2314
        nodes, err := c.nodesLister.List(labels.Everything())
×
2315
        if err != nil {
×
2316
                klog.Errorf("failed to list nodes: %v", err)
×
2317
                return err
×
2318
        }
×
2319

2320
        var nodesIPv4, nodesIPv6 []string
×
2321
        for _, node := range nodes {
×
2322
                nodeIPv4, nodeIPv6 := util.GetNodeInternalIP(*node)
×
2323

×
2324
                if nodeIPv4 != "" {
×
2325
                        nodesIPv4 = append(nodesIPv4, nodeIPv4)
×
2326
                }
×
2327
                if nodeIPv6 != "" {
×
2328
                        nodesIPv6 = append(nodesIPv6, nodeIPv6)
×
2329
                }
×
2330
        }
2331

2332
        u2oExcludeIP4Ag := strings.ReplaceAll(fmt.Sprintf(util.U2OExcludeIPAg, subnet.Name, "ip4"), "-", ".")
×
2333
        u2oExcludeIP6Ag := strings.ReplaceAll(fmt.Sprintf(util.U2OExcludeIPAg, subnet.Name, "ip6"), "-", ".")
×
2334

×
2335
        if err := c.OVNNbClient.CreateAddressSet(u2oExcludeIP4Ag, externalIDs); err != nil {
×
2336
                klog.Errorf("create address set %s: %v", u2oExcludeIP4Ag, err)
×
2337
                return err
×
2338
        }
×
2339

2340
        if err := c.OVNNbClient.CreateAddressSet(u2oExcludeIP6Ag, externalIDs); err != nil {
×
2341
                klog.Errorf("create address set %s: %v", u2oExcludeIP6Ag, err)
×
2342
                return err
×
2343
        }
×
2344

2345
        if len(nodesIPv4) > 0 {
×
2346
                if err := c.OVNNbClient.AddressSetUpdateAddress(u2oExcludeIP4Ag, nodesIPv4...); err != nil {
×
2347
                        klog.Errorf("set v4 address set %s with address %v: %v", u2oExcludeIP4Ag, nodesIPv4, err)
×
2348
                        return err
×
2349
                }
×
2350
        }
2351

2352
        if len(nodesIPv6) > 0 {
×
2353
                if err := c.OVNNbClient.AddressSetUpdateAddress(u2oExcludeIP6Ag, nodesIPv6...); err != nil {
×
2354
                        klog.Errorf("set v6 address set %s with address %v: %v", u2oExcludeIP6Ag, nodesIPv6, err)
×
2355
                        return err
×
2356
                }
×
2357
        }
2358

2359
        for cidrBlock := range strings.SplitSeq(subnet.Spec.CIDRBlock, ",") {
×
2360
                ipSuffix := getIPSuffix(util.CheckProtocol(cidrBlock))
×
2361
                nextHop := v4Gw
×
2362
                U2OexcludeIPAs := u2oExcludeIP4Ag
×
2363
                if ipSuffix == "ip6" {
×
2364
                        nextHop = v6Gw
×
2365
                        U2OexcludeIPAs = u2oExcludeIP6Ag
×
2366
                }
×
2367

2368
                match1 := fmt.Sprintf("%s.dst == %s", ipSuffix, cidrBlock)
×
2369
                match2 := fmt.Sprintf("%s.dst == $%s && %s.src == %s", ipSuffix, U2OexcludeIPAs, ipSuffix, cidrBlock)
×
2370
                match3 := fmt.Sprintf("%s.src == %s", ipSuffix, cidrBlock)
×
2371

×
2372
                /*
×
2373
                        policy1:
×
2374
                        priority 29400 match: "ip4.dst == underlay subnet cidr"                         action: allow
×
2375

×
2376
                        policy2:
×
2377
                        priority 31000 match: "ip4.dst == node ips && ip4.src == underlay subnet cidr"  action: reroute physical gw
×
2378

×
2379
                        policy3:
×
2380
                        priority 29000 match: "ip4.src == underlay subnet cidr"                         action: reroute physical gw
×
2381

×
2382
                        comment:
×
2383
                        policy1 and policy2 allow overlay pod access underlay but when overlay pod access node ip, it should go join subnet,
×
2384
                        policy3: underlay pod first access u2o interconnection lrp and then reroute to physical gw
×
2385
                */
×
2386
                action := kubeovnv1.PolicyRouteActionAllow
×
2387
                if subnet.Spec.Vpc == c.config.ClusterRouter {
×
2388
                        klog.Infof("add u2o interconnection policy for router: %s, match %s, action %s", subnet.Spec.Vpc, match1, action)
×
2389
                        if err := c.addPolicyRouteToVpc(
×
2390
                                subnet.Spec.Vpc,
×
2391
                                &kubeovnv1.PolicyRoute{
×
2392
                                        Priority: util.U2OSubnetPolicyPriority,
×
2393
                                        Match:    match1,
×
2394
                                        Action:   action,
×
2395
                                },
×
2396
                                externalIDs,
×
2397
                        ); err != nil {
×
2398
                                klog.Errorf("failed to add u2o interconnection policy1 for subnet %s %v", subnet.Name, err)
×
2399
                                return err
×
2400
                        }
×
2401

2402
                        action = kubeovnv1.PolicyRouteActionReroute
×
2403
                        klog.Infof("add u2o interconnection policy for router: %s, match %s, action %s", subnet.Spec.Vpc, match2, action)
×
2404
                        if err := c.addPolicyRouteToVpc(
×
2405
                                subnet.Spec.Vpc,
×
2406
                                &kubeovnv1.PolicyRoute{
×
2407
                                        Priority:  util.SubnetRouterPolicyPriority,
×
2408
                                        Match:     match2,
×
2409
                                        Action:    action,
×
2410
                                        NextHopIP: nextHop,
×
2411
                                },
×
2412
                                externalIDs,
×
2413
                        ); err != nil {
×
2414
                                klog.Errorf("failed to add u2o interconnection policy2 for subnet %s %v", subnet.Name, err)
×
2415
                                return err
×
2416
                        }
×
2417
                }
2418

2419
                action = kubeovnv1.PolicyRouteActionReroute
×
2420
                klog.Infof("add u2o interconnection policy for router: %s, match %s, action %s, nexthop %s", subnet.Spec.Vpc, match3, action, nextHop)
×
2421
                if err := c.addPolicyRouteToVpc(
×
2422
                        subnet.Spec.Vpc,
×
2423
                        &kubeovnv1.PolicyRoute{
×
2424
                                Priority:  util.GatewayRouterPolicyPriority,
×
2425
                                Match:     match3,
×
2426
                                Action:    action,
×
2427
                                NextHopIP: nextHop,
×
2428
                        },
×
2429
                        externalIDs,
×
2430
                ); err != nil {
×
2431
                        klog.Errorf("failed to add u2o interconnection policy3 for subnet %s %v", subnet.Name, err)
×
2432
                        return err
×
2433
                }
×
2434
        }
2435
        return nil
×
2436
}
2437

2438
func (c *Controller) deletePolicyRouteForU2OInterconn(subnet *kubeovnv1.Subnet) error {
×
2439
        if !c.logicalRouterExists(subnet.Spec.Vpc) {
×
2440
                return nil
×
2441
        }
×
2442
        policies, err := c.OVNNbClient.ListLogicalRouterPolicies(subnet.Spec.Vpc, -1, map[string]string{
×
2443
                "isU2ORoutePolicy": "true",
×
2444
                "vendor":           util.CniTypeName,
×
2445
                "subnet":           subnet.Name,
×
2446
        }, true)
×
2447
        if err != nil {
×
2448
                klog.Errorf("failed to list logical router policies: %v", err)
×
2449
                return err
×
2450
        }
×
2451
        if len(policies) == 0 {
×
2452
                return nil
×
2453
        }
×
2454

2455
        lr := subnet.Status.U2OInterconnectionVPC
×
2456
        if lr == "" {
×
2457
                // old version field U2OInterconnectionVPC may be "" and then use subnet.Spec.Vpc
×
2458
                lr = subnet.Spec.Vpc
×
2459
        }
×
2460

2461
        for _, policy := range policies {
×
2462
                klog.Infof("delete u2o interconnection policy for router %s with match %s priority %d", lr, policy.Match, policy.Priority)
×
2463
                if err = c.OVNNbClient.DeleteLogicalRouterPolicyByUUID(lr, policy.UUID); err != nil {
×
2464
                        klog.Errorf("failed to delete u2o interconnection policy for subnet %s: %v", subnet.Name, err)
×
2465
                        return err
×
2466
                }
×
2467
        }
2468

2469
        u2oExcludeIP4Ag := strings.ReplaceAll(fmt.Sprintf(util.U2OExcludeIPAg, subnet.Name, "ip4"), "-", ".")
×
2470
        u2oExcludeIP6Ag := strings.ReplaceAll(fmt.Sprintf(util.U2OExcludeIPAg, subnet.Name, "ip6"), "-", ".")
×
2471

×
2472
        if err := c.OVNNbClient.DeleteAddressSet(u2oExcludeIP4Ag); err != nil {
×
2473
                klog.Errorf("delete address set %s: %v", u2oExcludeIP4Ag, err)
×
2474
                return err
×
2475
        }
×
2476

2477
        if err := c.OVNNbClient.DeleteAddressSet(u2oExcludeIP6Ag); err != nil {
×
2478
                klog.Errorf("delete address set %s: %v", u2oExcludeIP6Ag, err)
×
2479
                return err
×
2480
        }
×
2481

2482
        return nil
×
2483
}
2484

2485
func (c *Controller) addCustomVPCStaticRouteForSubnet(subnet *kubeovnv1.Subnet) error {
×
2486
        if subnet.Spec.Vpc == "" {
×
2487
                return nil
×
2488
        }
×
2489

2490
        v4Gw, v6Gw := util.SplitStringIP(subnet.Spec.Gateway)
×
2491
        v4Cidr, v6Cidr := util.SplitStringIP(subnet.Spec.CIDRBlock)
×
2492

×
2493
        if v4Gw != "" && v4Cidr != "" {
×
2494
                if err := c.addStaticRouteToVpc(
×
2495
                        subnet.Spec.Vpc,
×
2496
                        &kubeovnv1.StaticRoute{
×
2497
                                Policy:    kubeovnv1.PolicySrc,
×
2498
                                CIDR:      v4Cidr,
×
2499
                                NextHopIP: v4Gw,
×
2500
                        },
×
2501
                ); err != nil {
×
2502
                        klog.Errorf("failed to add static route, %v", err)
×
2503
                        return err
×
2504
                }
×
2505
        }
2506

2507
        if v6Gw != "" && v6Cidr != "" {
×
2508
                if err := c.addStaticRouteToVpc(
×
2509
                        subnet.Spec.Vpc,
×
2510
                        &kubeovnv1.StaticRoute{
×
2511
                                Policy:    kubeovnv1.PolicySrc,
×
2512
                                CIDR:      v6Cidr,
×
2513
                                NextHopIP: v6Gw,
×
2514
                        },
×
2515
                ); err != nil {
×
2516
                        klog.Errorf("failed to add static route, %v", err)
×
2517
                        return err
×
2518
                }
×
2519
        }
2520
        return nil
×
2521
}
2522

2523
func (c *Controller) deleteStaticRouteForU2OInterconn(subnet *kubeovnv1.Subnet) error {
×
2524
        if subnet.Spec.Vpc == "" {
×
2525
                return nil
×
2526
        }
×
2527

2528
        v4Gw, v6Gw := util.SplitStringIP(subnet.Spec.Gateway)
×
2529
        v4Cidr, v6Cidr := util.SplitStringIP(subnet.Spec.CIDRBlock)
×
2530
        if v4Gw != "" && v4Cidr != "" {
×
2531
                if err := c.deleteStaticRouteFromVpc(
×
2532
                        subnet.Spec.Vpc,
×
2533
                        subnet.Spec.RouteTable,
×
2534
                        v4Cidr,
×
2535
                        v4Gw,
×
2536
                        kubeovnv1.PolicySrc,
×
2537
                ); err != nil {
×
2538
                        klog.Errorf("failed to add static route, %v", err)
×
2539
                        return err
×
2540
                }
×
2541
        }
2542

2543
        if v6Gw != "" && v6Cidr != "" {
×
2544
                if err := c.deleteStaticRouteFromVpc(
×
2545
                        subnet.Spec.Vpc,
×
2546
                        subnet.Spec.RouteTable,
×
2547
                        v6Cidr,
×
2548
                        v6Gw,
×
2549
                        kubeovnv1.PolicySrc,
×
2550
                ); err != nil {
×
2551
                        klog.Errorf("failed to delete static route, %v", err)
×
2552
                        return err
×
2553
                }
×
2554
        }
2555
        return nil
×
2556
}
2557

2558
func (c *Controller) reconcileRouteTableForSubnet(subnet *kubeovnv1.Subnet) error {
×
2559
        if subnet.Spec.Vlan != "" && !subnet.Spec.U2OInterconnection {
×
2560
                return nil
×
2561
        }
×
2562

2563
        routerPortName := ovs.LogicalRouterPortName(subnet.Spec.Vpc, subnet.Name)
×
2564
        lrp, err := c.OVNNbClient.GetLogicalRouterPort(routerPortName, false)
×
2565
        if err != nil {
×
2566
                klog.Error(err)
×
2567
                return err
×
2568
        }
×
2569

2570
        rtb := lrp.Options["route_table"]
×
2571

×
2572
        // no need to update
×
2573
        if rtb == subnet.Spec.RouteTable {
×
2574
                return nil
×
2575
        }
×
2576

2577
        klog.Infof("reconcile route table %q for subnet %s", subnet.Spec.RouteTable, subnet.Name)
×
2578
        opt := map[string]string{"route_table": subnet.Spec.RouteTable}
×
2579
        if err = c.OVNNbClient.UpdateLogicalRouterPortOptions(routerPortName, opt); err != nil {
×
2580
                klog.Errorf("failed to set route table of logical router port %s to %s: %v", routerPortName, subnet.Spec.RouteTable, err)
×
2581
                return err
×
2582
        }
×
2583

2584
        return nil
×
2585
}
2586

2587
func (c *Controller) deleteCustomVPCPolicyRoutesForSubnet(subnet *kubeovnv1.Subnet) error {
×
2588
        if !c.logicalRouterExists(subnet.Spec.Vpc) {
×
2589
                return nil
×
2590
        }
×
2591
        for cidr := range strings.SplitSeq(subnet.Spec.CIDRBlock, ",") {
×
2592
                ipSuffix := getIPSuffix(util.CheckProtocol(cidr))
×
2593
                match := fmt.Sprintf("%s.dst == %s", ipSuffix, cidr)
×
2594
                klog.Infof("delete policy route for router: %s, priority: %d, match %s", subnet.Spec.Vpc, util.SubnetRouterPolicyPriority, match)
×
2595
                if err := c.deletePolicyRouteFromVpc(subnet.Spec.Vpc, util.SubnetRouterPolicyPriority, match); err != nil {
×
2596
                        klog.Errorf("failed to delete logical router policy for CIDR %s of subnet %s: %v", cidr, subnet.Name, err)
×
2597
                        return err
×
2598
                }
×
2599
        }
2600
        return nil
×
2601
}
2602

2603
func (c *Controller) clearOldU2OResource(subnet *kubeovnv1.Subnet) error {
×
2604
        if subnet.Status.U2OInterconnectionVPC != "" &&
×
2605
                (!subnet.Spec.U2OInterconnection || (subnet.Spec.U2OInterconnection && subnet.Status.U2OInterconnectionVPC != subnet.Spec.Vpc)) {
×
2606
                // remove old u2o lsp and lrp first
×
2607
                lspName := fmt.Sprintf("%s-%s", subnet.Name, subnet.Status.U2OInterconnectionVPC)
×
2608
                lrpName := fmt.Sprintf("%s-%s", subnet.Status.U2OInterconnectionVPC, subnet.Name)
×
2609
                klog.Infof("clean subnet %s old u2o resource with lsp %s lrp %s", subnet.Name, lspName, lrpName)
×
2610
                if err := c.OVNNbClient.DeleteLogicalSwitchPort(lspName); err != nil {
×
2611
                        klog.Errorf("failed to delete u2o logical switch port %s: %v", lspName, err)
×
2612
                        return err
×
2613
                }
×
2614

2615
                if err := c.OVNNbClient.DeleteLogicalRouterPort(lrpName); err != nil {
×
2616
                        klog.Errorf("failed to delete u2o logical router port %s: %v", lrpName, err)
×
2617
                        return err
×
2618
                }
×
2619

2620
                if err := c.deletePolicyRouteForU2OInterconn(subnet); err != nil {
×
2621
                        klog.Errorf("failed to delete u2o policy route for u2o connection %s: %v", subnet.Name, err)
×
2622
                        return err
×
2623
                }
×
2624

2625
                if subnet.Status.U2OInterconnectionVPC != c.config.ClusterRouter {
×
2626
                        if err := c.deleteStaticRouteForU2OInterconn(subnet); err != nil {
×
2627
                                klog.Errorf("failed to delete u2o static route for u2o connection %s: %v", subnet.Name, err)
×
2628
                                return err
×
2629
                        }
×
2630
                }
2631
        }
2632
        return nil
×
2633
}
2634

2635
func (c *Controller) reconcilePolicyRouteForCidrChangedSubnet(subnet *kubeovnv1.Subnet, isCommonRoute bool) error {
×
2636
        var match string
×
2637
        var priority int
×
2638

×
2639
        if isCommonRoute {
×
2640
                priority = util.SubnetRouterPolicyPriority
×
2641
        } else {
×
2642
                priority = util.GatewayRouterPolicyPriority
×
2643
        }
×
2644

2645
        policies, err := c.OVNNbClient.ListLogicalRouterPolicies(subnet.Spec.Vpc, priority, map[string]string{
×
2646
                "vendor": util.CniTypeName,
×
2647
                "subnet": subnet.Name,
×
2648
        }, true)
×
2649
        if err != nil {
×
2650
                klog.Errorf("failed to list logical router policies: %v", err)
×
2651
                return err
×
2652
        }
×
2653
        if len(policies) == 0 {
×
2654
                return nil
×
2655
        }
×
2656

2657
        for _, policy := range policies {
×
2658
                policyProtocol := kubeovnv1.ProtocolIPv4
×
2659
                if strings.Contains(policy.Match, "ip6") {
×
2660
                        policyProtocol = kubeovnv1.ProtocolIPv6
×
2661
                }
×
2662

2663
                for cidr := range strings.SplitSeq(subnet.Spec.CIDRBlock, ",") {
×
2664
                        if cidr == "" {
×
2665
                                continue
×
2666
                        }
2667
                        if policyProtocol != util.CheckProtocol(cidr) {
×
2668
                                continue
×
2669
                        }
2670

2671
                        ipSuffix := getIPSuffix(util.CheckProtocol(cidr))
×
2672

×
2673
                        if isCommonRoute {
×
2674
                                match = fmt.Sprintf("%s.dst == %s", ipSuffix, cidr)
×
2675
                        } else {
×
2676
                                if subnet.Spec.GatewayType == kubeovnv1.GWCentralizedType {
×
2677
                                        match = fmt.Sprintf("%s.src == %s", ipSuffix, cidr)
×
2678
                                } else {
×
2679
                                        continue
×
2680
                                }
2681
                        }
2682

2683
                        if policy.Match != match {
×
2684
                                klog.Infof("delete old policy route for subnet %s with match %s priority %d, new match %v", subnet.Name, policy.Match, policy.Priority, match)
×
2685
                                if err = c.OVNNbClient.DeleteLogicalRouterPolicyByUUID(subnet.Spec.Vpc, policy.UUID); err != nil {
×
2686
                                        klog.Errorf("failed to delete policy route for subnet %s: %v", subnet.Name, err)
×
2687
                                        return err
×
2688
                                }
×
2689
                        }
2690
                }
2691
        }
2692
        return nil
×
2693
}
2694

2695
func (c *Controller) addPolicyRouteForU2ONoLoadBalancer(subnet *kubeovnv1.Subnet) error {
×
2696
        nodes, err := c.nodesLister.List(labels.Everything())
×
2697
        if err != nil {
×
2698
                klog.Errorf("failed to list nodes: %v", err)
×
2699
                return err
×
2700
        }
×
2701
        for _, node := range nodes {
×
2702
                pgName := getOverlaySubnetsPortGroupName(subnet.Name, node.Name)
×
2703
                if err := c.OVNNbClient.CreatePortGroup(pgName, map[string]string{logicalRouterKey: subnet.Spec.Vpc, logicalSwitchKey: subnet.Name, u2oKey: "true"}); err != nil {
×
2704
                        klog.Errorf("failed to create u2o port group for subnet %s and node %s: %v", subnet.Name, node.Name, err)
×
2705
                        return err
×
2706
                }
×
2707
                key := util.NodeLspName(node.Name)
×
2708
                ip, err := c.ipsLister.Get(key)
×
2709
                if err != nil {
×
2710
                        if k8serrors.IsNotFound(err) {
×
2711
                                return nil
×
2712
                        }
×
2713
                        klog.Error(err)
×
2714
                        return err
×
2715
                }
2716
                v4Svc, v6Svc := util.SplitStringIP(c.config.ServiceClusterIPRange)
×
2717
                for cidrBlock := range strings.SplitSeq(subnet.Spec.CIDRBlock, ",") {
×
2718
                        ipSuffix := getIPSuffix(util.CheckProtocol(cidrBlock))
×
2719
                        nodeIP := ip.Spec.V4IPAddress
×
2720
                        svcCIDR := v4Svc
×
2721
                        if ipSuffix == "ip6" {
×
2722
                                nodeIP = ip.Spec.V6IPAddress
×
2723
                                svcCIDR = v6Svc
×
2724
                        }
×
2725
                        if nodeIP == "" || svcCIDR == "" {
×
2726
                                continue
×
2727
                        }
2728

2729
                        pgAs := fmt.Sprintf("%s_%s", pgName, ipSuffix)
×
2730
                        match := fmt.Sprintf("%s.src == $%s && %s.dst == %s", ipSuffix, pgAs, ipSuffix, svcCIDR)
×
2731
                        action := kubeovnv1.PolicyRouteActionReroute
×
2732
                        externalIDs := buildPolicyRouteExternalIDs(subnet.Name, map[string]string{
×
2733
                                "isU2ORoutePolicy":     "true",
×
2734
                                "isU2ONoLBRoutePolicy": "true",
×
2735
                                "node":                 node.Name,
×
2736
                        })
×
2737

×
2738
                        klog.Infof("add u2o interconnection policy without enabling loadbalancer for router: %s, match %s, action %s, nexthop %s", subnet.Spec.Vpc, match, action, nodeIP)
×
2739
                        if err := c.addPolicyRouteToVpc(
×
2740
                                c.config.ClusterRouter,
×
2741
                                &kubeovnv1.PolicyRoute{
×
2742
                                        Priority:  util.U2OSubnetPolicyPriority,
×
2743
                                        Match:     match,
×
2744
                                        Action:    action,
×
2745
                                        NextHopIP: nodeIP,
×
2746
                                },
×
2747
                                externalIDs,
×
2748
                        ); err != nil {
×
2749
                                klog.Errorf("failed to add logical router policy for port-group address-set %s: %v", pgAs, err)
×
2750
                                return err
×
2751
                        }
×
2752
                }
2753
        }
2754
        lsps, err := c.OVNNbClient.ListNormalLogicalSwitchPorts(true, map[string]string{logicalSwitchKey: subnet.Name})
×
2755
        if err != nil {
×
2756
                klog.Errorf("failed to list normal lsps for subnet %s: %v", subnet.Name, err)
×
2757
                return err
×
2758
        }
×
2759
        for _, lsp := range lsps {
×
2760
                ip, err := c.ipsLister.Get(lsp.Name)
×
2761
                if err != nil {
×
2762
                        if k8serrors.IsNotFound(err) {
×
2763
                                return nil
×
2764
                        }
×
2765
                        klog.Error(err)
×
2766
                        return err
×
2767
                }
2768
                pgName := getOverlaySubnetsPortGroupName(subnet.Name, ip.Spec.NodeName)
×
2769
                if err = c.OVNNbClient.PortGroupAddPorts(pgName, lsp.Name); err != nil {
×
2770
                        klog.Errorf("failed to add port to u2o port group %s: %v", pgName, err)
×
2771
                        return err
×
2772
                }
×
2773
        }
2774
        return nil
×
2775
}
2776

2777
func (c *Controller) deletePolicyRouteForU2ONoLoadBalancer(subnet *kubeovnv1.Subnet) error {
×
2778
        if !c.logicalRouterExists(subnet.Spec.Vpc) {
×
2779
                return nil
×
2780
        }
×
2781
        policies, err := c.OVNNbClient.ListLogicalRouterPolicies(subnet.Spec.Vpc, -1, map[string]string{
×
2782
                "isU2ONoLBRoutePolicy": "true",
×
2783
                "vendor":               util.CniTypeName,
×
2784
                "subnet":               subnet.Name,
×
2785
        }, true)
×
2786
        if err != nil {
×
2787
                klog.Errorf("failed to list logical router policies: %v", err)
×
2788
                return err
×
2789
        }
×
2790

2791
        lr := subnet.Status.U2OInterconnectionVPC
×
2792
        if lr == "" {
×
2793
                // old version field U2OInterconnectionVPC may be "" and then use subnet.Spec.Vpc
×
2794
                lr = subnet.Spec.Vpc
×
2795
        }
×
2796

2797
        for _, policy := range policies {
×
2798
                klog.Infof("delete u2o interconnection policy without enabling loadbalancer for router %s with match %s priority %d", lr, policy.Match, policy.Priority)
×
2799
                if err = c.OVNNbClient.DeleteLogicalRouterPolicyByUUID(lr, policy.UUID); err != nil {
×
2800
                        klog.Errorf("failed to delete u2o interconnection policy for subnet %s: %v", subnet.Name, err)
×
2801
                        return err
×
2802
                }
×
2803
        }
2804

2805
        pgs, err := c.OVNNbClient.ListPortGroups(map[string]string{logicalRouterKey: subnet.Spec.Vpc, logicalSwitchKey: subnet.Name, u2oKey: "true"})
×
2806
        if err != nil {
×
2807
                klog.Errorf("failed to list u2o port groups with u2oKey is true for subnet %s: %v", subnet.Name, err)
×
2808
                return err
×
2809
        }
×
2810
        for _, pg := range pgs {
×
2811
                klog.Infof("delete u2o port group %s for subnet %s", pg.Name, subnet.Name)
×
2812
                if err = c.OVNNbClient.DeletePortGroup(pg.Name); err != nil {
×
2813
                        klog.Errorf("failed to delete u2o port group for subnet %s: %v", subnet.Name, err)
×
2814
                        return err
×
2815
                }
×
2816
        }
2817
        return nil
×
2818
}
2819

2820
func (c *Controller) findSubnetByNetworkAttachmentDefinition(ns, name string, subnets []*kubeovnv1.Subnet) (*kubeovnv1.Subnet, error) {
×
2821
        nad, err := c.netAttachLister.NetworkAttachmentDefinitions(ns).Get(name)
×
2822
        if err != nil {
×
2823
                klog.Errorf("failed to get net-attach-def %s/%s: %v", ns, name, err)
×
2824
                return nil, err
×
2825
        }
×
2826
        netCfg, err := loadNetConf([]byte(nad.Spec.Config))
×
2827
        if err != nil {
×
2828
                klog.Errorf("failed to parse config of net-attach-def %s/%s: %v", ns, name, err)
×
2829
                return nil, err
×
2830
        }
×
2831

2832
        var provider string
×
2833
        if netCfg.Conf.Type == util.CniTypeName {
×
2834
                provider = fmt.Sprintf("%s.%s.%s", name, ns, util.OvnProvider)
×
2835
        } else {
×
2836
                provider = fmt.Sprintf("%s.%s", name, ns)
×
2837
        }
×
2838
        var subnet *kubeovnv1.Subnet
×
2839
        for _, s := range subnets {
×
2840
                if s.Spec.Provider == provider {
×
2841
                        subnet = s.DeepCopy()
×
2842
                        break
×
2843
                }
2844
        }
2845
        if subnet == nil {
×
2846
                err = fmt.Errorf("failed to get subnet for net-attach-def %s/%s", ns, name)
×
2847
                klog.Error(err)
×
2848
                return nil, err
×
2849
        }
×
2850

2851
        return subnet, nil
×
2852
}
2853

2854
func (c *Controller) handleMcastQuerierChange(subnet *kubeovnv1.Subnet) error {
×
2855
        if subnet.Spec.EnableMulticastSnoop {
×
2856
                multicastSnoopFlag := map[string]string{
×
2857
                        "mcast_snoop":   "true",
×
2858
                        "mcast_querier": "true",
×
2859
                        "mcast_ip4_src": subnet.Status.McastQuerierIP,
×
2860
                        "mcast_eth_src": subnet.Status.McastQuerierMAC,
×
2861
                }
×
2862
                mcastQuerierLspName := fmt.Sprintf(util.McastQuerierName, subnet.Name)
×
2863
                if err := c.OVNNbClient.CreateLogicalSwitchPort(subnet.Name, mcastQuerierLspName, subnet.Status.McastQuerierIP, subnet.Status.McastQuerierMAC, mcastQuerierLspName, "default", false, "", "", false, nil, ""); err != nil {
×
2864
                        err = fmt.Errorf("failed to create mcast querier lsp %s: %w", mcastQuerierLspName, err)
×
2865
                        klog.Error(err)
×
2866
                        return err
×
2867
                }
×
2868

2869
                if err := c.OVNNbClient.LogicalSwitchUpdateOtherConfig(subnet.Name, ovsdb.MutateOperationInsert, multicastSnoopFlag); err != nil {
×
2870
                        klog.Errorf("enable logical switch multicast snoop %s: %v", subnet.Name, err)
×
2871
                        return err
×
2872
                }
×
2873
        } else {
×
2874
                lss, err := c.OVNNbClient.ListLogicalSwitch(false, func(ls *ovnnb.LogicalSwitch) bool {
×
2875
                        return ls.Name == subnet.Name
×
2876
                })
×
2877
                if err != nil || len(lss) == 0 {
×
2878
                        klog.Errorf("failed to list logical switch %s: %v", subnet.Name, err)
×
2879
                        return err
×
2880
                }
×
2881

2882
                multicastSnoopFlag := map[string]string{
×
2883
                        "mcast_snoop":   lss[0].OtherConfig["mcast_snoop"],
×
2884
                        "mcast_querier": lss[0].OtherConfig["mcast_querier"],
×
2885
                        "mcast_ip4_src": lss[0].OtherConfig["mcast_ip4_src"],
×
2886
                        "mcast_eth_src": lss[0].OtherConfig["mcast_eth_src"],
×
2887
                }
×
2888
                mcastQuerierLspName := fmt.Sprintf(util.McastQuerierName, subnet.Name)
×
2889
                if err := c.OVNNbClient.LogicalSwitchUpdateOtherConfig(subnet.Name, ovsdb.MutateOperationDelete, multicastSnoopFlag); err != nil {
×
2890
                        klog.Errorf("disable logical switch multicast snoop %s: %v", subnet.Name, err)
×
2891
                        return err
×
2892
                }
×
2893

2894
                if err := c.OVNNbClient.DeleteLogicalSwitchPort(mcastQuerierLspName); err != nil {
×
2895
                        err = fmt.Errorf("failed to delete mcast querier lsp %s: %w", mcastQuerierLspName, err)
×
2896
                        klog.Error(err)
×
2897
                        return err
×
2898
                }
×
2899
        }
2900
        return nil
×
2901
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc