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

kubeovn / kube-ovn / 14967332477

12 May 2025 08:20AM UTC coverage: 21.616% (-0.1%) from 21.714%
14967332477

Pull #5110

github

zbb88888
use provider network default interface

Signed-off-by: zbb88888 <jmdxjsjgcxy@gmail.com>
Pull Request #5110: enable check vlan conflict

0 of 257 new or added lines in 6 files covered. (0.0%)

218 existing lines in 9 files now uncovered.

10254 of 47436 relevant lines covered (21.62%)

0.25 hits per line

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

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

3
import (
4
        "context"
5
        "encoding/json"
6
        "errors"
7
        "fmt"
8
        "net"
9
        "reflect"
10
        "slices"
11
        "sort"
12
        "strconv"
13
        "strings"
14
        "time"
15

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

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

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

×
40
func (c *Controller) enqueueDeleteSubnet(obj interface{}) {
41
        subnet := obj.(*kubeovnv1.Subnet)
×
42
        klog.V(3).Infof("enqueue delete subnet %s", subnet.Name)
×
43
        c.deleteSubnetQueue.Add(subnet)
×
44
}
×
45

×
46
func (c *Controller) enqueueUpdateSubnet(oldObj, newObj interface{}) {
47
        var usingIPs float64
×
48
        var u2oInterconnIP string
×
49
        oldSubnet := oldObj.(*kubeovnv1.Subnet)
×
50
        newSubnet := newObj.(*kubeovnv1.Subnet)
×
51
        key := cache.MetaObjectToName(newSubnet).String()
×
52

×
53
        // Trigger network policy refresh only if they are enabled, otherwise the lister will be nil
×
54
        if c.npsLister != nil {
×
55
                if newSubnet.Spec.Gateway != oldSubnet.Spec.Gateway || newSubnet.Status.U2OInterconnectionIP != oldSubnet.Status.U2OInterconnectionIP {
×
56
                        policies, err := c.npsLister.List(labels.Everything())
×
57
                        if err != nil {
×
58
                                klog.Errorf("failed to list network policies: %v", err)
×
59
                        } else {
×
60
                                for _, np := range policies {
×
61
                                        c.enqueueAddNp(np)
×
62
                                }
×
63
                        }
×
64
                }
65
        }
66

67
        if newSubnet.Spec.Protocol == kubeovnv1.ProtocolIPv6 {
68
                usingIPs = newSubnet.Status.V6UsingIPs
×
69
        } else {
×
70
                usingIPs = newSubnet.Status.V4UsingIPs
×
71
        }
×
72

×
73
        u2oInterconnIP = newSubnet.Status.U2OInterconnectionIP
74
        if !newSubnet.DeletionTimestamp.IsZero() && (usingIPs == 0 || (usingIPs == 1 && u2oInterconnIP != "")) {
×
75
                c.addOrUpdateSubnetQueue.Add(key)
×
76
                return
×
77
        }
×
78

×
79
        if oldSubnet.Spec.Vpc != newSubnet.Spec.Vpc &&
80
                ((oldSubnet.Spec.Vpc != "" || newSubnet.Spec.Vpc != c.config.ClusterRouter) && (oldSubnet.Spec.Vpc != c.config.ClusterRouter || newSubnet.Spec.Vpc != "")) {
×
81
                if newSubnet.Annotations == nil {
×
82
                        newSubnet.Annotations = make(map[string]string)
×
83
                }
×
84

×
85
                if oldSubnet.Spec.Vpc == "" {
86
                        newSubnet.Annotations[util.VpcLastName] = c.config.ClusterRouter
×
87
                } else {
×
88
                        newSubnet.Annotations[util.VpcLastName] = oldSubnet.Spec.Vpc
×
89
                }
×
90

×
91
                c.updateVpcStatusQueue.Add(oldSubnet.Spec.Vpc)
92
        }
×
93

94
        if oldSubnet.Spec.Private != newSubnet.Spec.Private ||
95
                oldSubnet.Spec.CIDRBlock != newSubnet.Spec.CIDRBlock ||
×
96
                !slices.Equal(oldSubnet.Spec.AllowSubnets, newSubnet.Spec.AllowSubnets) ||
×
97
                !slices.Equal(oldSubnet.Spec.Namespaces, newSubnet.Spec.Namespaces) ||
×
98
                oldSubnet.Spec.GatewayType != newSubnet.Spec.GatewayType ||
×
99
                oldSubnet.Spec.GatewayNode != newSubnet.Spec.GatewayNode ||
×
100
                oldSubnet.Spec.LogicalGateway != newSubnet.Spec.LogicalGateway ||
×
101
                oldSubnet.Spec.Gateway != newSubnet.Spec.Gateway ||
×
102
                !slices.Equal(oldSubnet.Spec.ExcludeIps, newSubnet.Spec.ExcludeIps) ||
×
103
                !slices.Equal(oldSubnet.Spec.Vips, newSubnet.Spec.Vips) ||
×
104
                oldSubnet.Spec.Vlan != newSubnet.Spec.Vlan ||
×
105
                oldSubnet.Spec.EnableDHCP != newSubnet.Spec.EnableDHCP ||
×
106
                oldSubnet.Spec.DHCPv4Options != newSubnet.Spec.DHCPv4Options ||
×
107
                oldSubnet.Spec.DHCPv6Options != newSubnet.Spec.DHCPv6Options ||
×
108
                oldSubnet.Spec.EnableIPv6RA != newSubnet.Spec.EnableIPv6RA ||
×
109
                oldSubnet.Spec.IPv6RAConfigs != newSubnet.Spec.IPv6RAConfigs ||
×
110
                oldSubnet.Spec.Protocol != newSubnet.Spec.Protocol ||
×
111
                (oldSubnet.Spec.EnableLb == nil && newSubnet.Spec.EnableLb != nil) ||
×
112
                (oldSubnet.Spec.EnableLb != nil && newSubnet.Spec.EnableLb == nil) ||
×
113
                (oldSubnet.Spec.EnableLb != nil && newSubnet.Spec.EnableLb != nil && *oldSubnet.Spec.EnableLb != *newSubnet.Spec.EnableLb) ||
×
114
                oldSubnet.Spec.EnableEcmp != newSubnet.Spec.EnableEcmp ||
×
115
                !reflect.DeepEqual(oldSubnet.Spec.Acls, newSubnet.Spec.Acls) ||
×
116
                oldSubnet.Spec.U2OInterconnection != newSubnet.Spec.U2OInterconnection ||
×
117
                oldSubnet.Spec.RouteTable != newSubnet.Spec.RouteTable ||
×
118
                oldSubnet.Spec.Vpc != newSubnet.Spec.Vpc ||
×
119
                oldSubnet.Spec.NatOutgoing != newSubnet.Spec.NatOutgoing ||
×
120
                oldSubnet.Spec.EnableMulticastSnoop != newSubnet.Spec.EnableMulticastSnoop ||
×
121
                !reflect.DeepEqual(oldSubnet.Spec.NatOutgoingPolicyRules, newSubnet.Spec.NatOutgoingPolicyRules) ||
×
122
                !reflect.DeepEqual(oldSubnet.Spec.NamespaceSelectors, newSubnet.Spec.NamespaceSelectors) ||
×
123
                (newSubnet.Spec.U2OInterconnection && newSubnet.Spec.U2OInterconnectionIP != "" && oldSubnet.Spec.U2OInterconnectionIP != newSubnet.Spec.U2OInterconnectionIP) {
×
124
                klog.V(3).Infof("enqueue update subnet %s", key)
×
125

×
126
                if oldSubnet.Spec.GatewayType != newSubnet.Spec.GatewayType {
×
127
                        c.recorder.Eventf(newSubnet, v1.EventTypeNormal, "SubnetGatewayTypeChanged",
×
128
                                "subnet gateway type changes from %q to %q", oldSubnet.Spec.GatewayType, newSubnet.Spec.GatewayType)
×
129
                }
×
130

×
131
                if oldSubnet.Spec.GatewayNode != newSubnet.Spec.GatewayNode {
132
                        c.recorder.Eventf(newSubnet, v1.EventTypeNormal, "SubnetGatewayNodeChanged",
×
133
                                "gateway node changes from %q to %q", oldSubnet.Spec.GatewayNode, newSubnet.Spec.GatewayNode)
×
134
                }
×
135

×
136
                c.addOrUpdateSubnetQueue.Add(key)
137
        }
×
138
}
139

140
func (c *Controller) formatSubnet(subnet *kubeovnv1.Subnet) (*kubeovnv1.Subnet, error) {
141
        var (
1✔
142
                changed bool
1✔
143
                err     error
1✔
144
        )
1✔
145

1✔
146
        if changed, err = checkSubnetChanged(subnet); err != nil {
1✔
147
                klog.Error(err)
1✔
148
                return nil, err
×
149
        }
×
150

×
151
        if subnet.Spec.Provider == "" {
152
                subnet.Spec.Provider = util.OvnProvider
2✔
153
                changed = true
1✔
154
        }
1✔
155

1✔
156
        if subnet.Spec.Vpc == "" {
157
                if isOvnSubnet(subnet) {
2✔
158
                        subnet.Spec.Vpc = c.config.ClusterRouter
2✔
159
                        changed = true
1✔
160
                }
1✔
161
        }
1✔
162

163
        if subnet.Spec.Vpc == c.config.ClusterRouter && subnet.Name != c.config.NodeSwitch {
164
                // Some format only needed in the default VPC
2✔
165
                if subnet.Spec.GatewayType == "" {
1✔
166
                        subnet.Spec.GatewayType = kubeovnv1.GWDistributedType
2✔
167
                        changed = true
1✔
168
                }
1✔
169
                if subnet.Spec.Default && subnet.Name != c.config.DefaultLogicalSwitch {
1✔
170
                        subnet.Spec.Default = false
1✔
171
                        changed = true
×
172
                }
×
173
        }
×
174

175
        if subnet.Spec.EnableLb == nil && subnet.Name != c.config.NodeSwitch {
176
                changed = true
2✔
177
                subnet.Spec.EnableLb = &c.config.EnableLb
1✔
178
        }
1✔
179
        // set join subnet Spec.EnableLb to nil
1✔
180
        if subnet.Spec.EnableLb != nil && subnet.Name == c.config.NodeSwitch {
181
                changed = true
1✔
182
                subnet.Spec.EnableLb = nil
×
183
        }
×
184

×
185
        if subnet.Spec.U2OInterconnectionIP != "" && !subnet.Spec.U2OInterconnection {
186
                subnet.Spec.U2OInterconnectionIP = ""
1✔
187
                changed = true
×
188
        }
×
189

×
190
        klog.Infof("format subnet %v, changed %v", subnet.Name, changed)
191
        if changed {
1✔
192
                newSubnet, err := c.config.KubeOvnClient.KubeovnV1().Subnets().Update(context.Background(), subnet, metav1.UpdateOptions{})
2✔
193
                if err != nil {
1✔
194
                        klog.Errorf("failed to update subnet %s, %v", subnet.Name, err)
1✔
195
                        return nil, err
×
196
                }
×
197
                return newSubnet, nil
×
198
        }
1✔
199
        return subnet, nil
200
}
1✔
201

202
func (c *Controller) validateSubnetVlan(subnet *kubeovnv1.Subnet) error {
NEW
203
        if subnet.Spec.Vlan == "" {
×
NEW
204
                return nil
×
NEW
205
        }
×
NEW
206

×
207
        vlan, err := c.vlansLister.Get(subnet.Spec.Vlan)
NEW
208
        if err != nil {
×
NEW
209
                err = fmt.Errorf("failed to get vlan %s: %w", subnet.Spec.Vlan, err)
×
NEW
210
                klog.Error(err)
×
NEW
211
                return err
×
NEW
212
        }
×
NEW
213

×
214
        if c.config.EnableCheckVlanConflict && vlan.Status.Conflict {
NEW
215
                err = fmt.Errorf("subnet %s has invalid conflict vlan %s", subnet.Name, vlan.Name)
×
NEW
216
                klog.Error(err)
×
NEW
217
                return err
×
NEW
218
        }
×
NEW
219
        return nil
×
NEW
220
}
×
221

222
func (c *Controller) updateNatOutgoingPolicyRulesStatus(subnet *kubeovnv1.Subnet) error {
223
        if subnet.Spec.NatOutgoing {
×
224
                subnet.Status.NatOutgoingPolicyRules = make([]kubeovnv1.NatOutgoingPolicyRuleStatus, len(subnet.Spec.NatOutgoingPolicyRules))
×
225
                for index, rule := range subnet.Spec.NatOutgoingPolicyRules {
×
226
                        jsonRule, err := json.Marshal(rule)
×
227
                        if err != nil {
×
228
                                klog.Error(err)
×
229
                                return err
×
230
                        }
×
231
                        priority := strconv.Itoa(index)
×
232
                        // hash code generate by subnetName, rule and priority
×
233
                        var retBytes []byte
×
234
                        retBytes = append(retBytes, []byte(subnet.Name)...)
×
235
                        retBytes = append(retBytes, []byte(priority)...)
×
236
                        retBytes = append(retBytes, jsonRule...)
×
237
                        result := util.Sha256Hash(retBytes)
×
238

×
239
                        subnet.Status.NatOutgoingPolicyRules[index].RuleID = result[:util.NatPolicyRuleIDLength]
×
240
                        subnet.Status.NatOutgoingPolicyRules[index].Match = rule.Match
×
241
                        subnet.Status.NatOutgoingPolicyRules[index].Action = rule.Action
×
242
                }
×
243
        } else {
244
                subnet.Status.NatOutgoingPolicyRules = []kubeovnv1.NatOutgoingPolicyRuleStatus{}
×
245
        }
×
246

×
247
        return nil
248
}
×
249

250
func checkSubnetChanged(subnet *kubeovnv1.Subnet) (bool, error) {
251
        var (
1✔
252
                changed, ret bool
1✔
253
                err          error
1✔
254
        )
1✔
255

1✔
256
        // changed value may be overlapped, so use ret to record value
1✔
257
        if changed, err = checkAndUpdateCIDR(subnet); err != nil {
1✔
258
                klog.Error(err)
1✔
259
                return changed, err
×
260
        }
×
261
        if changed {
×
262
                ret = true
2✔
263
        }
1✔
264

1✔
265
        if changed, err = checkAndUpdateGateway(subnet); err != nil {
266
                klog.Error(err)
1✔
267
                return changed, err
×
268
        }
×
269
        if changed {
×
270
                ret = true
2✔
271
        }
1✔
272

1✔
273
        if changed = checkAndUpdateExcludeIPs(subnet); changed {
274
                ret = true
2✔
275
        }
1✔
276

1✔
277
        if subnet.Spec.Protocol != util.CheckProtocol(subnet.Spec.CIDRBlock) {
278
                subnet.Spec.Protocol = util.CheckProtocol(subnet.Spec.CIDRBlock)
2✔
279
                ret = true
1✔
280
        }
1✔
281

1✔
282
        return ret, nil
283
}
1✔
284

285
func checkAndUpdateCIDR(subnet *kubeovnv1.Subnet) (bool, error) {
286
        var (
1✔
287
                changed    bool
1✔
288
                cidrBlocks []string
1✔
289
        )
1✔
290

1✔
291
        for _, cidr := range strings.Split(subnet.Spec.CIDRBlock, ",") {
1✔
292
                _, ipNet, err := net.ParseCIDR(cidr)
2✔
293
                if err != nil {
1✔
294
                        klog.Error(err)
1✔
295
                        return false, fmt.Errorf("subnet %s cidr %s is invalid", subnet.Name, cidr)
×
296
                }
×
297
                if ipNet.String() != cidr {
×
298
                        changed = true
2✔
299
                }
1✔
300
                cidrBlocks = append(cidrBlocks, ipNet.String())
1✔
301
        }
1✔
302
        subnet.Spec.CIDRBlock = strings.Join(cidrBlocks, ",")
303
        return changed, nil
1✔
304
}
1✔
305

306
func checkAndUpdateGateway(subnet *kubeovnv1.Subnet) (bool, error) {
307
        var (
1✔
308
                changed bool
1✔
309
                gw      string
1✔
310
                err     error
1✔
311
        )
1✔
312

1✔
313
        switch {
1✔
314
        case subnet.Spec.Gateway == "":
1✔
315
                gw, err = util.GetGwByCidr(subnet.Spec.CIDRBlock)
1✔
316
        case subnet.Spec.Protocol == kubeovnv1.ProtocolDual && util.CheckProtocol(subnet.Spec.Gateway) != util.CheckProtocol(subnet.Spec.CIDRBlock):
1✔
317
                gw, err = util.AppendGwByCidr(subnet.Spec.Gateway, subnet.Spec.CIDRBlock)
×
318
        default:
×
319
                gw = subnet.Spec.Gateway
1✔
320
        }
1✔
321
        if err != nil {
322
                klog.Error(err)
1✔
323
                return false, err
×
324
        }
×
325
        if subnet.Spec.Gateway != gw {
×
326
                subnet.Spec.Gateway = gw
2✔
327
                changed = true
1✔
328
        }
1✔
329

1✔
330
        return changed, nil
331
}
1✔
332

333
// this func must be called after subnet.Spec.Gateway is valued
334
func checkAndUpdateExcludeIPs(subnet *kubeovnv1.Subnet) bool {
335
        var (
1✔
336
                changed    bool
1✔
337
                excludeIPs []string
1✔
338
        )
1✔
339
        excludeIPs = append(excludeIPs, strings.Split(subnet.Spec.Gateway, ",")...)
1✔
340
        sort.Strings(excludeIPs)
1✔
341
        if len(subnet.Spec.ExcludeIps) == 0 {
1✔
342
                subnet.Spec.ExcludeIps = excludeIPs
2✔
343
                changed = true
1✔
344
        } else {
1✔
345
                changed = checkAndFormatsExcludeIPs(subnet)
2✔
346
                for _, gw := range excludeIPs {
1✔
347
                        gwExists := false
2✔
348
                        for _, excludeIP := range subnet.Spec.ExcludeIps {
1✔
349
                                if util.ContainsIPs(excludeIP, gw) {
2✔
350
                                        gwExists = true
2✔
351
                                        break
1✔
352
                                }
1✔
353
                        }
354
                        if !gwExists {
355
                                subnet.Spec.ExcludeIps = append(subnet.Spec.ExcludeIps, gw)
1✔
356
                                sort.Strings(subnet.Spec.ExcludeIps)
×
357
                                changed = true
×
358
                        }
×
359
                }
×
360
        }
361
        return changed
362
}
1✔
363

364
func (c *Controller) syncSubnetFinalizer(cl client.Client) error {
365
        // migrate depreciated finalizer to new finalizer
×
366
        subnets := &kubeovnv1.SubnetList{}
×
367
        return migrateFinalizers(cl, subnets, func(i int) (client.Object, client.Object) {
×
368
                if i < 0 || i >= len(subnets.Items) {
×
369
                        return nil, nil
×
370
                }
×
371
                return subnets.Items[i].DeepCopy(), subnets.Items[i].DeepCopy()
×
372
        })
×
373
}
374

375
func (c *Controller) handleSubnetFinalizer(subnet *kubeovnv1.Subnet) (*kubeovnv1.Subnet, bool, error) {
376
        if subnet.DeletionTimestamp.IsZero() && !slices.Contains(subnet.GetFinalizers(), util.KubeOVNControllerFinalizer) {
×
377
                newSubnet := subnet.DeepCopy()
×
378
                controllerutil.AddFinalizer(newSubnet, util.KubeOVNControllerFinalizer)
×
379
                patch, err := util.GenerateMergePatchPayload(subnet, newSubnet)
×
380
                if err != nil {
×
381
                        klog.Errorf("failed to generate patch payload for subnet '%s', %v", subnet.Name, err)
×
382
                        return newSubnet, false, err
×
383
                }
×
384
                patchSubnet, err := c.config.KubeOvnClient.KubeovnV1().Subnets().Patch(context.Background(), subnet.Name, types.MergePatchType, patch, metav1.PatchOptions{}, "")
×
385
                if err != nil {
×
386
                        klog.Errorf("failed to add finalizer to subnet %s, %v", subnet.Name, err)
×
387
                        return patchSubnet, false, err
×
388
                }
×
389
                // wait local cache ready
×
390
                time.Sleep(1 * time.Second)
391
                return patchSubnet, false, nil
×
392
        }
×
393

394
        usingIPs := subnet.Status.V4UsingIPs
395
        if util.CheckProtocol(subnet.Spec.CIDRBlock) == kubeovnv1.ProtocolIPv6 {
×
396
                usingIPs = subnet.Status.V6UsingIPs
×
397
        }
×
398

×
399
        u2oInterconnIP := subnet.Status.U2OInterconnectionIP
400
        if !subnet.DeletionTimestamp.IsZero() && (usingIPs == 0 || (usingIPs == 1 && u2oInterconnIP != "")) {
×
401
                newSubnet := subnet.DeepCopy()
×
402
                controllerutil.RemoveFinalizer(newSubnet, util.KubeOVNControllerFinalizer)
×
403
                patch, err := util.GenerateMergePatchPayload(subnet, newSubnet)
×
404
                if err != nil {
×
405
                        klog.Errorf("failed to generate patch payload for subnet '%s', %v", subnet.Name, err)
×
406
                        return newSubnet, false, err
×
407
                }
×
408
                if _, err := c.config.KubeOvnClient.KubeovnV1().Subnets().Patch(context.Background(), subnet.Name,
×
409
                        types.MergePatchType, patch, metav1.PatchOptions{}, ""); err != nil {
×
410
                        klog.Errorf("failed to remove finalizer from subnet %s, %v", subnet.Name, err)
×
411
                        return newSubnet, false, err
×
412
                }
×
413
                return newSubnet, true, nil
×
414
        }
×
415
        return subnet, false, nil
416
}
×
417

418
func (c Controller) patchSubnetStatus(subnet *kubeovnv1.Subnet, reason, errStr string) error {
419
        if errStr != "" {
×
420
                subnet.Status.SetError(reason, errStr)
×
421
                if reason == "ValidateLogicalSwitchFailed" {
×
422
                        subnet.Status.NotValidated(reason, errStr)
×
423
                } else {
×
424
                        subnet.Status.Validated(reason, "")
×
425
                }
×
426
                subnet.Status.NotReady(reason, errStr)
×
427
                c.recorder.Eventf(subnet, v1.EventTypeWarning, reason, errStr)
×
428
        } else {
×
429
                subnet.Status.Validated(reason, "")
×
430
                c.recorder.Eventf(subnet, v1.EventTypeNormal, reason, errStr)
×
431
                if reason == "SetPrivateLogicalSwitchSuccess" ||
×
432
                        reason == "ResetLogicalSwitchAclSuccess" ||
×
433
                        reason == "ReconcileCentralizedGatewaySuccess" ||
×
434
                        reason == "SetNonOvnSubnetSuccess" {
×
435
                        subnet.Status.Ready(reason, "")
×
436
                }
×
437
        }
×
438

439
        bytes, err := subnet.Status.Bytes()
440
        if err != nil {
×
441
                klog.Error(err)
×
442
                return err
×
443
        }
×
444
        if _, err := c.config.KubeOvnClient.KubeovnV1().Subnets().Patch(context.Background(), subnet.Name, types.MergePatchType, bytes, metav1.PatchOptions{}, "status"); err != nil {
×
445
                klog.Errorf("failed to patch status for subnet %s, %v", subnet.Name, err)
×
446
                return err
×
447
        }
×
448
        return nil
×
449
}
×
450

451
func (c *Controller) validateVpcBySubnet(subnet *kubeovnv1.Subnet) (*kubeovnv1.Vpc, error) {
452
        vpc, err := c.vpcsLister.Get(subnet.Spec.Vpc)
×
453
        if err != nil {
×
454
                klog.Errorf("failed to get subnet's vpc '%s', %v", subnet.Spec.Vpc, err)
×
455
                return vpc, err
×
456
        }
×
457

×
458
        if !vpc.Status.Standby {
459
                err = fmt.Errorf("the vpc '%s' not standby yet", vpc.Name)
×
460
                klog.Error(err)
×
461
                return vpc, err
×
462
        }
×
463

×
464
        if !vpc.Status.Default {
465
                for _, ns := range subnet.Spec.Namespaces {
×
466
                        if !slices.Contains(vpc.Spec.Namespaces, ns) {
×
467
                                err = fmt.Errorf("namespace '%s' is out of range to custom vpc '%s'", ns, vpc.Name)
×
468
                                klog.Error(err)
×
469
                                return vpc, err
×
470
                        }
×
471
                }
×
472
        } else {
473
                vpcs, err := c.vpcsLister.List(labels.Everything())
×
474
                if err != nil {
×
475
                        klog.Errorf("failed to list vpc, %v", err)
×
476
                        return vpc, err
×
477
                }
×
478
                for _, vpc := range vpcs {
×
479
                        if (subnet.Annotations[util.VpcLastName] == "" && subnet.Spec.Vpc != vpc.Name ||
×
480
                                subnet.Annotations[util.VpcLastName] != "" && subnet.Annotations[util.VpcLastName] != vpc.Name) &&
×
481
                                !vpc.Status.Default && util.IsStringsOverlap(vpc.Spec.Namespaces, subnet.Spec.Namespaces) {
×
482
                                err = fmt.Errorf("namespaces %v are overlap with vpc '%s'", subnet.Spec.Namespaces, vpc.Name)
×
483
                                klog.Error(err)
×
484
                                return vpc, err
×
485
                        }
×
486
                }
×
487
        }
488
        return vpc, nil
489
}
×
490

491
func (c *Controller) checkSubnetConflict(subnet *kubeovnv1.Subnet) error {
492
        subnetList, err := c.subnetsLister.List(labels.Everything())
×
493
        if err != nil {
×
494
                klog.Errorf("failed to list subnets %v", err)
×
495
                return err
×
496
        }
×
497

×
498
        for _, sub := range subnetList {
499
                if sub.Spec.Vpc != subnet.Spec.Vpc || sub.Spec.Vlan != subnet.Spec.Vlan || sub.Name == subnet.Name {
×
500
                        continue
×
501
                }
×
502

503
                if util.CIDROverlap(sub.Spec.CIDRBlock, subnet.Spec.CIDRBlock) {
504
                        err = fmt.Errorf("subnet %s cidr %s is conflict with subnet %s cidr %s", subnet.Name, subnet.Spec.CIDRBlock, sub.Name, sub.Spec.CIDRBlock)
×
505
                        klog.Error(err)
×
506
                        if err = c.patchSubnetStatus(subnet, "ValidateLogicalSwitchFailed", err.Error()); err != nil {
×
507
                                klog.Error(err)
×
508
                                return err
×
509
                        }
×
510
                        return err
×
511
                }
×
512

513
                if subnet.Spec.ExternalEgressGateway != "" && sub.Spec.ExternalEgressGateway != "" &&
514
                        subnet.Spec.PolicyRoutingTableID == sub.Spec.PolicyRoutingTableID {
×
515
                        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)
×
516
                        klog.Error(err)
×
517
                        if err = c.patchSubnetStatus(subnet, "ValidateLogicalSwitchFailed", err.Error()); err != nil {
×
518
                                klog.Error(err)
×
519
                                return err
×
520
                        }
×
521
                        return err
×
522
                }
×
523
        }
524

525
        if subnet.Spec.Vlan == "" && subnet.Spec.Vpc == c.config.ClusterRouter {
526
                nodes, err := c.nodesLister.List(labels.Everything())
×
527
                if err != nil {
×
528
                        klog.Errorf("failed to list nodes: %v", err)
×
529
                        return err
×
530
                }
×
531
                for _, node := range nodes {
×
532
                        for _, addr := range node.Status.Addresses {
×
533
                                if addr.Type == v1.NodeInternalIP && util.CIDRContainIP(subnet.Spec.CIDRBlock, addr.Address) {
×
534
                                        err = fmt.Errorf("subnet %s cidr %s conflict with node %s address %s", subnet.Name, subnet.Spec.CIDRBlock, node.Name, addr.Address)
×
535
                                        klog.Error(err)
×
536
                                        if err = c.patchSubnetStatus(subnet, "ValidateLogicalSwitchFailed", err.Error()); err != nil {
×
537
                                                klog.Error(err)
×
538
                                                return err
×
539
                                        }
×
540
                                        return err
×
541
                                }
×
542
                        }
543
                }
544
        }
545
        return nil
546
}
×
547

548
func (c *Controller) updateSubnetDHCPOption(subnet *kubeovnv1.Subnet, needRouter bool) error {
549
        var mtu int
×
550
        if subnet.Spec.Mtu > 0 {
×
551
                mtu = int(subnet.Spec.Mtu)
×
552
        } else {
×
553
                mtu = util.DefaultMTU
×
554
                if subnet.Spec.Vlan == "" {
×
555
                        switch c.config.NetworkType {
×
556
                        case util.NetworkTypeVlan:
×
557
                                // default to geneve
×
558
                                fallthrough
×
559
                        case util.NetworkTypeGeneve:
×
560
                                mtu -= util.GeneveHeaderLength
×
561
                        case util.NetworkTypeVxlan:
×
562
                                mtu -= util.VxlanHeaderLength
×
563
                        case util.NetworkTypeStt:
×
564
                                mtu -= util.SttHeaderLength
×
565
                        default:
×
566
                                return fmt.Errorf("invalid network type: %s", c.config.NetworkType)
×
567
                        }
×
568
                }
569
        }
570

571
        dhcpOptionsUUIDs, err := c.OVNNbClient.UpdateDHCPOptions(subnet, mtu)
572
        if err != nil {
×
573
                klog.Errorf("failed to update dhcp options for switch %s, %v", subnet.Name, err)
×
574
                return err
×
575
        }
×
576

×
577
        vpc, err := c.vpcsLister.Get(subnet.Spec.Vpc)
578
        if err != nil {
×
579
                klog.Errorf("failed to get subnet's vpc '%s', %v", subnet.Spec.Vpc, err)
×
580
                return err
×
581
        }
×
582

×
583
        if needRouter {
584
                lrpName := fmt.Sprintf("%s-%s", vpc.Status.Router, subnet.Name)
×
585
                if err := c.OVNNbClient.UpdateLogicalRouterPortRA(lrpName, subnet.Spec.IPv6RAConfigs, subnet.Spec.EnableIPv6RA); err != nil {
×
586
                        klog.Errorf("update ipv6 ra configs for logical router port %s, %v", lrpName, err)
×
587
                        return err
×
588
                }
×
589
        }
×
590

591
        if subnet.Status.DHCPv4OptionsUUID != dhcpOptionsUUIDs.DHCPv4OptionsUUID || subnet.Status.DHCPv6OptionsUUID != dhcpOptionsUUIDs.DHCPv6OptionsUUID {
592
                subnet.Status.DHCPv4OptionsUUID = dhcpOptionsUUIDs.DHCPv4OptionsUUID
×
593
                subnet.Status.DHCPv6OptionsUUID = dhcpOptionsUUIDs.DHCPv6OptionsUUID
×
594
                bytes, err := subnet.Status.Bytes()
×
595
                if err != nil {
×
596
                        klog.Error(err)
×
597
                        return err
×
598
                }
×
599
                if _, err := c.config.KubeOvnClient.KubeovnV1().Subnets().Patch(context.Background(), subnet.Name, types.MergePatchType, bytes, metav1.PatchOptions{}, "status"); err != nil {
×
600
                        klog.Errorf("patch subnet %s dhcp options failed: %v", subnet.Name, err)
×
601
                        return err
×
602
                }
×
603
        }
×
604

605
        return nil
606
}
×
607

608
func (c *Controller) handleAddOrUpdateSubnet(key string) error {
609
        c.subnetKeyMutex.LockKey(key)
×
610
        defer func() { _ = c.subnetKeyMutex.UnlockKey(key) }()
×
611

×
612
        cachedSubnet, err := c.subnetsLister.Get(key)
613
        if err != nil {
×
614
                if k8serrors.IsNotFound(err) {
×
615
                        return nil
×
616
                }
×
617
                klog.Error(err)
×
618
                return err
×
619
        }
×
620
        klog.V(3).Infof("handle add or update subnet %s", cachedSubnet.Name)
621
        subnet := cachedSubnet.DeepCopy()
×
622
        subnet, err = c.formatSubnet(subnet)
×
623
        if err != nil {
×
NEW
624
                err := fmt.Errorf("failed to format subnet %s, %w", key, err)
×
NEW
625
                klog.Error(err)
×
NEW
626
                return err
×
NEW
627
        }
×
NEW
628

×
629
        err = c.validateSubnetVlan(subnet)
NEW
630
        if err != nil {
×
NEW
631
                err := fmt.Errorf("failed to validate vlan for subnet %s, %w", key, err)
×
632
                klog.Error(err)
×
NEW
633
                if err = c.patchSubnetStatus(subnet, "ValidateSubnetVlanFailed", err.Error()); err != nil {
×
NEW
634
                        klog.Error(err)
×
NEW
635
                        return err
×
NEW
636
                }
×
637
                return err
×
638
        }
×
639

640
        if err = util.ValidateSubnet(*subnet); err != nil {
641
                klog.Errorf("failed to validate subnet %s, %v", subnet.Name, err)
×
642
                if err = c.patchSubnetStatus(subnet, "ValidateLogicalSwitchFailed", err.Error()); err != nil {
×
643
                        klog.Error(err)
×
644
                        return err
×
645
                }
×
646
                return err
×
647
        }
×
648
        if err = c.patchSubnetStatus(subnet, "ValidateLogicalSwitchSuccess", ""); err != nil {
649
                klog.Error(err)
×
650
                return err
×
651
        }
×
652

×
653
        if err := c.ipam.AddOrUpdateSubnet(subnet.Name, subnet.Spec.CIDRBlock, subnet.Spec.Gateway, subnet.Spec.ExcludeIps); err != nil {
654
                klog.Error(err)
×
655
                return err
×
656
        }
×
657

×
658
        // availableIPStr valued from ipam, so leave update subnet.status after ipam process
659
        if subnet.Spec.Protocol == kubeovnv1.ProtocolDual {
660
                subnet, err = c.calcDualSubnetStatusIP(subnet)
×
661
        } else {
×
662
                subnet, err = c.calcSubnetStatusIP(subnet)
×
663
        }
×
664
        if err != nil {
×
665
                klog.Errorf("calculate subnet %s used ip failed, %v", cachedSubnet.Name, err)
×
666
                return err
×
667
        }
×
668

×
669
        subnet, deleted, err := c.handleSubnetFinalizer(subnet)
670
        if err != nil {
×
671
                klog.Errorf("handle subnet finalizer failed %v", err)
×
672
                return err
×
673
        }
×
674
        if deleted {
×
675
                return nil
×
676
        }
×
677

×
678
        if !isOvnSubnet(subnet) {
679
                // subnet provider is not ovn, and vpc is empty, should not reconcile
×
680
                if err = c.patchSubnetStatus(subnet, "SetNonOvnSubnetSuccess", ""); err != nil {
×
681
                        klog.Error(err)
×
682
                        return err
×
683
                }
×
684

×
685
                subnet.Status.EnsureStandardConditions()
686
                klog.Infof("non ovn subnet %s is ready", subnet.Name)
×
687
                return nil
×
688
        }
×
689

690
        // This validate should be processed after isOvnSubnet, since maybe there's no vpc for subnet not managed by kube-ovn
691
        vpc, err := c.validateVpcBySubnet(subnet)
692
        if err != nil {
×
693
                klog.Errorf("failed to get subnet's vpc '%s', %v", subnet.Spec.Vpc, err)
×
694
                return err
×
695
        }
×
696
        _, isMcastQuerierChanged, err := c.reconcileSubnetSpecialIPs(subnet)
×
697
        if err != nil {
×
698
                klog.Errorf("failed to reconcile subnet %s Custom IPs %v", subnet.Name, err)
×
699
                return err
×
700
        }
×
701
        if err := c.checkSubnetConflict(subnet); err != nil {
×
702
                klog.Errorf("failed to check subnet %s, %v", subnet.Name, err)
×
703
                return err
×
704
        }
×
705

×
706
        needRouter := subnet.Spec.Vlan == "" || subnet.Spec.LogicalGateway ||
707
                (subnet.Status.U2OInterconnectionIP != "" && subnet.Spec.U2OInterconnection)
×
708
        // 1. overlay subnet, should add lrp, lrp ip is subnet gw
×
709
        // 2. underlay subnet use logical gw, should add lrp, lrp ip is subnet gw
×
710
        randomAllocateGW := !subnet.Spec.LogicalGateway && vpc.Spec.EnableExternal && subnet.Name == c.config.ExternalGatewaySwitch
×
711
        // 3. underlay subnet use physical gw, vpc has eip, lrp managed in vpc process, lrp ip is random allocation, not subnet gw
×
712

×
713
        gateway := subnet.Spec.Gateway
×
714
        var gatewayMAC string
×
715
        if subnet.Status.U2OInterconnectionIP != "" && subnet.Spec.U2OInterconnection {
×
716
                gateway = subnet.Status.U2OInterconnectionIP
×
717
                gatewayMAC = subnet.Status.U2OInterconnectionMAC
×
718
        }
×
719

×
720
        if err := c.clearOldU2OResource(subnet); err != nil {
721
                klog.Errorf("clear subnet %s old u2o resource failed: %v", subnet.Name, err)
×
722
                return err
×
723
        }
×
724

×
725
        // create or update logical switch
726
        if err := c.OVNNbClient.CreateLogicalSwitch(subnet.Name, vpc.Status.Router, subnet.Spec.CIDRBlock, gateway, gatewayMAC, needRouter, randomAllocateGW); err != nil {
727
                klog.Errorf("create logical switch %s: %v", subnet.Name, err)
×
728
                return err
×
729
        }
×
730

×
731
        if isMcastQuerierChanged {
732
                if err := c.handleMcastQuerierChange(subnet); err != nil {
×
733
                        klog.Errorf("failed to handle mcast querier IP change for subnet %s: %v", subnet.Name, err)
×
734
                        return err
×
735
                }
×
736
        }
×
737

738
        subnet.Status.EnsureStandardConditions()
739

×
740
        if err := c.updateSubnetDHCPOption(subnet, needRouter); err != nil {
×
741
                klog.Errorf("failed to update subnet %s dhcpOptions: %v", subnet.Name, err)
×
742
                return err
×
743
        }
×
744

×
745
        if c.config.EnableLb && subnet.Name != c.config.NodeSwitch {
746
                lbs := []string{
×
747
                        vpc.Status.TCPLoadBalancer,
×
748
                        vpc.Status.TCPSessionLoadBalancer,
×
749
                        vpc.Status.UDPLoadBalancer,
×
750
                        vpc.Status.UDPSessionLoadBalancer,
×
751
                        vpc.Status.SctpLoadBalancer,
×
752
                        vpc.Status.SctpSessionLoadBalancer,
×
753
                }
×
754
                if subnet.Spec.EnableLb != nil && *subnet.Spec.EnableLb {
×
755
                        if err := c.OVNNbClient.LogicalSwitchUpdateLoadBalancers(subnet.Name, ovsdb.MutateOperationInsert, lbs...); err != nil {
×
756
                                if err = c.patchSubnetStatus(subnet, "AddLbToLogicalSwitchFailed", err.Error()); err != nil {
×
757
                                        klog.Error(err)
×
758
                                        return err
×
759
                                }
×
760
                                klog.Error(err)
×
761
                                return err
×
762
                        }
×
763
                } else {
764
                        if err := c.OVNNbClient.LogicalSwitchUpdateLoadBalancers(subnet.Name, ovsdb.MutateOperationDelete, lbs...); err != nil {
×
765
                                klog.Errorf("remove load-balancer from subnet %s failed: %v", subnet.Name, err)
×
766
                                return err
×
767
                        }
×
768
                }
×
769
        }
770

771
        if err := c.reconcileSubnet(subnet); err != nil {
772
                klog.Errorf("reconcile subnet for %s failed, %v", subnet.Name, err)
×
773
                return err
×
774
        }
×
775

×
776
        subnet.Status.U2OInterconnectionVPC = ""
777
        if subnet.Spec.U2OInterconnection {
×
778
                subnet.Status.U2OInterconnectionVPC = vpc.Status.Router
×
779
        }
×
780

×
781
        if err = c.updateNatOutgoingPolicyRulesStatus(subnet); err != nil {
782
                klog.Errorf("failed to update NAT outgoing policy status for subnet %s: %v", subnet.Name, err)
×
783
                return err
×
784
        }
×
785

×
786
        if subnet.Spec.Private {
787
                if err := c.OVNNbClient.SetLogicalSwitchPrivate(subnet.Name, subnet.Spec.CIDRBlock, c.config.NodeSwitchCIDR, subnet.Spec.AllowSubnets); err != nil {
×
788
                        if err = c.patchSubnetStatus(subnet, "SetPrivateLogicalSwitchFailed", err.Error()); err != nil {
×
789
                                klog.Error(err)
×
790
                                return err
×
791
                        }
×
792
                        klog.Error(err)
×
793
                        return err
×
794
                }
×
795

796
                if err = c.patchSubnetStatus(subnet, "SetPrivateLogicalSwitchSuccess", ""); err != nil {
797
                        klog.Error(err)
×
798
                        return err
×
799
                }
×
800
        } else {
×
801
                // clear acl when direction is ""
×
802
                if err = c.OVNNbClient.DeleteAcls(subnet.Name, logicalSwitchKey, "", nil); err != nil {
×
803
                        if err = c.patchSubnetStatus(subnet, "ResetLogicalSwitchAclFailed", err.Error()); err != nil {
×
804
                                klog.Error(err)
×
805
                                return err
×
806
                        }
×
807
                        klog.Error(err)
×
808
                        return err
×
809
                }
×
810

811
                if err = c.patchSubnetStatus(subnet, "ResetLogicalSwitchAclSuccess", ""); err != nil {
812
                        klog.Error(err)
×
813
                        return err
×
814
                }
×
815
        }
×
816

817
        if err := c.OVNNbClient.UpdateLogicalSwitchACL(subnet.Name, subnet.Spec.CIDRBlock, subnet.Spec.Acls, subnet.Spec.AllowEWTraffic); err != nil {
818
                if err = c.patchSubnetStatus(subnet, "SetLogicalSwitchAclsFailed", err.Error()); err != nil {
×
819
                        klog.Error(err)
×
820
                        return err
×
821
                }
×
822
                klog.Error(err)
×
823
                return err
×
824
        }
×
825

826
        c.updateVpcStatusQueue.Add(subnet.Spec.Vpc)
827

×
828
        ippools, err := c.ippoolLister.List(labels.Everything())
×
829
        if err != nil {
×
830
                klog.Errorf("failed to list ippools: %v", err)
×
831
                return err
×
832
        }
×
833

×
834
        for _, p := range ippools {
835
                if p.Spec.Subnet == subnet.Name {
×
836
                        c.addOrUpdateIPPoolQueue.Add(p.Name)
×
837
                }
×
838
        }
×
839

840
        return nil
841
}
×
842

843
func (c *Controller) handleUpdateSubnetStatus(key string) error {
844
        c.subnetKeyMutex.LockKey(key)
×
845
        defer func() { _ = c.subnetKeyMutex.UnlockKey(key) }()
×
846

×
847
        cachedSubnet, err := c.subnetsLister.Get(key)
848
        subnet := cachedSubnet.DeepCopy()
×
849
        if err != nil {
×
850
                if k8serrors.IsNotFound(err) {
×
851
                        return nil
×
852
                }
×
853
                klog.Error(err)
×
854
                return err
×
855
        }
×
856

857
        ippools, err := c.ippoolLister.List(labels.Everything())
858
        if err != nil {
×
859
                klog.Errorf("failed to list ippool: %v", err)
×
860
                return err
×
861
        }
×
862
        for _, p := range ippools {
×
863
                if p.Spec.Subnet == subnet.Name {
×
864
                        c.updateIPPoolStatusQueue.Add(p.Name)
×
865
                }
×
866
        }
×
867

868
        if util.CheckProtocol(subnet.Spec.CIDRBlock) == kubeovnv1.ProtocolDual {
869
                if _, err := c.calcDualSubnetStatusIP(subnet); err != nil {
×
870
                        klog.Error(err)
×
871
                        return err
×
872
                }
×
873
        } else {
×
874
                if _, err = c.calcSubnetStatusIP(subnet); err != nil {
×
875
                        klog.Error(err)
×
876
                        return err
×
877
                }
×
878
        }
×
879

880
        if err := c.checkSubnetUsingIPs(subnet); err != nil {
881
                klog.Errorf("inconsistency detected in status of subnet %s : %v", subnet.Name, err)
×
882
                return err
×
883
        }
×
884
        return nil
×
885
}
×
886

887
func (c *Controller) handleDeleteLogicalSwitch(key string) (err error) {
888
        c.ipam.DeleteSubnet(key)
×
889

×
890
        exist, err := c.OVNNbClient.LogicalSwitchExists(key)
×
891
        if err != nil {
×
892
                klog.Errorf("check logical switch %s exist: %v", key, err)
×
893
                return err
×
894
        }
×
895

×
896
        // not found, skip
897
        if !exist {
898
                return nil
×
899
        }
×
900

×
901
        // clear acl when direction is ""
902
        if err = c.OVNNbClient.DeleteAcls(key, logicalSwitchKey, "", nil); err != nil {
903
                klog.Errorf("clear logical switch %s acls: %v", key, err)
×
904
                return err
×
905
        }
×
906

×
907
        if err = c.OVNNbClient.DeleteDHCPOptions(key, kubeovnv1.ProtocolDual); err != nil {
908
                klog.Errorf("failed to delete dhcp options of logical switch %s %v", key, err)
×
909
                return err
×
910
        }
×
911

×
912
        if err = c.OVNNbClient.DeleteLogicalSwitch(key); err != nil {
913
                klog.Errorf("delete logical switch %s: %v", key, err)
×
914
                return err
×
915
        }
×
916

×
917
        nss, err := c.namespacesLister.List(labels.Everything())
918
        if err != nil {
×
919
                klog.Errorf("failed to list namespaces, %v", err)
×
920
                return err
×
921
        }
×
922

×
923
        // re-annotate namespace
924
        for _, ns := range nss {
925
                annotations := ns.GetAnnotations()
×
926
                if annotations == nil {
×
927
                        continue
×
928
                }
×
929

930
                if slices.Contains(strings.Split(annotations[util.LogicalSwitchAnnotation], ","), key) {
931
                        c.enqueueAddNamespace(ns)
×
932
                }
×
933
        }
×
934

935
        return c.delLocalnet(key)
936
}
×
937

938
func (c *Controller) handleDeleteSubnet(subnet *kubeovnv1.Subnet) error {
939
        c.subnetKeyMutex.LockKey(subnet.Name)
×
940
        defer func() { _ = c.subnetKeyMutex.UnlockKey(subnet.Name) }()
×
941

×
942
        c.updateVpcStatusQueue.Add(subnet.Spec.Vpc)
943
        klog.Infof("delete u2o interconnection policy route for subnet %s", subnet.Name)
×
944
        if err := c.deletePolicyRouteForU2OInterconn(subnet); err != nil {
×
945
                klog.Errorf("failed to delete policy route for underlay to overlay subnet interconnection %s, %v", subnet.Name, err)
×
946
                return err
×
947
        }
×
948
        if subnet.Spec.Vpc != c.config.ClusterRouter {
×
949
                if err := c.deleteStaticRouteForU2OInterconn(subnet); err != nil {
×
950
                        klog.Errorf("failed to delete static route for underlay to overlay subnet interconnection %s, %v", subnet.Name, err)
×
951
                        return err
×
952
                }
×
953
        }
×
954

955
        u2oInterconnName := fmt.Sprintf(util.U2OInterconnName, subnet.Spec.Vpc, subnet.Name)
956
        if err := c.config.KubeOvnClient.KubeovnV1().IPs().Delete(context.Background(), u2oInterconnName, metav1.DeleteOptions{}); err != nil {
×
957
                if !k8serrors.IsNotFound(err) {
×
958
                        klog.Errorf("failed to delete ip %s, %v", u2oInterconnName, err)
×
959
                        return err
×
960
                }
×
961
        }
×
962

963
        if subnet.Spec.Vpc != c.config.ClusterRouter {
964
                if err := c.deleteCustomVPCPolicyRoutesForSubnet(subnet); err != nil {
×
965
                        klog.Errorf("failed to delete custom vpc routes subnet %s, %v", subnet.Name, err)
×
966
                        return err
×
967
                }
×
968
        }
×
969

970
        klog.Infof("delete policy route for %s subnet %s", subnet.Spec.GatewayType, subnet.Name)
971
        if err := c.deletePolicyRouteByGatewayType(subnet, subnet.Spec.GatewayType, true); err != nil {
×
972
                klog.Errorf("failed to delete policy route for overlay subnet %s, %v", subnet.Name, err)
×
973
                return err
×
974
        }
×
975

×
976
        err := c.handleDeleteLogicalSwitch(subnet.Name)
977
        if err != nil {
×
978
                klog.Errorf("failed to delete logical switch %s %v", subnet.Name, err)
×
979
                return err
×
980
        }
×
981

×
982
        var router string
983
        vpc, err := c.vpcsLister.Get(subnet.Spec.Vpc)
×
984
        if err != nil {
×
985
                if !k8serrors.IsNotFound(err) {
×
986
                        klog.Errorf("get vpc %s: %v", vpc.Name, err)
×
987
                        return err
×
988
                }
×
989
                router = c.config.ClusterRouter
×
990
        } else {
×
991
                router = vpc.Status.Router
×
992
        }
×
993

×
994
        lspName := fmt.Sprintf("%s-%s", subnet.Name, router)
995
        lrpName := fmt.Sprintf("%s-%s", router, subnet.Name)
×
996
        if err = c.OVNNbClient.RemoveLogicalPatchPort(lspName, lrpName); err != nil {
×
997
                klog.Errorf("delete router port %s and %s:%v", lspName, lrpName, err)
×
998
                return err
×
999
        }
×
1000

×
1001
        vlans, err := c.vlansLister.List(labels.Everything())
1002
        if err != nil && !k8serrors.IsNotFound(err) {
×
1003
                klog.Errorf("failed to list vlans: %v", err)
×
1004
                return err
×
1005
        }
×
1006

×
1007
        for _, vlan := range vlans {
1008
                if err = c.updateVlanStatusForSubnetDeletion(vlan, subnet.Name); err != nil {
×
1009
                        klog.Error(err)
×
1010
                        return err
×
1011
                }
×
1012
        }
×
1013

1014
        return nil
1015
}
×
1016

1017
func (c *Controller) updateVlanStatusForSubnetDeletion(vlan *kubeovnv1.Vlan, subnet string) error {
1018
        if !slices.Contains(vlan.Status.Subnets, subnet) {
×
1019
                return nil
×
1020
        }
×
1021

×
1022
        newVlan := vlan.DeepCopy()
1023
        newVlan.Status.Subnets = util.RemoveString(newVlan.Status.Subnets, subnet)
×
1024
        _, err := c.config.KubeOvnClient.KubeovnV1().Vlans().UpdateStatus(context.Background(), newVlan, metav1.UpdateOptions{})
×
1025
        if err != nil {
×
1026
                klog.Errorf("failed to update status of vlan %s: %v", vlan.Name, err)
×
1027
                return err
×
1028
        }
×
1029

×
1030
        return nil
1031
}
×
1032

1033
func (c *Controller) reconcileSubnet(subnet *kubeovnv1.Subnet) error {
1034
        if err := c.reconcileNamespaces(subnet); err != nil {
×
1035
                klog.Errorf("reconcile namespaces for subnet %s failed, %v", subnet.Name, err)
×
1036
                return err
×
1037
        }
×
1038

×
1039
        if err := c.reconcileRouteTableForSubnet(subnet); err != nil {
1040
                klog.Errorf("reconcile route table for subnet %s failed, %v", subnet.Name, err)
×
1041
                return err
×
1042
        }
×
1043

×
1044
        if subnet.Spec.Vpc == c.config.ClusterRouter {
1045
                if err := c.reconcileOvnDefaultVpcRoute(subnet); err != nil {
×
1046
                        klog.Errorf("reconcile default vpc ovn route for subnet %s failed: %v", subnet.Name, err)
×
1047
                        return err
×
1048
                }
×
1049
        }
×
1050

1051
        if subnet.Spec.Vpc != c.config.ClusterRouter {
1052
                if err := c.reconcileCustomVpcStaticRoute(subnet); err != nil {
×
1053
                        klog.Errorf("reconcile custom vpc ovn route for subnet %s failed: %v", subnet.Name, err)
×
1054
                        return err
×
1055
                }
×
1056
        }
×
1057

1058
        if err := c.reconcileVlan(subnet); err != nil {
1059
                klog.Errorf("reconcile vlan for subnet %s failed, %v", subnet.Name, err)
×
1060
                return err
×
1061
        }
×
1062

×
1063
        if err := c.reconcileVips(subnet); err != nil {
1064
                klog.Errorf("reconcile vips for subnet %s failed, %v", subnet.Name, err)
×
1065
                return err
×
1066
        }
×
1067
        return nil
×
1068
}
×
1069

1070
func (c *Controller) reconcileVips(subnet *kubeovnv1.Subnet) error {
1071
        /* get all virtual port belongs to this logical switch */
1✔
1072
        lsps, err := c.OVNNbClient.ListLogicalSwitchPorts(true, map[string]string{logicalSwitchKey: subnet.Name}, func(lsp *ovnnb.LogicalSwitchPort) bool {
1✔
1073
                return lsp.Type == "virtual"
1✔
1074
        })
×
1075
        if err != nil {
×
1076
                klog.Errorf("failed to find virtual port for subnet %s: %v", subnet.Name, err)
1✔
1077
                return err
×
1078
        }
×
1079

×
1080
        /* filter all invalid virtual port */
1081
        existVips := make(map[string]string) // key is vip, value is port name
1082
        for _, lsp := range lsps {
1✔
1083
                vip, ok := lsp.Options["virtual-ip"]
2✔
1084
                if !ok {
1✔
1085
                        continue // ignore vip which is empty
1✔
1086
                }
×
1087

1088
                if net.ParseIP(vip) == nil {
1089
                        continue // ignore invalid vip
1✔
1090
                }
×
1091

1092
                existVips[vip] = lsp.Name
1093
        }
1✔
1094

1095
        /* filter virtual port to be added and old virtual port to be deleted */
1096
        var newVips []string
1097
        for _, vip := range subnet.Spec.Vips {
1✔
1098
                if _, ok := existVips[vip]; !ok {
2✔
1099
                        // new virtual port to be added
2✔
1100
                        newVips = append(newVips, vip)
1✔
1101
                } else {
1✔
1102
                        // delete old virtual port that do not need to be deleted
2✔
1103
                        delete(existVips, vip)
1✔
1104
                }
1✔
1105
        }
1✔
1106

1107
        // delete old virtual ports
1108
        for _, lspName := range existVips {
1109
                if err = c.OVNNbClient.DeleteLogicalSwitchPort(lspName); err != nil {
2✔
1110
                        klog.Errorf("delete virtual port %s lspName from logical switch %s: %v", lspName, subnet.Name, err)
1✔
1111
                        return err
×
1112
                }
×
1113
        }
×
1114

1115
        // add new virtual port
1116
        if err = c.OVNNbClient.CreateVirtualLogicalSwitchPorts(subnet.Name, newVips...); err != nil {
1117
                klog.Errorf("create virtual port with vips %v from logical switch %s: %v", newVips, subnet.Name, err)
1✔
1118
                return err
×
1119
        }
×
1120

×
1121
        c.syncVirtualPortsQueue.Add(subnet.Name)
1122
        return nil
1✔
1123
}
1✔
1124

1125
func (c *Controller) syncVirtualPort(key string) error {
1126
        subnet, err := c.subnetsLister.Get(key)
1✔
1127
        if err != nil {
1✔
1128
                if k8serrors.IsNotFound(err) {
1✔
1129
                        return nil
×
1130
                }
×
1131
                klog.Errorf("failed to get subnet %s, %v", key, err)
×
1132
                return err
×
1133
        }
×
1134
        if len(subnet.Spec.Vips) == 0 {
1135
                return nil
1✔
1136
        }
×
1137

×
1138
        externalIDs := map[string]string{
1139
                logicalSwitchKey: subnet.Name,
1✔
1140
                "attach-vips":    "true",
1✔
1141
        }
1✔
1142

1✔
1143
        lsps, err := c.OVNNbClient.ListNormalLogicalSwitchPorts(true, externalIDs)
1✔
1144
        if err != nil {
1✔
1145
                klog.Errorf("list logical switch %s ports: %v", subnet.Name, err)
1✔
1146
                return err
×
1147
        }
×
1148

×
1149
        for _, vip := range subnet.Spec.Vips {
1150
                if !util.CIDRContainIP(subnet.Spec.CIDRBlock, vip) {
2✔
1151
                        klog.Errorf("vip %s is out of range to subnet %s", vip, subnet.Name)
1✔
1152
                        continue
×
1153
                }
×
1154

1155
                var virtualParents []string
1156
                for _, lsp := range lsps {
1✔
1157
                        vips, ok := lsp.ExternalIDs["vips"]
2✔
1158
                        if !ok {
1✔
1159
                                continue // ignore vips which is empty
1✔
1160
                        }
×
1161

1162
                        if strings.Contains(vips, vip) {
1163
                                virtualParents = append(virtualParents, lsp.Name)
2✔
1164
                        }
1✔
1165
                }
1✔
1166

1167
                // logical switch port has no valid vip
1168
                if len(virtualParents) == 0 {
1169
                        continue
2✔
1170
                }
1✔
1171

1172
                if err = c.OVNNbClient.SetLogicalSwitchPortVirtualParents(subnet.Name, strings.Join(virtualParents, ","), vip); err != nil {
1173
                        klog.Errorf("set vip %s virtual parents %v: %v", vip, virtualParents, err)
1✔
1174
                        return err
×
1175
                }
×
1176
        }
×
1177

1178
        return nil
1179
}
1✔
1180

1181
func (c *Controller) reconcileNamespaces(subnet *kubeovnv1.Subnet) error {
1182
        var (
×
1183
                namespaces []*v1.Namespace
×
1184
                err        error
×
1185
        )
×
1186

×
1187
        // 1. get all namespaces should be updated
×
1188
        expectNss, err := c.getNamespacesBySelector(subnet.Spec.NamespaceSelectors)
×
1189
        if err != nil {
×
1190
                klog.Errorf("failed to list namespaces by selector, %v", err)
×
1191
                return err
×
1192
        }
×
1193
        for _, ns := range subnet.Spec.Namespaces {
×
1194
                if !slices.Contains(expectNss, ns) {
×
1195
                        expectNss = append(expectNss, ns)
×
1196
                }
×
1197
        }
×
1198

1199
        // 2. update namespaces
1200
        for _, expectNs := range expectNss {
1201
                checkNs, err := c.namespacesLister.Get(expectNs)
×
1202
                if err != nil {
×
1203
                        if k8serrors.IsNotFound(err) {
×
1204
                                continue
×
1205
                        }
×
1206
                        klog.Error(err)
1207
                        return err
×
1208
                }
×
1209
                if checkNs.Annotations != nil && slices.Contains(strings.Split(checkNs.Annotations[util.LogicalSwitchAnnotation], ","), subnet.Name) {
1210
                        // when subnet cidr changed, the ns annotation with the subnet should be updated
×
1211
                        if !slices.Contains(strings.Split(checkNs.Annotations[util.CidrAnnotation], ";"), subnet.Spec.CIDRBlock) {
×
1212
                                c.addNamespaceQueue.Add(checkNs.Name)
×
1213
                        }
×
1214
                        continue
×
1215
                }
×
1216
                c.addNamespaceQueue.Add(expectNs)
1217
        }
×
1218

1219
        // 3. update unbind namespace annotation
1220
        if namespaces, err = c.namespacesLister.List(labels.Everything()); err != nil {
1221
                klog.Errorf("failed to list namespaces, %v", err)
×
1222
                return err
×
1223
        }
×
1224

×
1225
        for _, ns := range namespaces {
1226
                if ns.Annotations != nil && slices.Contains(strings.Split(ns.Annotations[util.LogicalSwitchAnnotation], ","), subnet.Name) {
×
1227
                        if slices.Contains(expectNss, ns.Name) {
×
1228
                                continue
×
1229
                        }
×
1230
                        // ns deleted from subnet.Spec.Namespaces or subnet delete namespaceSelectors which match the checked namespace
1231
                        c.addNamespaceQueue.Add(ns.Name)
1232
                }
×
1233
        }
1234

1235
        return nil
1236
}
×
1237

1238
func (c *Controller) getNamespacesBySelector(nsSelectors []metav1.LabelSelector) ([]string, error) {
1239
        var expectNss []string
×
1240
        for _, nsSelector := range nsSelectors {
×
1241
                matchSelector, err := metav1.LabelSelectorAsSelector(&nsSelector)
×
1242
                if err != nil {
×
1243
                        klog.Errorf("failed to convert label selector, %v", err)
×
1244
                        return expectNss, err
×
1245
                }
×
1246

×
1247
                nss, err := c.namespacesLister.List(matchSelector)
1248
                if err != nil {
×
1249
                        klog.Errorf("failed to list namespaces by selector, %v", err)
×
1250
                        return expectNss, err
×
1251
                }
×
1252
                for _, ns := range nss {
×
1253
                        expectNss = append(expectNss, ns.Name)
×
1254
                }
×
1255
        }
×
1256
        return expectNss, nil
1257
}
×
1258

1259
func (c *Controller) reconcileCustomVpcBfdStaticRoute(vpcName, subnetName string) error {
1260
        // vpc enable bfd and subnet enable ecmp
×
1261
        // use static ecmp route with bfd
×
1262
        ovnEips, err := c.ovnEipsLister.List(labels.SelectorFromSet(labels.Set{util.OvnEipTypeLabel: util.OvnEipTypeLSP}))
×
1263
        if err != nil {
×
1264
                klog.Errorf("failed to list node external ovn eip, %v", err)
×
1265
                return err
×
1266
        }
×
1267
        if len(ovnEips) < 2 {
×
1268
                err := fmt.Errorf("ecmp route with bfd for HA, which need two %s type eips at least, has %d", util.OvnEipTypeLSP, len(ovnEips))
×
1269
                klog.Error(err)
×
1270
                return err
×
1271
        }
×
1272

×
1273
        subnet, err := c.subnetsLister.Get(subnetName)
1274
        if err != nil {
×
1275
                klog.Errorf("failed to get subnet %s, %v", subnetName, err)
×
1276
                return err
×
1277
        }
×
1278
        cachedVpc, err := c.vpcsLister.Get(vpcName)
×
1279
        if err != nil {
×
1280
                if k8serrors.IsNotFound(err) {
×
1281
                        return nil
×
1282
                }
×
1283
                klog.Errorf("failed to get vpc %s, %v", vpcName, err)
×
1284
                return err
×
1285
        }
×
1286

1287
        var (
1288
                needUpdate, v4Exist bool
×
1289
                lrpEipName          string
×
1290
        )
×
1291

×
1292
        lrpEipName = fmt.Sprintf("%s-%s", vpcName, c.config.ExternalGatewaySwitch)
×
1293
        lrpEip, err := c.ovnEipsLister.Get(lrpEipName)
×
1294
        if err != nil {
×
1295
                err := fmt.Errorf("failed to get lrp eip %s, %w", lrpEipName, err)
×
1296
                klog.Error(err)
×
1297
                return err
×
1298
        }
×
1299
        if !lrpEip.Status.Ready || lrpEip.Status.V4Ip == "" {
×
1300
                err := fmt.Errorf("lrp eip %q not ready", lrpEipName)
×
1301
                klog.Error(err)
×
1302
                return err
×
1303
        }
×
1304
        vpc := cachedVpc.DeepCopy()
×
1305

×
1306
        for _, eip := range ovnEips {
×
1307
                if !eip.Status.Ready || eip.Status.V4Ip == "" {
×
1308
                        err := fmt.Errorf("ovn eip %q not ready", eip.Name)
×
1309
                        klog.Error(err)
×
1310
                        return err
×
1311
                }
×
1312
                bfd, err := c.OVNNbClient.CreateBFD(lrpEipName, eip.Status.V4Ip, c.config.BfdMinRx, c.config.BfdMinTx, c.config.BfdDetectMult, nil)
×
1313
                if err != nil {
×
1314
                        klog.Error(err)
×
1315
                        return err
×
1316
                }
×
1317
                // TODO:// support v6
×
1318
                v4Exist = false
1319
                for _, route := range vpc.Spec.StaticRoutes {
×
1320
                        if route.Policy == kubeovnv1.PolicySrc &&
×
1321
                                route.NextHopIP == eip.Status.V4Ip &&
×
1322
                                route.ECMPMode == util.StaticRouteBfdEcmp &&
×
1323
                                route.CIDR == subnet.Spec.CIDRBlock &&
×
1324
                                route.RouteTable == subnet.Spec.RouteTable {
×
1325
                                v4Exist = true
×
1326
                                break
×
1327
                        }
×
1328
                }
1329
                if !v4Exist {
1330
                        // add ecmp type static route with bfd
×
1331
                        route := &kubeovnv1.StaticRoute{
×
1332
                                Policy:     kubeovnv1.PolicySrc,
×
1333
                                CIDR:       subnet.Spec.CIDRBlock,
×
1334
                                NextHopIP:  eip.Status.V4Ip,
×
1335
                                ECMPMode:   util.StaticRouteBfdEcmp,
×
1336
                                BfdID:      bfd.UUID,
×
1337
                                RouteTable: subnet.Spec.RouteTable,
×
1338
                        }
×
1339
                        klog.Infof("add ecmp bfd static route %v", route)
×
1340
                        vpc.Spec.StaticRoutes = append(vpc.Spec.StaticRoutes, route)
×
1341
                        needUpdate = true
×
1342
                }
×
1343
        }
×
1344
        if needUpdate {
1345
                if _, err = c.config.KubeOvnClient.KubeovnV1().Vpcs().Update(context.Background(), vpc, metav1.UpdateOptions{}); err != nil {
×
1346
                        klog.Errorf("failed to update vpc spec static route %s, %v", vpc.Name, err)
×
1347
                        return err
×
1348
                }
×
1349
                if err = c.patchVpcBfdStatus(vpc.Name); err != nil {
×
1350
                        klog.Errorf("failed to patch vpc %s, %v", vpc.Name, err)
×
1351
                        return err
×
1352
                }
×
1353
        }
×
1354
        return nil
1355
}
×
1356

1357
func (c *Controller) reconcileCustomVpcDelNormalStaticRoute(vpcName string) error {
1358
        // normal static route is prior than ecmp bfd static route
×
1359
        // if use ecmp bfd static route, normal static route should not exist
×
1360
        defaultExternalSubnet, err := c.subnetsLister.Get(c.config.ExternalGatewaySwitch)
×
1361
        if err != nil {
×
1362
                klog.Errorf("failed to get default external switch subnet %s: %v", c.config.ExternalGatewaySwitch, err)
×
1363
                return err
×
1364
        }
×
1365
        gatewayV4, gatewayV6 := util.SplitStringIP(defaultExternalSubnet.Spec.Gateway)
×
1366
        needUpdate := false
×
1367
        vpc, err := c.vpcsLister.Get(vpcName)
×
1368
        if err != nil {
×
1369
                if k8serrors.IsNotFound(err) {
×
1370
                        return nil
×
1371
                }
×
1372
                klog.Errorf("failed to get vpc %s, %v", vpcName, err)
×
1373
                return err
×
1374
        }
×
1375
        routeTotal := len(vpc.Spec.StaticRoutes)
1376
        routes := make([]*kubeovnv1.StaticRoute, 0, routeTotal)
×
1377
        for _, route := range vpc.Spec.StaticRoutes {
×
1378
                if route.Policy == kubeovnv1.PolicyDst &&
×
1379
                        (route.NextHopIP == gatewayV4 || route.NextHopIP == gatewayV6) &&
×
1380
                        (route.CIDR == "0.0.0.0/0" || route.CIDR == "::/0") {
×
1381
                        klog.Infof("in order to use ecmp bfd route, need remove normal static route %v", route)
×
1382
                        needUpdate = true
×
1383
                } else {
×
1384
                        routes = append(routes, route)
×
1385
                }
×
1386
        }
×
1387

1388
        if needUpdate {
1389
                vpc.Spec.StaticRoutes = routes
×
1390
                if _, err = c.config.KubeOvnClient.KubeovnV1().Vpcs().Update(context.Background(), vpc, metav1.UpdateOptions{}); err != nil {
×
1391
                        klog.Errorf("failed to update vpc spec static route %s, %v", vpc.Name, err)
×
1392
                        return err
×
1393
                }
×
1394
        }
×
1395

1396
        if err = c.patchVpcBfdStatus(vpc.Name); err != nil {
1397
                klog.Errorf("failed to patch vpc %s, %v", vpc.Name, err)
×
1398
                return err
×
1399
        }
×
1400

×
1401
        return nil
1402
}
×
1403

1404
func (c *Controller) reconcileDistributedSubnetRouteInDefaultVpc(subnet *kubeovnv1.Subnet) error {
1405
        if subnet.Spec.GatewayNode != "" || subnet.Status.ActivateGateway != "" {
×
1406
                klog.Infof("delete old centralized policy route for subnet %s", subnet.Name)
×
1407
                if err := c.deletePolicyRouteForCentralizedSubnet(subnet); err != nil {
×
1408
                        klog.Errorf("failed to delete policy route for subnet %s, %v", subnet.Name, err)
×
1409
                        return err
×
1410
                }
×
1411

×
1412
                subnet.Spec.GatewayNode = ""
1413
                if _, err := c.config.KubeOvnClient.KubeovnV1().Subnets().Update(context.Background(), subnet, metav1.UpdateOptions{}); err != nil {
×
1414
                        klog.Errorf("failed to remove gatewayNode or activateGateway from subnet %s, %v", subnet.Name, err)
×
1415
                        return err
×
1416
                }
×
1417
                subnet.Status.ActivateGateway = ""
×
1418
                if err := c.patchSubnetStatus(subnet, "ChangeToDistributedGw", ""); err != nil {
×
1419
                        klog.Error(err)
×
1420
                        return err
×
1421
                }
×
1422
        }
×
1423

1424
        nodes, err := c.nodesLister.List(labels.Everything())
1425
        if err != nil {
×
1426
                klog.Errorf("failed to list nodes: %v", err)
×
1427
                return err
×
1428
        }
×
1429
        for _, node := range nodes {
×
1430
                if err = c.createPortGroupForDistributedSubnet(node, subnet); err != nil {
×
1431
                        klog.Errorf("failed to create port group %v", err)
×
1432
                        return err
×
1433
                }
×
1434
                if node.Annotations[util.AllocatedAnnotation] != "true" {
×
1435
                        continue
×
1436
                }
×
1437
                nodeIP, err := getNodeTunlIP(node)
×
1438
                if err != nil {
1439
                        klog.Errorf("failed to get node %s tunnel ip, %v", node.Name, err)
×
1440
                        return err
×
1441
                }
×
1442
                nextHop := getNextHopByTunnelIP(nodeIP)
×
1443
                v4IP, v6IP := util.SplitStringIP(nextHop)
×
1444
                if err = c.addPolicyRouteForDistributedSubnet(subnet, node.Name, v4IP, v6IP); err != nil {
×
1445
                        klog.Errorf("failed to add policy router for node %s and subnet %s: %v", node.Name, subnet.Name, err)
×
1446
                        return err
×
1447
                }
×
1448
        }
×
1449

×
1450
        pods, err := c.podsLister.Pods(metav1.NamespaceAll).List(labels.Everything())
1451
        if err != nil {
1452
                klog.Errorf("failed to list pods %v", err)
×
1453
                return err
×
1454
        }
×
1455
        for _, pod := range pods {
×
1456
                if !isPodAlive(pod) || pod.Spec.NodeName == "" {
×
1457
                        continue
×
1458
                }
×
1459

×
1460
                podNets, err := c.getPodKubeovnNets(pod)
1461
                if err != nil {
1462
                        klog.Errorf("failed to get pod nets %v", err)
×
1463
                        continue
×
1464
                }
×
1465

×
1466
                podPorts := make([]string, 0, 1)
1467
                for _, podNet := range podNets {
1468
                        if !isOvnSubnet(podNet.Subnet) {
×
1469
                                continue
×
1470
                        }
×
1471

×
1472
                        if pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, podNet.ProviderName)] == "" || pod.Annotations[fmt.Sprintf(util.LogicalSwitchAnnotationTemplate, podNet.ProviderName)] != subnet.Name {
1473
                                continue
1474
                        }
×
1475

×
1476
                        podName := c.getNameByPod(pod)
1477
                        portName := ovs.PodNameToPortName(podName, pod.Namespace, podNet.ProviderName)
1478
                        podPorts = append(podPorts, portName)
×
1479
                }
×
1480

×
1481
                pgName := getOverlaySubnetsPortGroupName(subnet.Name, pod.Spec.NodeName)
1482
                portsToAdd := make([]string, 0, len(podPorts))
1483
                for _, port := range podPorts {
×
1484
                        exist, err := c.OVNNbClient.LogicalSwitchPortExists(port)
×
1485
                        if err != nil {
×
1486
                                klog.Error(err)
×
1487
                                return err
×
1488
                        }
×
1489

×
1490
                        if !exist {
×
1491
                                klog.Errorf("lsp does not exist for pod %v, please delete the pod and retry", port)
1492
                                continue
×
1493
                        }
×
1494

×
1495
                        portsToAdd = append(portsToAdd, port)
1496
                }
1497

×
1498
                if err = c.OVNNbClient.PortGroupAddPorts(pgName, portsToAdd...); err != nil {
1499
                        klog.Errorf("add ports to port group %s: %v", pgName, err)
1500
                        return err
×
1501
                }
×
1502
        }
×
1503
        return nil
×
1504
}
1505

×
1506
func (c *Controller) reconcileDefaultCentralizedSubnetRouteInDefaultVpc(subnet *kubeovnv1.Subnet) error {
1507
        // check if activateGateway still ready
1508
        if subnet.Status.ActivateGateway != "" && util.GatewayContains(subnet.Spec.GatewayNode, subnet.Status.ActivateGateway) {
×
1509
                node, err := c.nodesLister.Get(subnet.Status.ActivateGateway)
×
1510
                if err == nil && nodeReady(node) {
×
1511
                        klog.Infof("subnet %s uses the old activate gw %s", subnet.Name, node.Name)
×
1512

×
1513
                        nodeTunlIPAddr, err := getNodeTunlIP(node)
×
1514
                        if err != nil {
×
1515
                                klog.Errorf("failed to get gatewayNode tunnel ip for subnet %s", subnet.Name)
×
1516
                                return err
×
1517
                        }
×
1518
                        nextHop := getNextHopByTunnelIP(nodeTunlIPAddr)
×
1519
                        if err = c.addPolicyRouteForCentralizedSubnet(subnet, subnet.Status.ActivateGateway, nil, strings.Split(nextHop, ",")); err != nil {
×
1520
                                klog.Errorf("failed to add active-backup policy route for centralized subnet %s: %v", subnet.Name, err)
×
1521
                                return err
×
1522
                        }
×
1523
                        return nil
×
1524
                }
×
1525
        }
×
1526

1527
        klog.Info("find a new activate node")
1528
        // need a new activate gateway
1529
        newActivateNode := ""
×
1530
        var nodeTunlIPAddr []net.IP
×
1531
        for _, gw := range strings.Split(subnet.Spec.GatewayNode, ",") {
×
1532
                // the format of gatewayNodeStr 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
×
1533
                if strings.Contains(gw, ":") {
×
1534
                        gw = strings.TrimSpace(strings.Split(gw, ":")[0])
×
1535
                } else {
×
1536
                        gw = strings.TrimSpace(gw)
×
1537
                }
×
1538
                node, err := c.nodesLister.Get(gw)
×
1539
                if err == nil && nodeReady(node) {
×
1540
                        newActivateNode = node.Name
×
1541
                        nodeTunlIPAddr, err = getNodeTunlIP(node)
×
1542
                        if err != nil {
×
1543
                                klog.Error(err)
×
1544
                                return err
×
1545
                        }
×
1546
                        klog.Infof("subnet %s uses a new activate gw %s", subnet.Name, node.Name)
×
1547
                        break
×
1548
                }
×
1549
        }
×
1550
        if newActivateNode == "" {
1551
                klog.Warningf("all gateways of subnet %s are not ready", subnet.Name)
1552
                subnet.Status.ActivateGateway = newActivateNode
×
1553
                if err := c.patchSubnetStatus(subnet, "NoActiveGatewayFound", fmt.Sprintf("subnet %s gws are not ready", subnet.Name)); err != nil {
×
1554
                        klog.Error(err)
×
1555
                        return err
×
1556
                }
×
1557

×
1558
                return fmt.Errorf("subnet %s gws are not ready", subnet.Name)
×
1559
        }
1560

×
1561
        nextHop := getNextHopByTunnelIP(nodeTunlIPAddr)
1562
        klog.Infof("subnet %s configure new gateway node, nextHop %s", subnet.Name, nextHop)
1563
        if err := c.addPolicyRouteForCentralizedSubnet(subnet, newActivateNode, nil, strings.Split(nextHop, ",")); err != nil {
×
1564
                klog.Errorf("failed to add policy route for active-backup centralized subnet %s: %v", subnet.Name, err)
×
1565
                return err
×
1566
        }
×
1567
        subnet.Status.ActivateGateway = newActivateNode
×
1568
        if err := c.patchSubnetStatus(subnet, "ReconcileCentralizedGatewaySuccess", ""); err != nil {
×
1569
                klog.Error(err)
×
1570
                return err
×
1571
        }
×
1572

×
1573
        klog.Infof("delete old distributed policy route for subnet %s", subnet.Name)
×
1574
        if err := c.deletePolicyRouteByGatewayType(subnet, kubeovnv1.GWDistributedType, false); err != nil {
1575
                klog.Errorf("failed to delete policy route for overlay subnet %s, %v", subnet.Name, err)
×
1576
                return err
×
1577
        }
×
1578
        return nil
×
1579
}
×
1580

×
1581
func (c *Controller) reconcileEcmpCentralizedSubnetRouteInDefaultVpc(subnet *kubeovnv1.Subnet) error {
1582
        // centralized subnet, enable ecmp, add ecmp policy route
1583
        var (
×
1584
                gatewayNodes = strings.Split(subnet.Spec.GatewayNode, ",")
×
1585
                nodeV4IPs    = make([]string, 0, len(gatewayNodes))
×
1586
                nodeV6IPs    = make([]string, 0, len(gatewayNodes))
×
1587
                nameV4IPMap  = make(map[string]string, len(gatewayNodes))
×
1588
                nameV6IPMap  = make(map[string]string, len(gatewayNodes))
×
1589
        )
×
1590

×
1591
        for _, gw := range gatewayNodes {
×
1592
                // the format of gatewayNodeStr 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
×
1593
                if strings.Contains(gw, ":") {
×
1594
                        gw = strings.TrimSpace(strings.Split(gw, ":")[0])
×
1595
                } else {
×
1596
                        gw = strings.TrimSpace(gw)
×
1597
                }
×
1598

×
1599
                node, err := c.nodesLister.Get(gw)
×
1600
                if err != nil {
1601
                        klog.Errorf("failed to get gw node %s, %v", gw, err)
×
1602
                        continue
×
1603
                }
×
1604

×
1605
                if nodeReady(node) {
1606
                        nexthopNodeIP := strings.TrimSpace(node.Annotations[util.IPAddressAnnotation])
1607
                        if nexthopNodeIP == "" {
×
1608
                                klog.Errorf("gateway node %v has no ip annotation", node.Name)
×
1609
                                continue
×
1610
                        }
×
1611
                        nexthopV4, nexthopV6 := util.SplitStringIP(nexthopNodeIP)
×
1612
                        if nexthopV4 != "" {
1613
                                nameV4IPMap[node.Name] = nexthopV4
×
1614
                                nodeV4IPs = append(nodeV4IPs, nexthopV4)
×
1615
                        }
×
1616
                        if nexthopV6 != "" {
×
1617
                                nameV6IPMap[node.Name] = nexthopV6
×
1618
                                nodeV6IPs = append(nodeV6IPs, nexthopV6)
×
1619
                        }
×
1620
                } else {
×
1621
                        klog.Errorf("gateway node %v is not ready", gw)
×
1622
                }
×
1623
        }
×
1624

×
1625
        v4CIDR, v6CIDR := util.SplitStringIP(subnet.Spec.CIDRBlock)
1626
        if nodeV4IPs != nil && v4CIDR != "" {
1627
                klog.Infof("delete old distributed policy route for subnet %s", subnet.Name)
×
1628
                if err := c.deletePolicyRouteByGatewayType(subnet, kubeovnv1.GWDistributedType, false); err != nil {
×
1629
                        klog.Errorf("failed to delete policy route for overlay subnet %s, %v", subnet.Name, err)
×
1630
                        return err
×
1631
                }
×
1632
                klog.Infof("subnet %s configure ecmp policy route, nexthops %v", subnet.Name, nodeV4IPs)
×
1633
                if err := c.updatePolicyRouteForCentralizedSubnet(subnet.Name, v4CIDR, nodeV4IPs, nameV4IPMap); err != nil {
×
1634
                        klog.Errorf("failed to add v4 ecmp policy route for centralized subnet %s: %v", subnet.Name, err)
×
1635
                        return err
×
1636
                }
×
1637
        }
×
1638
        if nodeV6IPs != nil && v6CIDR != "" {
×
1639
                klog.Infof("delete old distributed policy route for subnet %s", subnet.Name)
1640
                if err := c.deletePolicyRouteByGatewayType(subnet, kubeovnv1.GWDistributedType, false); err != nil {
×
1641
                        klog.Errorf("failed to delete policy route for overlay subnet %s, %v", subnet.Name, err)
×
1642
                        return err
×
1643
                }
×
1644
                klog.Infof("subnet %s configure ecmp policy route, nexthops %v", subnet.Name, nodeV6IPs)
×
1645
                if err := c.updatePolicyRouteForCentralizedSubnet(subnet.Name, v6CIDR, nodeV6IPs, nameV6IPMap); err != nil {
×
1646
                        klog.Errorf("failed to add v6 ecmp policy route for centralized subnet %s: %v", subnet.Name, err)
×
1647
                        return err
×
1648
                }
×
1649
        }
×
1650
        return nil
×
1651
}
1652

×
1653
func (c *Controller) reconcileOvnDefaultVpcRoute(subnet *kubeovnv1.Subnet) error {
1654
        if subnet.Name == c.config.NodeSwitch {
1655
                if err := c.addCommonRoutesForSubnet(subnet); err != nil {
×
1656
                        klog.Error(err)
×
1657
                        return err
×
1658
                }
×
1659
                return nil
×
1660
        }
×
1661

×
1662
        if subnet.Spec.Vlan != "" && !subnet.Spec.LogicalGateway {
1663
                // physical switch provide gw for this underlay subnet
1664
                pods, err := c.podsLister.Pods(metav1.NamespaceAll).List(labels.Everything())
×
1665
                if err != nil {
×
1666
                        klog.Errorf("failed to list pods %v", err)
×
1667
                        return err
×
1668
                }
×
1669
                for _, pod := range pods {
×
1670
                        if pod.Annotations[util.LogicalSwitchAnnotation] == subnet.Name && pod.Annotations[util.IPAddressAnnotation] != "" {
×
1671
                                if err := c.deleteStaticRoute(
×
1672
                                        pod.Annotations[util.IPAddressAnnotation], c.config.ClusterRouter, subnet.Spec.RouteTable); err != nil {
×
1673
                                        klog.Errorf("failed to delete static route %v", err)
×
1674
                                        return err
×
1675
                                }
×
1676
                        }
×
1677
                }
×
1678

1679
                if !subnet.Spec.LogicalGateway && subnet.Name != c.config.ExternalGatewaySwitch && !subnet.Spec.U2OInterconnection {
1680
                        lspName := fmt.Sprintf("%s-%s", subnet.Name, c.config.ClusterRouter)
1681
                        klog.Infof("delete logical switch port %s", lspName)
×
1682
                        if err := c.OVNNbClient.DeleteLogicalSwitchPort(lspName); err != nil {
×
1683
                                klog.Errorf("failed to delete lsp %s-%s, %v", subnet.Name, c.config.ClusterRouter, err)
×
1684
                                return err
×
1685
                        }
×
1686
                        lrpName := fmt.Sprintf("%s-%s", c.config.ClusterRouter, subnet.Name)
×
1687
                        klog.Infof("delete logical router port %s", lrpName)
×
1688
                        if err := c.OVNNbClient.DeleteLogicalRouterPort(lrpName); err != nil {
×
1689
                                klog.Errorf("failed to delete lrp %s: %v", lrpName, err)
×
1690
                                return err
×
1691
                        }
×
1692
                }
×
1693

×
1694
                if subnet.Spec.U2OInterconnection && subnet.Status.U2OInterconnectionIP != "" {
1695
                        if err := c.addPolicyRouteForU2OInterconn(subnet); err != nil {
1696
                                klog.Errorf("failed to add policy route for underlay to overlay subnet interconnection %s %v", subnet.Name, err)
×
1697
                                return err
×
1698
                        }
×
1699
                } else {
×
1700
                        if err := c.deletePolicyRouteForU2OInterconn(subnet); err != nil {
×
1701
                                klog.Errorf("failed to delete policy route for underlay to overlay subnet interconnection %s, %v", subnet.Name, err)
×
1702
                                return err
×
1703
                        }
×
1704
                }
×
1705

×
1706
                if (!c.config.EnableLb || (subnet.Spec.EnableLb == nil || !*subnet.Spec.EnableLb)) &&
1707
                        subnet.Spec.U2OInterconnection && subnet.Status.U2OInterconnectionIP != "" {
1708
                        if err := c.addPolicyRouteForU2ONoLoadBalancer(subnet); err != nil {
×
1709
                                klog.Errorf("failed to add policy route for underlay to overlay subnet interconnection without enabling loadbalancer %s %v", subnet.Name, err)
×
1710
                                return err
×
1711
                        }
×
1712
                } else {
×
1713
                        if err := c.deletePolicyRouteForU2ONoLoadBalancer(subnet); err != nil {
×
1714
                                klog.Errorf("failed to delete policy route for underlay to overlay subnet interconnection without enabling loadbalancer %s, %v", subnet.Name, err)
×
1715
                                return err
×
1716
                        }
×
1717
                }
×
1718
        } else {
×
1719
                // It's difficult to update policy route when subnet cidr is changed, add check for cidr changed situation
1720
                if err := c.reconcilePolicyRouteForCidrChangedSubnet(subnet, true); err != nil {
×
1721
                        klog.Error(err)
×
1722
                        return err
×
1723
                }
×
1724

×
1725
                if err := c.addCommonRoutesForSubnet(subnet); err != nil {
×
1726
                        klog.Error(err)
1727
                        return err
×
1728
                }
×
1729

×
1730
                // distributed subnet, only add distributed policy route
×
1731
                if subnet.Spec.GatewayType == kubeovnv1.GWDistributedType {
1732
                        if err := c.reconcileDistributedSubnetRouteInDefaultVpc(subnet); err != nil {
1733
                                klog.Error(err)
×
1734
                                return err
×
1735
                        }
×
1736
                } else {
×
1737
                        // centralized subnet
×
1738
                        if subnet.Spec.GatewayNode == "" {
×
1739
                                subnet.Status.NotReady("NoReadyGateway", "")
×
1740
                                if err := c.patchSubnetStatus(subnet, "NoReadyGateway", ""); err != nil {
×
1741
                                        klog.Error(err)
×
1742
                                        return err
×
1743
                                }
×
1744
                                err := fmt.Errorf("subnet %s Spec.GatewayNode field must be specified for centralized gateway type", subnet.Name)
×
1745
                                klog.Error(err)
×
1746
                                return err
×
1747
                        }
×
1748

×
1749
                        gwNodeExists := c.checkGwNodeExists(subnet.Spec.GatewayNode)
1750
                        if !gwNodeExists {
1751
                                klog.Errorf("failed to init centralized gateway for subnet %s, no gateway node exists", subnet.Name)
×
1752
                                return errors.New("failed to add ecmp policy route, no gateway node exists")
×
1753
                        }
×
1754

×
1755
                        if err := c.reconcilePolicyRouteForCidrChangedSubnet(subnet, false); err != nil {
×
1756
                                klog.Error(err)
1757
                                return err
×
1758
                        }
×
1759

×
1760
                        if subnet.Spec.EnableEcmp {
×
1761
                                if err := c.reconcileEcmpCentralizedSubnetRouteInDefaultVpc(subnet); err != nil {
1762
                                        klog.Error(err)
×
1763
                                        return err
×
1764
                                }
×
1765
                        } else {
×
1766
                                if err := c.reconcileDefaultCentralizedSubnetRouteInDefaultVpc(subnet); err != nil {
×
1767
                                        klog.Error(err)
×
1768
                                        return err
×
1769
                                }
×
1770
                        }
×
1771
                }
×
1772
        }
1773
        return nil
1774
}
1775

×
1776
func (c *Controller) reconcileCustomVpcStaticRoute(subnet *kubeovnv1.Subnet) error {
1777
        // in custom vpc, subnet gw type is unmeaning
1778
        // 1. vpc out to public network through vpc nat gw pod, the static route is auto managed by admin user
×
1779
        // 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
×
1780
        // 3. vpc out to public network through ovn nat lrp, without bfd ecmp, the vpc spec static route is auto managed here
×
1781

×
1782
        vpc, err := c.vpcsLister.Get(subnet.Spec.Vpc)
×
1783
        if err != nil {
×
1784
                if k8serrors.IsNotFound(err) {
×
1785
                        return nil
×
1786
                }
×
1787
                klog.Errorf("failed to get vpc %s, %v", subnet.Spec.Vpc, err)
×
1788
                return err
×
1789
        }
×
1790

×
1791
        if vpc.Spec.EnableExternal && vpc.Spec.EnableBfd && subnet.Spec.EnableEcmp {
1792
                klog.Infof("add bfd and external static ecmp route for vpc %s, subnet %s", vpc.Name, subnet.Name)
1793
                // handle vpc static route
×
1794
                // use static ecmp route with bfd
×
1795
                // bfd ecmp static route depend on subnet cidr
×
1796
                if err := c.reconcileCustomVpcBfdStaticRoute(vpc.Name, subnet.Name); err != nil {
×
1797
                        klog.Errorf("failed to reconcile vpc %q bfd static route", vpc.Name)
×
1798
                        return err
×
1799
                }
×
1800
        }
×
1801

×
1802
        if subnet.Spec.Vlan != "" && !subnet.Spec.LogicalGateway && subnet.Spec.U2OInterconnection && subnet.Status.U2OInterconnectionIP != "" {
1803
                if err := c.addPolicyRouteForU2OInterconn(subnet); err != nil {
1804
                        klog.Errorf("failed to add policy route for underlay to overlay subnet interconnection %s %v", subnet.Name, err)
×
1805
                        return err
×
1806
                }
×
1807

×
1808
                if err := c.addStaticRouteForU2OInterconn(subnet); err != nil {
×
1809
                        klog.Errorf("failed to add static route for underlay to overlay subnet interconnection %s %v", subnet.Name, err)
1810
                        return err
×
1811
                }
×
1812
        }
×
1813

×
1814
        if err := c.addCustomVPCPolicyRoutesForSubnet(subnet); err != nil {
1815
                klog.Error(err)
1816
                return err
×
1817
        }
×
1818

×
1819
        return nil
×
1820
}
1821

×
1822
func (c *Controller) deleteStaticRoute(ip, router, routeTable string) error {
1823
        for _, ipStr := range strings.Split(ip, ",") {
1824
                if err := c.deleteStaticRouteFromVpc(
×
1825
                        router,
×
1826
                        routeTable,
×
1827
                        ipStr,
×
1828
                        "",
×
1829
                        kubeovnv1.PolicyDst,
×
1830
                ); err != nil {
×
1831
                        klog.Errorf("failed to delete static route %s, %v", ipStr, err)
×
1832
                        return err
×
1833
                }
×
1834
        }
×
1835

×
1836
        return nil
1837
}
1838

×
1839
func (c *Controller) reconcileVlan(subnet *kubeovnv1.Subnet) error {
1840
        if subnet.Spec.Vlan == "" {
1841
                return nil
×
1842
        }
×
1843
        klog.Infof("reconcile vlan %v", subnet.Spec.Vlan)
×
1844

×
1845
        vlan, err := c.vlansLister.Get(subnet.Spec.Vlan)
×
1846
        if err != nil {
×
1847
                klog.Errorf("failed to get vlan %s: %v", subnet.Spec.Vlan, err)
×
1848
                return err
×
1849
        }
×
NEW
1850
        if c.config.EnableCheckVlanConflict && vlan.Status.Conflict {
×
NEW
1851
                err = fmt.Errorf("subnet %s has invalid conflict vlan %s", subnet.Name, vlan.Name)
×
NEW
1852
                klog.Error(err)
×
NEW
1853
                return err
×
NEW
1854
        }
×
1855

×
1856
        localnetPort := ovs.GetLocalnetName(subnet.Name)
×
1857
        if err := c.OVNNbClient.CreateLocalnetLogicalSwitchPort(subnet.Name, localnetPort, vlan.Spec.Provider, subnet.Spec.CIDRBlock, vlan.Spec.ID); err != nil {
1858
                klog.Errorf("create localnet port for subnet %s: %v", subnet.Name, err)
×
1859
                return err
×
1860
        }
×
1861

×
1862
        if !slices.Contains(vlan.Status.Subnets, subnet.Name) {
×
1863
                newVlan := vlan.DeepCopy()
1864
                newVlan.Status.Subnets = append(newVlan.Status.Subnets, subnet.Name)
×
1865
                _, err = c.config.KubeOvnClient.KubeovnV1().Vlans().UpdateStatus(context.Background(), newVlan, metav1.UpdateOptions{})
×
1866
                if err != nil {
×
1867
                        klog.Errorf("failed to update status of vlan %s: %v", vlan.Name, err)
×
1868
                        return err
×
1869
                }
×
1870
        }
×
1871

×
1872
        return nil
1873
}
1874

×
1875
func (c *Controller) reconcileSubnetSpecialIPs(subnet *kubeovnv1.Subnet) (bool, bool, error) {
1876
        isU2OIPChanged := false
1877
        isMcastQuerierIPChanged := false
×
1878
        var err error
×
1879

×
1880
        // reconcile u2o IP
×
1881
        if subnet.Spec.Vlan != "" && !subnet.Spec.LogicalGateway {
×
1882
                u2oInterconnName := fmt.Sprintf(util.U2OInterconnName, subnet.Spec.Vpc, subnet.Name)
×
1883
                u2oInterconnLrpName := fmt.Sprintf("%s-%s", subnet.Spec.Vpc, subnet.Name)
×
1884
                var v4ip, v6ip string
×
1885
                if subnet.Spec.U2OInterconnection {
×
1886
                        v4ip, v6ip, _, err = c.acquireU2OIP(subnet, u2oInterconnName, u2oInterconnLrpName)
×
1887
                        if err != nil {
×
1888
                                return isU2OIPChanged, isMcastQuerierIPChanged, err
×
1889
                        }
×
1890

×
1891
                        if v4ip != "" || v6ip != "" {
×
1892
                                isU2OIPChanged = true
1893
                        }
×
1894
                } else if subnet.Status.U2OInterconnectionIP != "" {
×
1895
                        err = c.releaseU2OIP(subnet, u2oInterconnName)
×
1896
                        if err != nil {
×
1897
                                return isU2OIPChanged, isMcastQuerierIPChanged, err
×
1898
                        }
×
1899
                        isU2OIPChanged = true
×
1900
                }
×
1901

×
1902
                if isU2OIPChanged {
1903
                        klog.Infof("reconcile underlay subnet %s to overlay interconnection with U2OInterconnection %v U2OInterconnectionIP %s",
1904
                                subnet.Name, subnet.Spec.U2OInterconnection, subnet.Status.U2OInterconnectionIP)
×
1905
                }
×
1906
        }
×
1907

×
1908
        // reconcile mcast querier IP
1909
        if subnet.Spec.EnableMulticastSnoop {
1910
                isMcastQuerierIPChanged, err = c.acquireMcastQuerierIP(subnet)
1911
                if err != nil {
×
1912
                        return isU2OIPChanged, isMcastQuerierIPChanged, err
×
1913
                }
×
1914
        } else {
×
1915
                isMcastQuerierIPChanged, err = c.releaseMcastQuerierIP(subnet)
×
1916
                if err != nil {
×
1917
                        return isU2OIPChanged, isMcastQuerierIPChanged, err
×
1918
                }
×
1919
        }
×
1920

×
1921
        // caculate subnet status
1922
        if isU2OIPChanged || isMcastQuerierIPChanged {
1923
                if subnet.Spec.Protocol == kubeovnv1.ProtocolDual {
1924
                        if _, err := c.calcDualSubnetStatusIP(subnet); err != nil {
×
1925
                                klog.Error(err)
×
1926
                                return isU2OIPChanged, isMcastQuerierIPChanged, err
×
1927
                        }
×
1928
                } else {
×
1929
                        if _, err := c.calcSubnetStatusIP(subnet); err != nil {
×
1930
                                klog.Error(err)
×
1931
                                return isU2OIPChanged, isMcastQuerierIPChanged, err
×
1932
                        }
×
1933
                }
×
1934
        }
×
1935

1936
        return isU2OIPChanged, isMcastQuerierIPChanged, nil
1937
}
1938

×
1939
func (c *Controller) acquireU2OIP(subnet *kubeovnv1.Subnet, u2oInterconnName, u2oInterconnLrpName string) (string, string, string, error) {
1940
        var v4ip, v6ip, mac string
1941
        var err error
×
1942
        if subnet.Spec.U2OInterconnectionIP == "" && (subnet.Status.U2OInterconnectionIP == "" || subnet.Status.U2OInterconnectionMAC == "") {
×
1943
                v4ip, v6ip, mac, err = c.acquireIPAddress(subnet.Name, u2oInterconnName, u2oInterconnLrpName)
×
1944
                if err != nil {
×
1945
                        klog.Errorf("failed to acquire underlay to overlay interconnection ip address for subnet %s, %v", subnet.Name, err)
×
1946
                        return "", "", "", err
×
1947
                }
×
1948
        } else if subnet.Spec.U2OInterconnectionIP != "" && subnet.Status.U2OInterconnectionIP != subnet.Spec.U2OInterconnectionIP {
×
1949
                if subnet.Status.U2OInterconnectionIP != "" {
×
1950
                        klog.Infof("release underlay to overlay interconnection ip address %s for subnet %s", subnet.Status.U2OInterconnectionIP, subnet.Name)
×
1951
                        c.ipam.ReleaseAddressByPod(u2oInterconnName, subnet.Name)
×
1952
                }
×
1953
                v4ip, v6ip, mac, err = c.acquireStaticIPAddress(subnet.Name, u2oInterconnName, u2oInterconnLrpName, subnet.Spec.U2OInterconnectionIP)
×
1954
                if err != nil {
×
1955
                        klog.Errorf("failed to acquire static underlay to overlay interconnection ip address for subnet %s, %v", subnet.Name, err)
×
1956
                        return "", "", "", err
×
1957
                }
×
1958
        }
×
1959
        if v4ip != "" || v6ip != "" {
×
1960
                switch subnet.Spec.Protocol {
1961
                case kubeovnv1.ProtocolIPv4:
×
1962
                        subnet.Status.U2OInterconnectionIP = v4ip
×
1963
                case kubeovnv1.ProtocolIPv6:
×
1964
                        subnet.Status.U2OInterconnectionIP = v6ip
×
1965
                case kubeovnv1.ProtocolDual:
×
1966
                        subnet.Status.U2OInterconnectionIP = fmt.Sprintf("%s,%s", v4ip, v6ip)
×
1967
                }
×
1968
                err = c.createOrUpdateIPCR("", u2oInterconnName, subnet.Status.U2OInterconnectionIP, mac, subnet.Name, "default", "", "")
×
1969
                if err != nil {
1970
                        klog.Errorf("failed to create or update IPs of %s : %v", u2oInterconnLrpName, err)
×
1971
                        return "", "", "", err
×
1972
                }
×
1973
                subnet.Status.U2OInterconnectionMAC = mac
×
1974
        }
×
1975
        return v4ip, v6ip, mac, nil
×
1976
}
1977

×
1978
func (c *Controller) releaseU2OIP(subnet *kubeovnv1.Subnet, u2oInterconnName string) error {
1979
        klog.Infof("release underlay to overlay interconnection ip address %s for subnet %s", subnet.Status.U2OInterconnectionIP, subnet.Name)
1980
        c.ipam.ReleaseAddressByPod(u2oInterconnName, subnet.Name)
×
1981
        subnet.Status.U2OInterconnectionIP = ""
×
1982
        subnet.Status.U2OInterconnectionMAC = ""
×
1983
        subnet.Status.U2OInterconnectionVPC = ""
×
1984

×
1985
        err := c.config.KubeOvnClient.KubeovnV1().IPs().Delete(context.Background(), u2oInterconnName, metav1.DeleteOptions{})
×
1986
        if err != nil && !k8serrors.IsNotFound(err) {
×
1987
                klog.Errorf("failed to delete ip %s, %v", u2oInterconnName, err)
×
1988
                return err
×
1989
        }
×
1990

×
1991
        return nil
×
1992
}
1993

×
1994
func (c *Controller) acquireMcastQuerierIP(subnet *kubeovnv1.Subnet) (bool, error) {
1995
        isMcastQuerierChanged := false
1996
        mcastQuerierLspName := fmt.Sprintf(util.McastQuerierName, subnet.Name)
×
1997
        var v4ip, v6ip, mac string
×
1998
        var err error
×
1999

×
2000
        if subnet.Status.McastQuerierIP == "" || subnet.Status.McastQuerierMAC == "" {
×
2001
                v4ip, v6ip, mac, err = c.acquireIPAddress(subnet.Name, mcastQuerierLspName, mcastQuerierLspName)
×
2002
                if err != nil {
×
2003
                        klog.Errorf("failed to acquire mcast querier ip address for subnet %s, %v", subnet.Name, err)
×
2004
                        return isMcastQuerierChanged, err
×
2005
                }
×
2006
        }
×
2007

×
2008
        if v4ip != "" || v6ip != "" {
2009
                switch subnet.Spec.Protocol {
2010
                case kubeovnv1.ProtocolIPv4:
×
2011
                        subnet.Status.McastQuerierIP = v4ip
×
2012
                case kubeovnv1.ProtocolIPv6:
×
2013
                        subnet.Status.McastQuerierIP = v6ip
×
2014
                case kubeovnv1.ProtocolDual:
×
2015
                        subnet.Status.McastQuerierIP = fmt.Sprintf("%s,%s", v4ip, v6ip)
×
2016
                }
×
2017

×
2018
                err := c.createOrUpdateIPCR("", mcastQuerierLspName, subnet.Status.McastQuerierIP, mac, subnet.Name, "default", "", "")
2019
                if err != nil {
2020
                        klog.Errorf("failed to create or update IPs of %s : %v", mcastQuerierLspName, err)
×
2021
                        return isMcastQuerierChanged, err
×
2022
                }
×
2023

×
2024
                subnet.Status.McastQuerierMAC = mac
×
2025
                klog.Infof("reconcile subnet %s mcast querier IP %s mac %s",
2026
                        subnet.Name, subnet.Status.McastQuerierIP, subnet.Status.McastQuerierMAC)
×
2027
                isMcastQuerierChanged = true
×
2028
        }
×
2029

×
2030
        return isMcastQuerierChanged, nil
2031
}
2032

×
2033
func (c *Controller) releaseMcastQuerierIP(subnet *kubeovnv1.Subnet) (bool, error) {
2034
        isMcastQuerierChanged := false
2035
        if subnet.Status.McastQuerierIP != "" {
×
2036
                mcastQuerierLspName := fmt.Sprintf(util.McastQuerierName, subnet.Name)
×
2037
                klog.Infof("release mcast querier ip address %s for subnet %s", subnet.Status.McastQuerierIP, subnet.Name)
×
2038
                c.ipam.ReleaseAddressByPod(mcastQuerierLspName, subnet.Name)
×
2039
                subnet.Status.McastQuerierIP = ""
×
2040
                subnet.Status.McastQuerierMAC = ""
×
2041

×
2042
                if err := c.config.KubeOvnClient.KubeovnV1().IPs().Delete(context.Background(), mcastQuerierLspName, metav1.DeleteOptions{}); err != nil {
×
2043
                        if !k8serrors.IsNotFound(err) {
×
2044
                                klog.Errorf("failed to delete ip %s, %v", mcastQuerierLspName, err)
×
2045
                                return isMcastQuerierChanged, err
×
2046
                        }
×
2047
                }
×
2048
                isMcastQuerierChanged = true
×
2049
                klog.Infof("reconcile subnet %s mcast querier IP %s mac %s",
2050
                        subnet.Name, subnet.Status.McastQuerierIP, subnet.Status.McastQuerierMAC)
×
2051
        }
×
2052
        return isMcastQuerierChanged, nil
×
2053
}
2054

×
2055
func (c *Controller) calcDualSubnetStatusIP(subnet *kubeovnv1.Subnet) (*kubeovnv1.Subnet, error) {
2056
        if err := util.CheckCidrs(subnet.Spec.CIDRBlock); err != nil {
2057
                return nil, err
×
2058
        }
×
2059
        // Get the number of pods, not ips. For one pod with two ip(v4 & v6) in dual-stack, num of Items is 1
×
2060
        podUsedIPs, err := c.ipsLister.List(labels.SelectorFromSet(labels.Set{subnet.Name: ""}))
×
2061
        if err != nil {
2062
                klog.Error(err)
×
2063
                return nil, err
×
2064
        }
×
2065
        var lenIP, lenVip, lenIptablesEip, lenOvnEip int
×
2066
        lenIP = len(podUsedIPs)
×
2067
        usingIPNums := lenIP
×
2068

×
2069
        // TODO:// replace ExcludeIps with ip pool and gw to avoid later loop
×
2070
        noGWExcludeIPs := []string{}
×
2071
        v4gw, v6gw := util.SplitStringIP(subnet.Spec.Gateway)
×
2072
        for _, excludeIP := range subnet.Spec.ExcludeIps {
×
2073
                if v4gw == excludeIP || v6gw == excludeIP {
×
2074
                        // no need to compare gateway ip with pod ip
×
2075
                        continue
×
2076
                }
×
2077
                noGWExcludeIPs = append(noGWExcludeIPs, excludeIP)
×
2078
        }
2079
        if noGWExcludeIPs != nil {
×
2080
                for _, podUsedIP := range podUsedIPs {
2081
                        for _, excludeIP := range noGWExcludeIPs {
×
2082
                                if util.ContainsIPs(excludeIP, podUsedIP.Spec.V4IPAddress) || util.ContainsIPs(excludeIP, podUsedIP.Spec.V6IPAddress) {
×
2083
                                        // This ip cr is allocated from subnet.spec.excludeIPs, do not count it as usingIPNums
×
2084
                                        usingIPNums--
×
2085
                                        break
×
2086
                                }
×
2087
                        }
×
2088
                }
2089
        }
2090

2091
        // subnet.Spec.ExcludeIps contains both v4 and v6 addresses
2092
        v4ExcludeIPs, v6ExcludeIPs := util.SplitIpsByProtocol(subnet.Spec.ExcludeIps)
2093
        // gateway always in excludeIPs
2094
        cidrBlocks := strings.Split(subnet.Spec.CIDRBlock, ",")
×
2095
        v4toSubIPs := util.ExpandExcludeIPs(v4ExcludeIPs, cidrBlocks[0])
×
2096
        v6toSubIPs := util.ExpandExcludeIPs(v6ExcludeIPs, cidrBlocks[1])
×
2097
        _, v4CIDR, _ := net.ParseCIDR(cidrBlocks[0])
×
2098
        _, v6CIDR, _ := net.ParseCIDR(cidrBlocks[1])
×
2099
        v4availableIPs := util.AddressCount(v4CIDR) - util.CountIPNums(v4toSubIPs)
×
2100
        v6availableIPs := util.AddressCount(v6CIDR) - util.CountIPNums(v6toSubIPs)
×
2101

×
2102
        usingIPs := float64(usingIPNums)
×
2103

×
2104
        vips, err := c.virtualIpsLister.List(labels.SelectorFromSet(labels.Set{
×
2105
                util.SubnetNameLabel: subnet.Name,
×
2106
                util.IPReservedLabel: "",
×
2107
        }))
×
2108
        if err != nil {
×
2109
                klog.Error(err)
×
2110
                return nil, err
×
2111
        }
×
2112
        lenVip = len(vips)
×
2113
        usingIPs += float64(lenVip)
×
2114

×
2115
        if !isOvnSubnet(subnet) {
×
2116
                eips, err := c.iptablesEipsLister.List(
×
2117
                        labels.SelectorFromSet(labels.Set{util.SubnetNameLabel: subnet.Name}))
×
2118
                if err != nil {
×
2119
                        klog.Error(err)
×
2120
                        return nil, err
×
2121
                }
×
2122
                lenIptablesEip = len(eips)
×
2123
                usingIPs += float64(lenIptablesEip)
×
2124
        }
×
2125
        if subnet.Spec.Vlan != "" {
×
2126
                ovnEips, err := c.ovnEipsLister.List(labels.SelectorFromSet(labels.Set{
2127
                        util.SubnetNameLabel: subnet.Name,
×
2128
                }))
×
2129
                if err != nil {
×
2130
                        klog.Error(err)
×
2131
                        return nil, err
×
2132
                }
×
2133
                lenOvnEip = len(ovnEips)
×
2134
                usingIPs += float64(lenOvnEip)
×
2135
        }
×
2136

×
2137
        v4availableIPs -= usingIPs
2138
        if v4availableIPs < 0 {
2139
                v4availableIPs = 0
×
2140
        }
×
2141
        v6availableIPs -= usingIPs
×
2142
        if v6availableIPs < 0 {
×
2143
                v6availableIPs = 0
×
2144
        }
×
2145

×
2146
        v4UsingIPStr, v6UsingIPStr, v4AvailableIPStr, v6AvailableIPStr := c.ipam.GetSubnetIPRangeString(subnet.Name, subnet.Spec.ExcludeIps)
×
2147

2148
        if subnet.Status.V4AvailableIPs == v4availableIPs &&
×
2149
                subnet.Status.V6AvailableIPs == v6availableIPs &&
×
2150
                subnet.Status.V4UsingIPs == usingIPs &&
×
2151
                subnet.Status.V6UsingIPs == usingIPs &&
×
2152
                subnet.Status.V4UsingIPRange == v4UsingIPStr &&
×
2153
                subnet.Status.V6UsingIPRange == v6UsingIPStr &&
×
2154
                subnet.Status.V4AvailableIPRange == v4AvailableIPStr &&
×
2155
                subnet.Status.V6AvailableIPRange == v6AvailableIPStr {
×
2156
                return subnet, nil
×
2157
        }
×
2158

×
2159
        subnet.Status.V4AvailableIPs = v4availableIPs
×
2160
        subnet.Status.V6AvailableIPs = v6availableIPs
2161
        subnet.Status.V4UsingIPs = usingIPs
×
2162
        subnet.Status.V6UsingIPs = usingIPs
×
2163
        subnet.Status.V4UsingIPRange = v4UsingIPStr
×
2164
        subnet.Status.V6UsingIPRange = v6UsingIPStr
×
2165
        subnet.Status.V4AvailableIPRange = v4AvailableIPStr
×
2166
        subnet.Status.V6AvailableIPRange = v6AvailableIPStr
×
2167
        bytes, err := subnet.Status.Bytes()
×
2168
        if err != nil {
×
2169
                klog.Error(err)
×
2170
                return nil, err
×
2171
        }
×
2172
        newSubnet, err := c.config.KubeOvnClient.KubeovnV1().Subnets().Patch(context.Background(), subnet.Name, types.MergePatchType, bytes, metav1.PatchOptions{}, "status")
×
2173
        return newSubnet, err
×
2174
}
×
2175

×
2176
func (c *Controller) calcSubnetStatusIP(subnet *kubeovnv1.Subnet) (*kubeovnv1.Subnet, error) {
2177
        _, cidr, err := net.ParseCIDR(subnet.Spec.CIDRBlock)
2178
        if err != nil {
×
2179
                klog.Error(err)
×
2180
                return nil, err
×
2181
        }
×
2182
        var lenIP, lenVip, lenIptablesEip, lenOvnEip int
×
2183
        podUsedIPs, err := c.ipsLister.List(labels.SelectorFromSet(labels.Set{subnet.Name: ""}))
×
2184
        if err != nil {
×
2185
                klog.Error(err)
×
2186
                return nil, err
×
2187
        }
×
2188
        lenIP = len(podUsedIPs)
×
2189
        usingIPNums := lenIP
×
2190

×
2191
        // TODO:// replace ExcludeIps with ip pool and gw to avoid later loop
×
2192
        noGWExcludeIPs := []string{}
×
2193
        v4gw, v6gw := util.SplitStringIP(subnet.Spec.Gateway)
×
2194
        for _, excludeIP := range subnet.Spec.ExcludeIps {
×
2195
                if v4gw == excludeIP || v6gw == excludeIP {
×
2196
                        // no need to compare gateway ip with pod ip
×
2197
                        continue
×
2198
                }
×
2199
                noGWExcludeIPs = append(noGWExcludeIPs, excludeIP)
×
2200
        }
2201
        if noGWExcludeIPs != nil {
×
2202
                for _, podUsedIP := range podUsedIPs {
2203
                        for _, excludeIP := range noGWExcludeIPs {
×
2204
                                if util.ContainsIPs(excludeIP, podUsedIP.Spec.V4IPAddress) || util.ContainsIPs(excludeIP, podUsedIP.Spec.V6IPAddress) {
×
2205
                                        // This ip cr is allocated from subnet.spec.excludeIPs, do not count it as usingIPNums
×
2206
                                        usingIPNums--
×
2207
                                        break
×
2208
                                }
×
2209
                        }
×
2210
                }
2211
        }
2212

2213
        // gateway always in excludeIPs
2214
        toSubIPs := util.ExpandExcludeIPs(subnet.Spec.ExcludeIps, subnet.Spec.CIDRBlock)
2215
        availableIPs := util.AddressCount(cidr) - util.CountIPNums(toSubIPs)
2216
        usingIPs := float64(usingIPNums)
×
2217
        vips, err := c.virtualIpsLister.List(labels.SelectorFromSet(labels.Set{
×
2218
                util.SubnetNameLabel: subnet.Name,
×
2219
                util.IPReservedLabel: "",
×
2220
        }))
×
2221
        if err != nil {
×
2222
                klog.Error(err)
×
2223
                return nil, err
×
2224
        }
×
2225
        lenVip = len(vips)
×
2226
        usingIPs += float64(lenVip)
×
2227
        if !isOvnSubnet(subnet) {
×
2228
                eips, err := c.iptablesEipsLister.List(
×
2229
                        labels.SelectorFromSet(labels.Set{util.SubnetNameLabel: subnet.Name}))
×
2230
                if err != nil {
×
2231
                        klog.Error(err)
×
2232
                        return nil, err
×
2233
                }
×
2234
                lenIptablesEip = len(eips)
×
2235
                usingIPs += float64(lenIptablesEip)
×
2236
        }
×
2237
        if subnet.Spec.Vlan != "" {
×
2238
                ovnEips, err := c.ovnEipsLister.List(labels.SelectorFromSet(labels.Set{
2239
                        util.SubnetNameLabel: subnet.Name,
×
2240
                }))
×
2241
                if err != nil {
×
2242
                        klog.Error(err)
×
2243
                        return nil, err
×
2244
                }
×
2245
                lenOvnEip = len(ovnEips)
×
2246
                usingIPs += float64(lenOvnEip)
×
2247
        }
×
2248

×
2249
        availableIPs -= usingIPs
2250
        if availableIPs < 0 {
2251
                availableIPs = 0
×
2252
        }
×
2253

×
2254
        v4UsingIPStr, v6UsingIPStr, v4AvailableIPStr, v6AvailableIPStr := c.ipam.GetSubnetIPRangeString(subnet.Name, subnet.Spec.ExcludeIps)
×
2255
        cachedFloatFields := [4]float64{
2256
                subnet.Status.V4AvailableIPs,
×
2257
                subnet.Status.V4UsingIPs,
×
2258
                subnet.Status.V6AvailableIPs,
×
2259
                subnet.Status.V6UsingIPs,
×
2260
        }
×
2261
        cachedStringFields := [4]string{
×
2262
                subnet.Status.V4UsingIPRange,
×
2263
                subnet.Status.V4AvailableIPRange,
×
2264
                subnet.Status.V6UsingIPRange,
×
2265
                subnet.Status.V6AvailableIPRange,
×
2266
        }
×
2267

×
2268
        if subnet.Spec.Protocol == kubeovnv1.ProtocolIPv4 {
×
2269
                subnet.Status.V4AvailableIPs = availableIPs
×
2270
                subnet.Status.V4UsingIPs = usingIPs
×
2271
                subnet.Status.V4UsingIPRange = v4UsingIPStr
×
2272
                subnet.Status.V4AvailableIPRange = v4AvailableIPStr
×
2273
                subnet.Status.V6AvailableIPs = 0
×
2274
                subnet.Status.V6UsingIPs = 0
×
2275
        } else {
×
2276
                subnet.Status.V6AvailableIPs = availableIPs
×
2277
                subnet.Status.V6UsingIPs = usingIPs
×
2278
                subnet.Status.V6UsingIPRange = v6UsingIPStr
×
2279
                subnet.Status.V6AvailableIPRange = v6AvailableIPStr
×
2280
                subnet.Status.V4AvailableIPs = 0
×
2281
                subnet.Status.V4UsingIPs = 0
×
2282
        }
×
2283
        if cachedFloatFields == [4]float64{
×
2284
                subnet.Status.V4AvailableIPs,
×
2285
                subnet.Status.V4UsingIPs,
×
2286
                subnet.Status.V6AvailableIPs,
×
2287
                subnet.Status.V6UsingIPs,
×
2288
        } && cachedStringFields == [4]string{
×
2289
                subnet.Status.V4UsingIPRange,
×
2290
                subnet.Status.V4AvailableIPRange,
×
2291
                subnet.Status.V6UsingIPRange,
×
2292
                subnet.Status.V6AvailableIPRange,
×
2293
        } {
×
2294
                return subnet, nil
×
2295
        }
×
2296

×
2297
        bytes, err := subnet.Status.Bytes()
×
2298
        if err != nil {
2299
                klog.Error(err)
×
2300
                return nil, err
×
2301
        }
×
2302
        newSubnet, err := c.config.KubeOvnClient.KubeovnV1().Subnets().Patch(context.Background(), subnet.Name, types.MergePatchType, bytes, metav1.PatchOptions{}, "status")
×
2303
        return newSubnet, err
×
2304
}
×
2305

×
2306
func (c *Controller) checkSubnetUsingIPs(subnet *kubeovnv1.Subnet) error {
2307
        if subnet.Status.V4UsingIPs != 0 && subnet.Status.V4UsingIPRange == "" {
2308
                err := fmt.Errorf("subnet %s has %.0f v4 ip in use, while the v4 using ip range is empty", subnet.Name, subnet.Status.V4UsingIPs)
×
2309
                klog.Error(err)
×
2310
                return err
×
2311
        }
×
2312
        if subnet.Status.V6UsingIPs != 0 && subnet.Status.V6UsingIPRange == "" {
×
2313
                err := fmt.Errorf("subnet %s has %.0f v6 ip in use, while the v6 using ip range is empty", subnet.Name, subnet.Status.V6UsingIPs)
×
2314
                klog.Error(err)
×
2315
                return err
×
2316
        }
×
2317
        return nil
×
2318
}
×
2319

×
2320
func isOvnSubnet(subnet *kubeovnv1.Subnet) bool {
2321
        return util.IsOvnProvider(subnet.Spec.Provider)
2322
}
1✔
2323

1✔
2324
func checkAndFormatsExcludeIPs(subnet *kubeovnv1.Subnet) bool {
1✔
2325
        var excludeIPs []string
2326
        mapIPs := make(map[string]*ipam.IPRange, len(subnet.Spec.ExcludeIps))
1✔
2327
        for _, excludeIP := range subnet.Spec.ExcludeIps {
1✔
2328
                if _, ok := mapIPs[excludeIP]; !ok {
1✔
2329
                        ips := strings.Split(excludeIP, "..")
2✔
2330
                        start, _ := ipam.NewIP(ips[0])
2✔
2331
                        end := start
1✔
2332
                        if len(ips) != 1 {
1✔
2333
                                end, _ = ipam.NewIP(ips[1])
1✔
2334
                        }
1✔
2335
                        mapIPs[excludeIP] = ipam.NewIPRange(start, end)
×
2336
                }
×
2337
        }
1✔
2338
        newMap := filterRepeatIPRange(mapIPs)
2339
        for _, v := range newMap {
2340
                if v.Start().Equal(v.End()) {
1✔
2341
                        excludeIPs = append(excludeIPs, v.Start().String())
2✔
2342
                } else {
2✔
2343
                        excludeIPs = append(excludeIPs, v.Start().String()+".."+v.End().String())
1✔
2344
                }
1✔
2345
        }
×
2346
        sort.Strings(excludeIPs)
×
2347
        if !slices.Equal(subnet.Spec.ExcludeIps, excludeIPs) {
2348
                klog.V(3).Infof("excludeips before format is %v, after format is %v", subnet.Spec.ExcludeIps, excludeIPs)
1✔
2349
                subnet.Spec.ExcludeIps = excludeIPs
1✔
2350
                return true
×
2351
        }
×
2352
        return false
×
2353
}
×
2354

1✔
2355
func filterRepeatIPRange(mapIPs map[string]*ipam.IPRange) map[string]*ipam.IPRange {
2356
        for ka, a := range mapIPs {
2357
                for kb, b := range mapIPs {
1✔
2358
                        if ka == kb && a == b {
2✔
2359
                                continue
2✔
2360
                        }
2✔
2361

1✔
2362
                        if b.End().LessThan(a.Start()) || b.Start().GreaterThan(a.End()) {
2363
                                continue
2364
                        }
2✔
2365

1✔
2366
                        if (a.Start().Equal(b.Start()) || a.Start().GreaterThan(b.Start())) &&
2367
                                (a.End().Equal(b.End()) || a.End().LessThan(b.End())) {
2368
                                delete(mapIPs, ka)
×
2369
                                continue
×
2370
                        }
×
2371

×
2372
                        if (a.Start().Equal(b.Start()) || a.Start().GreaterThan(b.Start())) &&
2373
                                a.End().GreaterThan(b.End()) {
2374
                                delete(mapIPs, ka)
×
2375
                                mapIPs[kb] = ipam.NewIPRange(b.Start(), a.End())
×
2376
                                continue
×
2377
                        }
×
2378

×
2379
                        if (a.End().Equal(b.End()) || a.End().LessThan(b.End())) &&
2380
                                a.Start().LessThan(b.Start()) {
2381
                                delete(mapIPs, ka)
×
2382
                                mapIPs[kb] = ipam.NewIPRange(a.Start(), b.End())
×
2383
                                continue
×
2384
                        }
×
2385

×
2386
                        // a contains b
2387
                        mapIPs[kb] = a
2388
                        delete(mapIPs, ka)
2389
                }
×
2390
        }
×
2391
        return mapIPs
2392
}
2393

1✔
2394
func (c *Controller) checkGwNodeExists(gatewayNode string) bool {
2395
        found := false
2396
        for _, gwName := range strings.Split(gatewayNode, ",") {
×
2397
                // 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
×
2398
                if strings.Contains(gwName, ":") {
×
2399
                        gwName = strings.TrimSpace(strings.Split(gwName, ":")[0])
×
2400
                } else {
×
2401
                        gwName = strings.TrimSpace(gwName)
×
2402
                }
×
2403

×
2404
                gwNode, err := c.nodesLister.Get(gwName)
×
2405
                if err != nil {
2406
                        if k8serrors.IsNotFound(err) {
×
2407
                                klog.Errorf("gw node %s does not exist, %v", gwName, err)
×
2408
                                continue
×
2409
                        }
×
2410
                }
×
2411
                if gwNode != nil {
2412
                        found = true
2413
                        break
×
2414
                }
×
2415
        }
×
2416
        return found
2417
}
2418

×
2419
func (c *Controller) addCommonRoutesForSubnet(subnet *kubeovnv1.Subnet) error {
2420
        for _, cidr := range strings.Split(subnet.Spec.CIDRBlock, ",") {
2421
                if cidr == "" {
×
2422
                        continue
×
2423
                }
×
2424

×
2425
                var gateway string
2426
                protocol := util.CheckProtocol(cidr)
2427
                for _, gw := range strings.Split(subnet.Spec.Gateway, ",") {
×
2428
                        if util.CheckProtocol(gw) == protocol {
×
2429
                                gateway = gw
×
2430
                                break
×
2431
                        }
×
2432
                }
×
2433
                if gateway == "" {
2434
                        return fmt.Errorf("failed to get gateway of CIDR %s", cidr)
2435
                }
×
2436

×
2437
                // policy route
×
2438
                af := 4
2439
                if protocol == kubeovnv1.ProtocolIPv6 {
2440
                        af = 6
×
2441
                }
×
2442

×
2443
                var (
×
2444
                        match       = fmt.Sprintf("ip%d.dst == %s", af, cidr)
2445
                        action      = kubeovnv1.PolicyRouteActionAllow
×
2446
                        externalIDs = map[string]string{"vendor": util.CniTypeName, "subnet": subnet.Name}
×
2447
                )
×
2448
                klog.Infof("add common policy route for router: %s, match %s, action %s, externalID %v", subnet.Spec.Vpc, match, action, externalIDs)
×
2449
                if err := c.addPolicyRouteToVpc(
×
2450
                        subnet.Spec.Vpc,
×
2451
                        &kubeovnv1.PolicyRoute{
×
2452
                                Priority: util.SubnetRouterPolicyPriority,
×
2453
                                Match:    match,
×
2454
                                Action:   action,
×
2455
                        },
×
2456
                        externalIDs,
×
2457
                ); err != nil {
×
2458
                        klog.Errorf("failed to add logical router policy for CIDR %s of subnet %s: %v", cidr, subnet.Name, err)
×
2459
                        return err
×
2460
                }
×
2461
        }
×
2462
        return nil
×
2463
}
2464

×
2465
func getOverlaySubnetsPortGroupName(subnetName, nodeName string) string {
2466
        return strings.ReplaceAll(fmt.Sprintf("%s.%s", subnetName, nodeName), "-", ".")
2467
}
×
2468

×
2469
func (c *Controller) createPortGroupForDistributedSubnet(node *v1.Node, subnet *kubeovnv1.Subnet) error {
×
2470
        if subnet.Spec.Vlan != "" && !subnet.Spec.LogicalGateway {
2471
                return nil
×
2472
        }
×
2473
        if subnet.Spec.Vpc != c.config.ClusterRouter || subnet.Name == c.config.NodeSwitch {
×
2474
                return nil
×
2475
        }
×
2476

×
2477
        pgName := getOverlaySubnetsPortGroupName(subnet.Name, node.Name)
×
2478
        if err := c.OVNNbClient.CreatePortGroup(pgName, map[string]string{networkPolicyKey: subnet.Name + "/" + node.Name}); err != nil {
2479
                klog.Errorf("create port group for subnet %s and node %s: %v", subnet.Name, node.Name, err)
×
2480
                return err
×
2481
        }
×
2482

×
2483
        return nil
×
2484
}
2485

×
2486
func (c *Controller) updatePolicyRouteForCentralizedSubnet(subnetName, cidr string, nextHops []string, nameIPMap map[string]string) error {
2487
        ipSuffix := "ip4"
2488
        if util.CheckProtocol(cidr) == kubeovnv1.ProtocolIPv6 {
×
2489
                ipSuffix = "ip6"
×
2490
        }
×
2491

×
2492
        var (
×
2493
                match  = fmt.Sprintf("%s.src == %s", ipSuffix, cidr)
2494
                action = kubeovnv1.PolicyRouteActionReroute
×
2495
                // there's no way to update policy route when gatewayNode changed for subnet, so delete and readd policy route
×
2496
                // The delete operation is processed in AddPolicyRoute if the policy route is inconsistent, so no need delete here
×
2497
                externalIDs = map[string]string{
×
2498
                        "vendor": util.CniTypeName,
×
2499
                        "subnet": subnetName,
×
2500
                }
×
2501
        )
×
2502
        // It's difficult to delete policy route when delete node,
×
2503
        // add map nodeName:nodeIP to external_ids to help process when delete node
×
2504
        for node, ip := range nameIPMap {
×
2505
                externalIDs[node] = ip
×
2506
        }
×
2507
        klog.Infof("add policy route for router: %s, match %s, action %s, nexthops %v, externalID %s", c.config.ClusterRouter, match, action, nextHops, externalIDs)
×
2508
        if err := c.addPolicyRouteToVpc(
×
2509
                c.config.ClusterRouter,
×
2510
                &kubeovnv1.PolicyRoute{
×
2511
                        Priority:  util.GatewayRouterPolicyPriority,
×
2512
                        Match:     match,
×
2513
                        Action:    action,
×
2514
                        NextHopIP: strings.Join(nextHops, ","),
×
2515
                },
×
2516
                externalIDs,
×
2517
        ); err != nil {
×
2518
                klog.Errorf("failed to add policy route for centralized subnet %s: %v", subnetName, err)
×
2519
                return err
×
2520
        }
×
2521
        return nil
×
2522
}
2523

2524
func (c *Controller) addPolicyRouteForCentralizedSubnet(subnet *kubeovnv1.Subnet, nodeName string, ipNameMap map[string]string, nodeIPs []string) error {
×
2525
        for _, nodeIP := range nodeIPs {
×
2526
                // node v4ip v6ip
×
2527
                for _, cidrBlock := range strings.Split(subnet.Spec.CIDRBlock, ",") {
×
2528
                        if util.CheckProtocol(cidrBlock) != util.CheckProtocol(nodeIP) {
×
2529
                                continue
×
2530
                        }
2531
                        // Check for repeat policy route is processed in AddPolicyRoute
2532

2533
                        var nextHops []string
×
2534
                        nameIPMap := map[string]string{}
×
2535
                        nextHops = append(nextHops, nodeIP)
×
2536
                        tmpName := nodeName
×
2537
                        if nodeName == "" {
×
2538
                                tmpName = ipNameMap[nodeIP]
×
2539
                        }
×
2540
                        nameIPMap[tmpName] = nodeIP
×
2541
                        if err := c.updatePolicyRouteForCentralizedSubnet(subnet.Name, cidrBlock, nextHops, nameIPMap); err != nil {
×
2542
                                klog.Error(err)
×
2543
                                return err
×
2544
                        }
×
2545
                }
2546
        }
2547
        return nil
×
2548
}
2549

2550
func (c *Controller) deletePolicyRouteForCentralizedSubnet(subnet *kubeovnv1.Subnet) error {
×
2551
        for _, cidr := range strings.Split(subnet.Spec.CIDRBlock, ",") {
×
2552
                ipSuffix := "ip4"
×
2553
                if util.CheckProtocol(cidr) == kubeovnv1.ProtocolIPv6 {
×
2554
                        ipSuffix = "ip6"
×
2555
                }
×
2556
                match := fmt.Sprintf("%s.src == %s", ipSuffix, cidr)
×
2557
                klog.Infof("delete policy route for router: %s, priority: %d, match %s", c.config.ClusterRouter, util.GatewayRouterPolicyPriority, match)
×
2558
                if err := c.deletePolicyRouteFromVpc(c.config.ClusterRouter, util.GatewayRouterPolicyPriority, match); err != nil {
×
2559
                        klog.Errorf("failed to delete policy route for centralized subnet %s: %v", subnet.Name, err)
×
2560
                        return err
×
2561
                }
×
2562
        }
2563
        return nil
×
2564
}
2565

2566
func (c *Controller) addPolicyRouteForDistributedSubnet(subnet *kubeovnv1.Subnet, nodeName, nodeIPv4, nodeIPv6 string) error {
×
2567
        if subnet.Spec.Vlan != "" && !subnet.Spec.LogicalGateway {
×
2568
                return nil
×
2569
        }
×
2570
        if subnet.Spec.Vpc != c.config.ClusterRouter || subnet.Name == c.config.NodeSwitch {
×
2571
                return nil
×
2572
        }
×
2573

2574
        pgName := getOverlaySubnetsPortGroupName(subnet.Name, nodeName)
×
2575
        for _, cidrBlock := range strings.Split(subnet.Spec.CIDRBlock, ",") {
×
2576
                ipSuffix, nodeIP := "ip4", nodeIPv4
×
2577
                if util.CheckProtocol(cidrBlock) == kubeovnv1.ProtocolIPv6 {
×
2578
                        ipSuffix, nodeIP = "ip6", nodeIPv6
×
2579
                }
×
2580
                if nodeIP == "" {
×
2581
                        continue
×
2582
                }
2583

2584
                var (
×
2585
                        pgAs        = fmt.Sprintf("%s_%s", pgName, ipSuffix)
×
2586
                        match       = fmt.Sprintf("%s.src == $%s", ipSuffix, pgAs)
×
2587
                        action      = kubeovnv1.PolicyRouteActionReroute
×
2588
                        externalIDs = map[string]string{
×
2589
                                "vendor": util.CniTypeName,
×
2590
                                "subnet": subnet.Name,
×
2591
                                "node":   nodeName,
×
2592
                        }
×
2593
                )
×
2594

×
2595
                klog.Infof("add policy route for router: %s, match %s, action %s, externalID %v", c.config.ClusterRouter, match, action, externalIDs)
×
2596
                if err := c.addPolicyRouteToVpc(
×
2597
                        c.config.ClusterRouter,
×
2598
                        &kubeovnv1.PolicyRoute{
×
2599
                                Priority:  util.GatewayRouterPolicyPriority,
×
2600
                                Match:     match,
×
2601
                                Action:    action,
×
2602
                                NextHopIP: nodeIP,
×
2603
                        },
×
2604
                        externalIDs,
×
2605
                ); err != nil {
×
2606
                        klog.Errorf("failed to add logical router policy for port-group address-set %s: %v", pgAs, err)
×
2607
                        return err
×
2608
                }
×
2609
        }
2610
        return nil
×
2611
}
2612

2613
func (c *Controller) deletePolicyRouteForDistributedSubnet(subnet *kubeovnv1.Subnet, nodeName string) error {
×
2614
        pgName := getOverlaySubnetsPortGroupName(subnet.Name, nodeName)
×
2615
        for _, cidrBlock := range strings.Split(subnet.Spec.CIDRBlock, ",") {
×
2616
                ipSuffix := "ip4"
×
2617
                if util.CheckProtocol(cidrBlock) == kubeovnv1.ProtocolIPv6 {
×
2618
                        ipSuffix = "ip6"
×
2619
                }
×
2620
                pgAs := fmt.Sprintf("%s_%s", pgName, ipSuffix)
×
2621
                match := fmt.Sprintf("%s.src == $%s", ipSuffix, pgAs)
×
2622
                klog.Infof("delete policy route for router: %s, priority: %d, match: %q", c.config.ClusterRouter, util.GatewayRouterPolicyPriority, match)
×
2623
                if err := c.deletePolicyRouteFromVpc(c.config.ClusterRouter, util.GatewayRouterPolicyPriority, match); err != nil {
×
2624
                        klog.Errorf("failed to delete policy route for subnet %s: %v", subnet.Name, err)
×
2625
                        return err
×
2626
                }
×
2627
        }
2628
        return nil
×
2629
}
2630

2631
func (c *Controller) deletePolicyRouteByGatewayType(subnet *kubeovnv1.Subnet, gatewayType string, isDelete bool) error {
×
2632
        if (subnet.Spec.Vlan != "" && !subnet.Spec.LogicalGateway) || subnet.Spec.Vpc != c.config.ClusterRouter {
×
2633
                return nil
×
2634
        }
×
2635

2636
        for _, cidr := range strings.Split(subnet.Spec.CIDRBlock, ",") {
×
2637
                if cidr == "" || !isDelete {
×
2638
                        continue
×
2639
                }
2640

2641
                af := 4
×
2642
                if util.CheckProtocol(cidr) == kubeovnv1.ProtocolIPv6 {
×
2643
                        af = 6
×
2644
                }
×
2645
                match := fmt.Sprintf("ip%d.dst == %s", af, cidr)
×
2646
                klog.Infof("delete policy route for router: %s, priority: %d, match %s", c.config.ClusterRouter, util.SubnetRouterPolicyPriority, match)
×
2647
                if err := c.deletePolicyRouteFromVpc(c.config.ClusterRouter, util.SubnetRouterPolicyPriority, match); err != nil {
×
2648
                        klog.Errorf("failed to delete logical router policy for CIDR %s of subnet %s: %v", cidr, subnet.Name, err)
×
2649
                        return err
×
2650
                }
×
2651
        }
2652
        if subnet.Name == c.config.NodeSwitch {
×
2653
                return nil
×
2654
        }
×
2655

2656
        if gatewayType == kubeovnv1.GWDistributedType {
×
2657
                nodes, err := c.nodesLister.List(labels.Everything())
×
2658
                if err != nil {
×
2659
                        klog.Errorf("list nodes: %v", err)
×
2660
                        return err
×
2661
                }
×
2662
                for _, node := range nodes {
×
2663
                        pgName := getOverlaySubnetsPortGroupName(subnet.Name, node.Name)
×
2664
                        if err = c.OVNNbClient.DeletePortGroup(pgName); err != nil {
×
2665
                                klog.Errorf("delete port group for subnet %s and node %s: %v", subnet.Name, node.Name, err)
×
2666
                                return err
×
2667
                        }
×
2668

2669
                        if err = c.deletePolicyRouteForDistributedSubnet(subnet, node.Name); err != nil {
×
2670
                                klog.Errorf("delete policy route for subnet %s and node %s: %v", subnet.Name, node.Name, err)
×
2671
                                return err
×
2672
                        }
×
2673
                }
2674
        }
2675

2676
        if gatewayType == kubeovnv1.GWCentralizedType {
×
2677
                klog.Infof("delete policy route for centralized subnet %s", subnet.Name)
×
2678
                if err := c.deletePolicyRouteForCentralizedSubnet(subnet); err != nil {
×
2679
                        klog.Errorf("delete policy route for subnet %s: %v", subnet.Name, err)
×
2680
                        return err
×
2681
                }
×
2682
        }
2683

2684
        return nil
×
2685
}
2686

2687
func (c *Controller) addPolicyRouteForU2OInterconn(subnet *kubeovnv1.Subnet) error {
×
2688
        var v4Gw, v6Gw string
×
2689
        for _, gw := range strings.Split(subnet.Spec.Gateway, ",") {
×
2690
                switch util.CheckProtocol(gw) {
×
2691
                case kubeovnv1.ProtocolIPv4:
×
2692
                        v4Gw = gw
×
2693
                case kubeovnv1.ProtocolIPv6:
×
2694
                        v6Gw = gw
×
2695
                }
2696
        }
2697

2698
        externalIDs := map[string]string{
×
2699
                "vendor":           util.CniTypeName,
×
2700
                "subnet":           subnet.Name,
×
2701
                "isU2ORoutePolicy": "true",
×
2702
        }
×
2703

×
2704
        nodes, err := c.nodesLister.List(labels.Everything())
×
2705
        if err != nil {
×
2706
                klog.Errorf("failed to list nodes: %v", err)
×
2707
                return err
×
2708
        }
×
2709

2710
        var nodesIPv4, nodesIPv6 []string
×
2711
        for _, node := range nodes {
×
2712
                nodeIPv4, nodeIPv6 := util.GetNodeInternalIP(*node)
×
2713

×
2714
                if nodeIPv4 != "" {
×
2715
                        nodesIPv4 = append(nodesIPv4, nodeIPv4)
×
2716
                }
×
2717
                if nodeIPv6 != "" {
×
2718
                        nodesIPv6 = append(nodesIPv6, nodeIPv6)
×
2719
                }
×
2720
        }
2721

2722
        u2oExcludeIP4Ag := strings.ReplaceAll(fmt.Sprintf(util.U2OExcludeIPAg, subnet.Name, "ip4"), "-", ".")
×
2723
        u2oExcludeIP6Ag := strings.ReplaceAll(fmt.Sprintf(util.U2OExcludeIPAg, subnet.Name, "ip6"), "-", ".")
×
2724

×
2725
        if err := c.OVNNbClient.CreateAddressSet(u2oExcludeIP4Ag, externalIDs); err != nil {
×
2726
                klog.Errorf("create address set %s: %v", u2oExcludeIP4Ag, err)
×
2727
                return err
×
2728
        }
×
2729

2730
        if err := c.OVNNbClient.CreateAddressSet(u2oExcludeIP6Ag, externalIDs); err != nil {
×
2731
                klog.Errorf("create address set %s: %v", u2oExcludeIP6Ag, err)
×
2732
                return err
×
2733
        }
×
2734

2735
        if len(nodesIPv4) > 0 {
×
2736
                if err := c.OVNNbClient.AddressSetUpdateAddress(u2oExcludeIP4Ag, nodesIPv4...); err != nil {
×
2737
                        klog.Errorf("set v4 address set %s with address %v: %v", u2oExcludeIP4Ag, nodesIPv4, err)
×
2738
                        return err
×
2739
                }
×
2740
        }
2741

2742
        if len(nodesIPv6) > 0 {
×
2743
                if err := c.OVNNbClient.AddressSetUpdateAddress(u2oExcludeIP6Ag, nodesIPv6...); err != nil {
×
2744
                        klog.Errorf("set v6 address set %s with address %v: %v", u2oExcludeIP6Ag, nodesIPv6, err)
×
2745
                        return err
×
2746
                }
×
2747
        }
2748

2749
        for _, cidrBlock := range strings.Split(subnet.Spec.CIDRBlock, ",") {
×
2750
                ipSuffix := "ip4"
×
2751
                nextHop := v4Gw
×
2752
                U2OexcludeIPAs := u2oExcludeIP4Ag
×
2753
                if util.CheckProtocol(cidrBlock) == kubeovnv1.ProtocolIPv6 {
×
2754
                        ipSuffix = "ip6"
×
2755
                        nextHop = v6Gw
×
2756
                        U2OexcludeIPAs = u2oExcludeIP6Ag
×
2757
                }
×
2758

2759
                match1 := fmt.Sprintf("%s.dst == %s", ipSuffix, cidrBlock)
×
2760
                match2 := fmt.Sprintf("%s.dst == $%s && %s.src == %s", ipSuffix, U2OexcludeIPAs, ipSuffix, cidrBlock)
×
2761
                match3 := fmt.Sprintf("%s.src == %s", ipSuffix, cidrBlock)
×
2762

×
2763
                /*
×
2764
                        policy1:
×
2765
                        priority 29400 match: "ip4.dst == underlay subnet cidr"                         action: allow
×
2766

×
2767
                        policy2:
×
2768
                        priority 31000 match: "ip4.dst == node ips && ip4.src == underlay subnet cidr"  action: reroute physical gw
×
2769

×
2770
                        policy3:
×
2771
                        priority 29000 match: "ip4.src == underlay subnet cidr"                         action: reroute physical gw
×
2772

×
2773
                        comment:
×
2774
                        policy1 and policy2 allow overlay pod access underlay but when overlay pod access node ip, it should go join subnet,
×
2775
                        policy3: underlay pod first access u2o interconnection lrp and then reroute to physical gw
×
2776
                */
×
2777
                action := kubeovnv1.PolicyRouteActionAllow
×
2778
                if subnet.Spec.Vpc == c.config.ClusterRouter {
×
2779
                        klog.Infof("add u2o interconnection policy for router: %s, match %s, action %s", subnet.Spec.Vpc, match1, action)
×
2780
                        if err := c.addPolicyRouteToVpc(
×
2781
                                subnet.Spec.Vpc,
×
2782
                                &kubeovnv1.PolicyRoute{
×
2783
                                        Priority: util.U2OSubnetPolicyPriority,
×
2784
                                        Match:    match1,
×
2785
                                        Action:   action,
×
2786
                                },
×
2787
                                externalIDs,
×
2788
                        ); err != nil {
×
2789
                                klog.Errorf("failed to add u2o interconnection policy1 for subnet %s %v", subnet.Name, err)
×
2790
                                return err
×
2791
                        }
×
2792

2793
                        action = kubeovnv1.PolicyRouteActionReroute
×
2794
                        klog.Infof("add u2o interconnection policy for router: %s, match %s, action %s", subnet.Spec.Vpc, match2, action)
×
2795
                        if err := c.addPolicyRouteToVpc(
×
2796
                                subnet.Spec.Vpc,
×
2797
                                &kubeovnv1.PolicyRoute{
×
2798
                                        Priority:  util.SubnetRouterPolicyPriority,
×
2799
                                        Match:     match2,
×
2800
                                        Action:    action,
×
2801
                                        NextHopIP: nextHop,
×
2802
                                },
×
2803
                                externalIDs,
×
2804
                        ); err != nil {
×
2805
                                klog.Errorf("failed to add u2o interconnection policy2 for subnet %s %v", subnet.Name, err)
×
2806
                                return err
×
2807
                        }
×
2808
                }
2809

2810
                action = kubeovnv1.PolicyRouteActionReroute
×
2811
                klog.Infof("add u2o interconnection policy for router: %s, match %s, action %s, nexthop %s", subnet.Spec.Vpc, match3, action, nextHop)
×
2812
                if err := c.addPolicyRouteToVpc(
×
2813
                        subnet.Spec.Vpc,
×
2814
                        &kubeovnv1.PolicyRoute{
×
2815
                                Priority:  util.GatewayRouterPolicyPriority,
×
2816
                                Match:     match3,
×
2817
                                Action:    action,
×
2818
                                NextHopIP: nextHop,
×
2819
                        },
×
2820
                        externalIDs,
×
2821
                ); err != nil {
×
2822
                        klog.Errorf("failed to add u2o interconnection policy3 for subnet %s %v", subnet.Name, err)
×
2823
                        return err
×
2824
                }
×
2825
        }
2826
        return nil
×
2827
}
2828

2829
func (c *Controller) deletePolicyRouteForU2OInterconn(subnet *kubeovnv1.Subnet) error {
×
2830
        logicalRouter, err := c.OVNNbClient.GetLogicalRouter(subnet.Spec.Vpc, true)
×
2831
        if err == nil && logicalRouter == nil {
×
2832
                klog.Infof("logical router %s already deleted", subnet.Spec.Vpc)
×
2833
                return nil
×
2834
        }
×
2835
        policies, err := c.OVNNbClient.ListLogicalRouterPolicies(subnet.Spec.Vpc, -1, map[string]string{
×
2836
                "isU2ORoutePolicy": "true",
×
2837
                "vendor":           util.CniTypeName,
×
2838
                "subnet":           subnet.Name,
×
2839
        }, true)
×
2840
        if err != nil {
×
2841
                klog.Errorf("failed to list logical router policies: %v", err)
×
2842
                return err
×
2843
        }
×
2844
        if len(policies) == 0 {
×
2845
                return nil
×
2846
        }
×
2847

2848
        lr := subnet.Status.U2OInterconnectionVPC
×
2849
        if lr == "" {
×
2850
                // old version field U2OInterconnectionVPC may be "" and then use subnet.Spec.Vpc
×
2851
                lr = subnet.Spec.Vpc
×
2852
        }
×
2853

2854
        for _, policy := range policies {
×
2855
                klog.Infof("delete u2o interconnection policy for router %s with match %s priority %d", lr, policy.Match, policy.Priority)
×
2856
                if err = c.OVNNbClient.DeleteLogicalRouterPolicyByUUID(lr, policy.UUID); err != nil {
×
2857
                        klog.Errorf("failed to delete u2o interconnection policy for subnet %s: %v", subnet.Name, err)
×
2858
                        return err
×
2859
                }
×
2860
        }
2861

2862
        u2oExcludeIP4Ag := strings.ReplaceAll(fmt.Sprintf(util.U2OExcludeIPAg, subnet.Name, "ip4"), "-", ".")
×
2863
        u2oExcludeIP6Ag := strings.ReplaceAll(fmt.Sprintf(util.U2OExcludeIPAg, subnet.Name, "ip6"), "-", ".")
×
2864

×
2865
        if err := c.OVNNbClient.DeleteAddressSet(u2oExcludeIP4Ag); err != nil {
×
2866
                klog.Errorf("delete address set %s: %v", u2oExcludeIP4Ag, err)
×
2867
                return err
×
2868
        }
×
2869

2870
        if err := c.OVNNbClient.DeleteAddressSet(u2oExcludeIP6Ag); err != nil {
×
2871
                klog.Errorf("delete address set %s: %v", u2oExcludeIP6Ag, err)
×
2872
                return err
×
2873
        }
×
2874

2875
        return nil
×
2876
}
2877

2878
func (c *Controller) addStaticRouteForU2OInterconn(subnet *kubeovnv1.Subnet) error {
×
2879
        if subnet.Spec.Vpc == "" {
×
2880
                return nil
×
2881
        }
×
2882

2883
        var v4Gw, v6Gw, v4Cidr, v6Cidr string
×
2884
        for _, gw := range strings.Split(subnet.Spec.Gateway, ",") {
×
2885
                switch util.CheckProtocol(gw) {
×
2886
                case kubeovnv1.ProtocolIPv4:
×
2887
                        v4Gw = gw
×
2888
                case kubeovnv1.ProtocolIPv6:
×
2889
                        v6Gw = gw
×
2890
                }
2891
        }
2892

2893
        for _, cidr := range strings.Split(subnet.Spec.CIDRBlock, ",") {
×
2894
                if util.CheckProtocol(cidr) == kubeovnv1.ProtocolIPv4 {
×
2895
                        v4Cidr = cidr
×
2896
                } else {
×
2897
                        v6Cidr = cidr
×
2898
                }
×
2899
        }
2900

2901
        if v4Gw != "" && v4Cidr != "" {
×
2902
                if err := c.addStaticRouteToVpc(
×
2903
                        subnet.Spec.Vpc,
×
2904
                        &kubeovnv1.StaticRoute{
×
2905
                                Policy:    kubeovnv1.PolicySrc,
×
2906
                                CIDR:      v4Cidr,
×
2907
                                NextHopIP: v4Gw,
×
2908
                        },
×
2909
                ); err != nil {
×
2910
                        klog.Errorf("failed to add static route, %v", err)
×
2911
                        return err
×
2912
                }
×
2913
        }
2914

2915
        if v6Gw != "" && v6Cidr != "" {
×
2916
                if err := c.addStaticRouteToVpc(
×
2917
                        subnet.Spec.Vpc,
×
2918
                        &kubeovnv1.StaticRoute{
×
2919
                                Policy:    kubeovnv1.PolicySrc,
×
2920
                                CIDR:      v6Cidr,
×
2921
                                NextHopIP: v6Gw,
×
2922
                        },
×
2923
                ); err != nil {
×
2924
                        klog.Errorf("failed to add static route, %v", err)
×
2925
                        return err
×
2926
                }
×
2927
        }
2928
        return nil
×
2929
}
2930

2931
func (c *Controller) deleteStaticRouteForU2OInterconn(subnet *kubeovnv1.Subnet) error {
×
2932
        if subnet.Spec.Vpc == "" {
×
2933
                return nil
×
2934
        }
×
2935

2936
        var v4Gw, v6Gw, v4Cidr, v6Cidr string
×
2937
        for _, gw := range strings.Split(subnet.Spec.Gateway, ",") {
×
2938
                switch util.CheckProtocol(gw) {
×
2939
                case kubeovnv1.ProtocolIPv4:
×
2940
                        v4Gw = gw
×
2941
                case kubeovnv1.ProtocolIPv6:
×
2942
                        v6Gw = gw
×
2943
                }
2944
        }
2945

2946
        for _, cidr := range strings.Split(subnet.Spec.CIDRBlock, ",") {
×
2947
                if util.CheckProtocol(cidr) == kubeovnv1.ProtocolIPv4 {
×
2948
                        v4Cidr = cidr
×
2949
                } else {
×
2950
                        v6Cidr = cidr
×
2951
                }
×
2952
        }
2953

2954
        if v4Gw != "" && v4Cidr != "" {
×
2955
                if err := c.deleteStaticRouteFromVpc(
×
2956
                        subnet.Spec.Vpc,
×
2957
                        subnet.Spec.RouteTable,
×
2958
                        v4Cidr,
×
2959
                        v4Gw,
×
2960
                        kubeovnv1.PolicySrc,
×
2961
                ); err != nil {
×
2962
                        klog.Errorf("failed to add static route, %v", err)
×
2963
                        return err
×
2964
                }
×
2965
        }
2966

2967
        if v6Gw != "" && v6Cidr != "" {
×
2968
                if err := c.deleteStaticRouteFromVpc(
×
2969
                        subnet.Spec.Vpc,
×
2970
                        subnet.Spec.RouteTable,
×
2971
                        v6Cidr,
×
2972
                        v6Gw,
×
2973
                        kubeovnv1.PolicySrc,
×
2974
                ); err != nil {
×
2975
                        klog.Errorf("failed to delete static route, %v", err)
×
2976
                        return err
×
2977
                }
×
2978
        }
2979
        return nil
×
2980
}
2981

2982
func (c *Controller) reconcileRouteTableForSubnet(subnet *kubeovnv1.Subnet) error {
×
2983
        if subnet.Spec.Vlan != "" && !subnet.Spec.U2OInterconnection {
×
2984
                return nil
×
2985
        }
×
2986

2987
        routerPortName := ovs.LogicalRouterPortName(subnet.Spec.Vpc, subnet.Name)
×
2988
        lrp, err := c.OVNNbClient.GetLogicalRouterPort(routerPortName, false)
×
2989
        if err != nil {
×
2990
                klog.Error(err)
×
2991
                return err
×
2992
        }
×
2993

2994
        rtb := lrp.Options["route_table"]
×
2995

×
2996
        // no need to update
×
2997
        if rtb == subnet.Spec.RouteTable {
×
2998
                return nil
×
2999
        }
×
3000

3001
        klog.Infof("reconcile route table %q for subnet %s", subnet.Spec.RouteTable, subnet.Name)
×
3002
        opt := map[string]string{"route_table": subnet.Spec.RouteTable}
×
3003
        if err = c.OVNNbClient.UpdateLogicalRouterPortOptions(routerPortName, opt); err != nil {
×
3004
                klog.Errorf("failed to set route table of logical router port %s to %s: %v", routerPortName, subnet.Spec.RouteTable, err)
×
3005
                return err
×
3006
        }
×
3007

3008
        return nil
×
3009
}
3010

3011
func (c *Controller) addCustomVPCPolicyRoutesForSubnet(subnet *kubeovnv1.Subnet) error {
×
3012
        return c.addCommonRoutesForSubnet(subnet)
×
3013
}
×
3014

3015
func (c *Controller) deleteCustomVPCPolicyRoutesForSubnet(subnet *kubeovnv1.Subnet) error {
×
3016
        logicalRouter, err := c.OVNNbClient.GetLogicalRouter(subnet.Spec.Vpc, true)
×
3017
        if err == nil && logicalRouter == nil {
×
3018
                klog.Infof("logical router %s already deleted", subnet.Spec.Vpc)
×
3019
                return nil
×
3020
        }
×
3021
        for _, cidr := range strings.Split(subnet.Spec.CIDRBlock, ",") {
×
3022
                af := 4
×
3023
                if util.CheckProtocol(cidr) == kubeovnv1.ProtocolIPv6 {
×
3024
                        af = 6
×
3025
                }
×
3026
                match := fmt.Sprintf("ip%d.dst == %s", af, cidr)
×
3027
                klog.Infof("delete policy route for router: %s, priority: %d, match %s", subnet.Spec.Vpc, util.SubnetRouterPolicyPriority, match)
×
3028
                if err := c.deletePolicyRouteFromVpc(subnet.Spec.Vpc, util.SubnetRouterPolicyPriority, match); err != nil {
×
3029
                        klog.Errorf("failed to delete logical router policy for CIDR %s of subnet %s: %v", cidr, subnet.Name, err)
×
3030
                        return err
×
3031
                }
×
3032
        }
3033
        return nil
×
3034
}
3035

3036
func (c *Controller) clearOldU2OResource(subnet *kubeovnv1.Subnet) error {
×
3037
        if subnet.Status.U2OInterconnectionVPC != "" &&
×
3038
                (!subnet.Spec.U2OInterconnection || (subnet.Spec.U2OInterconnection && subnet.Status.U2OInterconnectionVPC != subnet.Spec.Vpc)) {
×
3039
                // remove old u2o lsp and lrp first
×
3040
                lspName := fmt.Sprintf("%s-%s", subnet.Name, subnet.Status.U2OInterconnectionVPC)
×
3041
                lrpName := fmt.Sprintf("%s-%s", subnet.Status.U2OInterconnectionVPC, subnet.Name)
×
3042
                klog.Infof("clean subnet %s old u2o resource with lsp %s lrp %s", subnet.Name, lspName, lrpName)
×
3043
                if err := c.OVNNbClient.DeleteLogicalSwitchPort(lspName); err != nil {
×
3044
                        klog.Errorf("failed to delete u2o logical switch port %s: %v", lspName, err)
×
3045
                        return err
×
3046
                }
×
3047

3048
                if err := c.OVNNbClient.DeleteLogicalRouterPort(lrpName); err != nil {
×
3049
                        klog.Errorf("failed to delete u2o logical router port %s: %v", lrpName, err)
×
3050
                        return err
×
3051
                }
×
3052

3053
                if err := c.deletePolicyRouteForU2OInterconn(subnet); err != nil {
×
3054
                        klog.Errorf("failed to delete u2o policy route for u2o connection %s: %v", subnet.Name, err)
×
3055
                        return err
×
3056
                }
×
3057

3058
                if subnet.Status.U2OInterconnectionVPC != c.config.ClusterRouter {
×
3059
                        if err := c.deleteStaticRouteForU2OInterconn(subnet); err != nil {
×
3060
                                klog.Errorf("failed to delete u2o static route for u2o connection %s: %v", subnet.Name, err)
×
3061
                                return err
×
3062
                        }
×
3063
                }
3064
        }
3065
        return nil
×
3066
}
3067

3068
func (c *Controller) reconcilePolicyRouteForCidrChangedSubnet(subnet *kubeovnv1.Subnet, isCommonRoute bool) error {
×
3069
        var match string
×
3070
        var priority int
×
3071

×
3072
        if isCommonRoute {
×
3073
                priority = util.SubnetRouterPolicyPriority
×
3074
        } else {
×
3075
                priority = util.GatewayRouterPolicyPriority
×
3076
        }
×
3077

3078
        policies, err := c.OVNNbClient.ListLogicalRouterPolicies(subnet.Spec.Vpc, priority, map[string]string{
×
3079
                "vendor": util.CniTypeName,
×
3080
                "subnet": subnet.Name,
×
3081
        }, true)
×
3082
        if err != nil {
×
3083
                klog.Errorf("failed to list logical router policies: %v", err)
×
3084
                return err
×
3085
        }
×
3086
        if len(policies) == 0 {
×
3087
                return nil
×
3088
        }
×
3089

3090
        for _, policy := range policies {
×
3091
                policyProtocol := kubeovnv1.ProtocolIPv4
×
3092
                if strings.Contains(policy.Match, "ip6") {
×
3093
                        policyProtocol = kubeovnv1.ProtocolIPv6
×
3094
                }
×
3095

3096
                for _, cidr := range strings.Split(subnet.Spec.CIDRBlock, ",") {
×
3097
                        if cidr == "" {
×
3098
                                continue
×
3099
                        }
3100
                        if policyProtocol != util.CheckProtocol(cidr) {
×
3101
                                continue
×
3102
                        }
3103

3104
                        af := 4
×
3105
                        if util.CheckProtocol(cidr) == kubeovnv1.ProtocolIPv6 {
×
3106
                                af = 6
×
3107
                        }
×
3108

3109
                        if isCommonRoute {
×
3110
                                match = fmt.Sprintf("ip%d.dst == %s", af, cidr)
×
3111
                        } else {
×
3112
                                if subnet.Spec.GatewayType == kubeovnv1.GWCentralizedType {
×
3113
                                        match = fmt.Sprintf("ip%d.src == %s", af, cidr)
×
3114
                                } else {
×
3115
                                        // distributed subnet does not need process gateway route policy
×
3116
                                        continue
×
3117
                                }
3118
                        }
3119

3120
                        if policy.Match != match {
×
3121
                                klog.Infof("delete old policy route for subnet %s with match %s priority %d, new match %v", subnet.Name, policy.Match, policy.Priority, match)
×
3122
                                if err = c.OVNNbClient.DeleteLogicalRouterPolicyByUUID(subnet.Spec.Vpc, policy.UUID); err != nil {
×
3123
                                        klog.Errorf("failed to delete policy route for subnet %s: %v", subnet.Name, err)
×
3124
                                        return err
×
3125
                                }
×
3126
                        }
3127
                }
3128
        }
3129
        return nil
×
3130
}
3131

3132
func (c *Controller) addPolicyRouteForU2ONoLoadBalancer(subnet *kubeovnv1.Subnet) error {
×
3133
        nodes, err := c.nodesLister.List(labels.Everything())
×
3134
        if err != nil {
×
3135
                klog.Errorf("failed to list nodes: %v", err)
×
3136
                return err
×
3137
        }
×
3138
        for _, node := range nodes {
×
3139
                pgName := getOverlaySubnetsPortGroupName(subnet.Name, node.Name)
×
3140
                if err := c.OVNNbClient.CreatePortGroup(pgName, map[string]string{logicalRouterKey: subnet.Spec.Vpc, logicalSwitchKey: subnet.Name, u2oKey: "true"}); err != nil {
×
3141
                        klog.Errorf("failed to create u2o port group for subnet %s and node %s: %v", subnet.Name, node.Name, err)
×
3142
                        return err
×
3143
                }
×
3144
                key := util.NodeLspName(node.Name)
×
3145
                ip, err := c.ipsLister.Get(key)
×
3146
                if err != nil {
×
3147
                        if k8serrors.IsNotFound(err) {
×
3148
                                return nil
×
3149
                        }
×
3150
                        klog.Error(err)
×
3151
                        return err
×
3152
                }
3153
                v4Svc, v6Svc := util.SplitStringIP(c.config.ServiceClusterIPRange)
×
3154
                for _, cidrBlock := range strings.Split(subnet.Spec.CIDRBlock, ",") {
×
3155
                        ipSuffix, nodeIP, svcCIDR := "ip4", ip.Spec.V4IPAddress, v4Svc
×
3156
                        if util.CheckProtocol(cidrBlock) == kubeovnv1.ProtocolIPv6 {
×
3157
                                ipSuffix, nodeIP, svcCIDR = "ip6", ip.Spec.V6IPAddress, v6Svc
×
3158
                        }
×
3159
                        if nodeIP == "" || svcCIDR == "" {
×
3160
                                continue
×
3161
                        }
3162

3163
                        var (
×
3164
                                pgAs        = fmt.Sprintf("%s_%s", pgName, ipSuffix)
×
3165
                                match       = fmt.Sprintf("%s.src == $%s && %s.dst == %s", ipSuffix, pgAs, ipSuffix, svcCIDR)
×
3166
                                action      = kubeovnv1.PolicyRouteActionReroute
×
3167
                                externalIDs = map[string]string{
×
3168
                                        "vendor":               util.CniTypeName,
×
3169
                                        "subnet":               subnet.Name,
×
3170
                                        "isU2ORoutePolicy":     "true",
×
3171
                                        "isU2ONoLBRoutePolicy": "true",
×
3172
                                        "node":                 node.Name,
×
3173
                                }
×
3174
                        )
×
3175

×
3176
                        klog.Infof("add u2o interconnection policy without enabling loadbalancer for router: %s, match %s, action %s, nexthop %s", subnet.Spec.Vpc, match, action, nodeIP)
×
3177
                        if err := c.addPolicyRouteToVpc(
×
3178
                                c.config.ClusterRouter,
×
3179
                                &kubeovnv1.PolicyRoute{
×
3180
                                        Priority:  util.U2OSubnetPolicyPriority,
×
3181
                                        Match:     match,
×
3182
                                        Action:    action,
×
3183
                                        NextHopIP: nodeIP,
×
3184
                                },
×
3185
                                externalIDs,
×
3186
                        ); err != nil {
×
3187
                                klog.Errorf("failed to add logical router policy for port-group address-set %s: %v", pgAs, err)
×
3188
                                return err
×
3189
                        }
×
3190
                }
3191
        }
3192
        lsps, err := c.OVNNbClient.ListNormalLogicalSwitchPorts(true, map[string]string{logicalSwitchKey: subnet.Name})
×
3193
        if err != nil {
×
3194
                klog.Errorf("failed to list normal lsps for subnet %s: %v", subnet.Name, err)
×
3195
                return err
×
3196
        }
×
3197
        for _, lsp := range lsps {
×
3198
                ip, err := c.ipsLister.Get(lsp.Name)
×
3199
                if err != nil {
×
3200
                        if k8serrors.IsNotFound(err) {
×
3201
                                return nil
×
3202
                        }
×
3203
                        klog.Error(err)
×
3204
                        return err
×
3205
                }
3206
                pgName := getOverlaySubnetsPortGroupName(subnet.Name, ip.Spec.NodeName)
×
3207
                if err = c.OVNNbClient.PortGroupAddPorts(pgName, lsp.Name); err != nil {
×
3208
                        klog.Errorf("failed to add port to u2o port group %s: %v", pgName, err)
×
3209
                        return err
×
3210
                }
×
3211
        }
3212
        return nil
×
3213
}
3214

3215
func (c *Controller) deletePolicyRouteForU2ONoLoadBalancer(subnet *kubeovnv1.Subnet) error {
×
3216
        logicalRouter, err := c.OVNNbClient.GetLogicalRouter(subnet.Spec.Vpc, true)
×
3217
        if err == nil && logicalRouter == nil {
×
3218
                klog.Infof("logical router %s already deleted", subnet.Spec.Vpc)
×
3219
                return nil
×
3220
        }
×
3221
        policies, err := c.OVNNbClient.ListLogicalRouterPolicies(subnet.Spec.Vpc, -1, map[string]string{
×
3222
                "isU2ONoLBRoutePolicy": "true",
×
3223
                "vendor":               util.CniTypeName,
×
3224
                "subnet":               subnet.Name,
×
3225
        }, true)
×
3226
        if err != nil {
×
3227
                klog.Errorf("failed to list logical router policies: %v", err)
×
3228
                return err
×
3229
        }
×
3230

3231
        lr := subnet.Status.U2OInterconnectionVPC
×
3232
        if lr == "" {
×
3233
                // old version field U2OInterconnectionVPC may be "" and then use subnet.Spec.Vpc
×
3234
                lr = subnet.Spec.Vpc
×
3235
        }
×
3236

3237
        for _, policy := range policies {
×
3238
                klog.Infof("delete u2o interconnection policy without enabling loadbalancer for router %s with match %s priority %d", lr, policy.Match, policy.Priority)
×
3239
                if err = c.OVNNbClient.DeleteLogicalRouterPolicyByUUID(lr, policy.UUID); err != nil {
×
3240
                        klog.Errorf("failed to delete u2o interconnection policy for subnet %s: %v", subnet.Name, err)
×
3241
                        return err
×
3242
                }
×
3243
        }
3244

3245
        pgs, err := c.OVNNbClient.ListPortGroups(map[string]string{logicalRouterKey: subnet.Spec.Vpc, logicalSwitchKey: subnet.Name, u2oKey: "true"})
×
3246
        if err != nil {
×
3247
                klog.Errorf("failed to list u2o port groups with u2oKey is true for subnet %s: %v", subnet.Name, err)
×
3248
                return err
×
3249
        }
×
3250
        for _, pg := range pgs {
×
3251
                klog.Infof("delete u2o port group %s for subnet %s", pg.Name, subnet.Name)
×
3252
                if err = c.OVNNbClient.DeletePortGroup(pg.Name); err != nil {
×
3253
                        klog.Errorf("failed to delete u2o port group for subnet %s: %v", subnet.Name, err)
×
3254
                        return err
×
3255
                }
×
3256
        }
3257
        return nil
×
3258
}
3259

3260
func (c *Controller) findSubnetByNetworkAttachmentDefinition(ns, name string, subnets []*kubeovnv1.Subnet) (*kubeovnv1.Subnet, error) {
×
3261
        nadClient := c.config.AttachNetClient.K8sCniCncfIoV1().NetworkAttachmentDefinitions(ns)
×
3262
        nad, err := nadClient.Get(context.Background(), name, metav1.GetOptions{})
×
3263
        if err != nil {
×
3264
                klog.Errorf("failed to get net-attach-def %s/%s: %v", ns, name, err)
×
3265
                return nil, err
×
3266
        }
×
3267
        netCfg, err := loadNetConf([]byte(nad.Spec.Config))
×
3268
        if err != nil {
×
3269
                klog.Errorf("failed to parse config of net-attach-def %s/%s: %v", ns, name, err)
×
3270
                return nil, err
×
3271
        }
×
3272

3273
        var provider string
×
3274
        if netCfg.Conf.Type == util.CniTypeName {
×
3275
                provider = fmt.Sprintf("%s.%s.%s", name, ns, util.OvnProvider)
×
3276
        } else {
×
3277
                provider = fmt.Sprintf("%s.%s", name, ns)
×
3278
        }
×
3279
        var subnet *kubeovnv1.Subnet
×
3280
        for _, s := range subnets {
×
3281
                if s.Spec.Provider == provider {
×
3282
                        subnet = s.DeepCopy()
×
3283
                        break
×
3284
                }
3285
        }
3286
        if subnet == nil {
×
3287
                err = fmt.Errorf("failed to get subnet for net-attach-def %s/%s", ns, name)
×
3288
                klog.Error(err)
×
3289
                return nil, err
×
3290
        }
×
3291

3292
        return subnet, nil
×
3293
}
3294

3295
func (c *Controller) handleMcastQuerierChange(subnet *kubeovnv1.Subnet) error {
×
3296
        if subnet.Spec.EnableMulticastSnoop {
×
3297
                multicastSnoopFlag := map[string]string{
×
3298
                        "mcast_snoop":   "true",
×
3299
                        "mcast_querier": "true",
×
3300
                        "mcast_ip4_src": subnet.Status.McastQuerierIP,
×
3301
                        "mcast_eth_src": subnet.Status.McastQuerierMAC,
×
3302
                }
×
3303
                mcastQuerierLspName := fmt.Sprintf(util.McastQuerierName, subnet.Name)
×
3304
                if err := c.OVNNbClient.CreateLogicalSwitchPort(subnet.Name, mcastQuerierLspName, subnet.Status.McastQuerierIP, subnet.Status.McastQuerierMAC, mcastQuerierLspName, "default", false, "", "", false, nil, ""); err != nil {
×
3305
                        err = fmt.Errorf("failed to create mcast querier lsp %s: %w", mcastQuerierLspName, err)
×
3306
                        klog.Error(err)
×
3307
                        return err
×
3308
                }
×
3309

3310
                if err := c.OVNNbClient.LogicalSwitchUpdateOtherConfig(subnet.Name, ovsdb.MutateOperationInsert, multicastSnoopFlag); err != nil {
×
3311
                        klog.Errorf("enable logical switch multicast snoop %s: %v", subnet.Name, err)
×
3312
                        return err
×
3313
                }
×
3314
        } else {
×
3315
                lss, err := c.OVNNbClient.ListLogicalSwitch(false, func(ls *ovnnb.LogicalSwitch) bool {
×
3316
                        return ls.Name == subnet.Name
×
3317
                })
×
3318
                if err != nil || len(lss) == 0 {
×
3319
                        klog.Errorf("failed to list logical switch %s: %v", subnet.Name, err)
×
3320
                        return err
×
3321
                }
×
3322

3323
                multicastSnoopFlag := map[string]string{
×
3324
                        "mcast_snoop":   lss[0].OtherConfig["mcast_snoop"],
×
3325
                        "mcast_querier": lss[0].OtherConfig["mcast_querier"],
×
3326
                        "mcast_ip4_src": lss[0].OtherConfig["mcast_ip4_src"],
×
3327
                        "mcast_eth_src": lss[0].OtherConfig["mcast_eth_src"],
×
3328
                }
×
3329
                mcastQuerierLspName := fmt.Sprintf(util.McastQuerierName, subnet.Name)
×
3330
                if err := c.OVNNbClient.LogicalSwitchUpdateOtherConfig(subnet.Name, ovsdb.MutateOperationDelete, multicastSnoopFlag); err != nil {
×
3331
                        klog.Errorf("disable logical switch multicast snoop %s: %v", subnet.Name, err)
×
3332
                        return err
×
3333
                }
×
3334

3335
                if err := c.OVNNbClient.DeleteLogicalSwitchPort(mcastQuerierLspName); err != nil {
×
3336
                        err = fmt.Errorf("failed to delete mcast querier lsp %s: %w", mcastQuerierLspName, err)
×
3337
                        klog.Error(err)
×
3338
                        return err
×
3339
                }
×
3340
        }
3341
        return nil
×
3342
}
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