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

kubeovn / kube-ovn / 21623048013

03 Feb 2026 08:37AM UTC coverage: 23.043%. Remained the same
21623048013

push

github

web-flow
fix typo (#6253)

Signed-off-by: Mengxin Liu <liumengxinfly@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

12 of 152 new or added lines in 51 files covered. (7.89%)

1 existing line in 1 file now uncovered.

12411 of 53860 relevant lines covered (23.04%)

0.27 hits per line

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

9.91
/pkg/controller/pod.go
1
package controller
2

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

16
        nadv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
17
        nadutils "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/utils"
18
        "github.com/scylladb/go-set/strset"
19
        appsv1 "k8s.io/api/apps/v1"
20
        v1 "k8s.io/api/core/v1"
21
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
22
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23
        "k8s.io/apimachinery/pkg/labels"
24
        "k8s.io/apimachinery/pkg/types"
25
        utilruntime "k8s.io/apimachinery/pkg/util/runtime"
26
        "k8s.io/client-go/kubernetes"
27
        "k8s.io/client-go/tools/cache"
28
        "k8s.io/klog/v2"
29
        "k8s.io/utils/ptr"
30
        kubevirtv1 "kubevirt.io/api/core/v1"
31

32
        kubeovnv1 "github.com/kubeovn/kube-ovn/pkg/apis/kubeovn/v1"
33
        "github.com/kubeovn/kube-ovn/pkg/ipam"
34
        "github.com/kubeovn/kube-ovn/pkg/ovs"
35
        "github.com/kubeovn/kube-ovn/pkg/ovsdb/ovnnb"
36
        "github.com/kubeovn/kube-ovn/pkg/request"
37
        "github.com/kubeovn/kube-ovn/pkg/util"
38
)
39

40
type NamedPort struct {
41
        mutex sync.RWMutex
42
        // first key is namespace, second key is portName
43
        namedPortMap map[string]map[string]*util.NamedPortInfo
44
}
45

46
func NewNamedPort() *NamedPort {
×
47
        return &NamedPort{
×
48
                mutex:        sync.RWMutex{},
×
49
                namedPortMap: map[string]map[string]*util.NamedPortInfo{},
×
50
        }
×
51
}
×
52

53
func (n *NamedPort) AddNamedPortByPod(pod *v1.Pod) {
×
54
        n.mutex.Lock()
×
55
        defer n.mutex.Unlock()
×
56
        ns := pod.Namespace
×
57
        podName := pod.Name
×
58

×
59
        restartableInitContainers := make([]v1.Container, 0, len(pod.Spec.InitContainers))
×
60
        for i := range pod.Spec.InitContainers {
×
61
                if pod.Spec.InitContainers[i].RestartPolicy != nil &&
×
62
                        *pod.Spec.InitContainers[i].RestartPolicy == v1.ContainerRestartPolicyAlways {
×
63
                        restartableInitContainers = append(restartableInitContainers, pod.Spec.InitContainers[i])
×
64
                }
×
65
        }
66

67
        containers := slices.Concat(restartableInitContainers, pod.Spec.Containers)
×
68
        if len(containers) == 0 {
×
69
                return
×
70
        }
×
71

72
        for _, container := range containers {
×
73
                if len(container.Ports) == 0 {
×
74
                        continue
×
75
                }
76

77
                for _, port := range container.Ports {
×
78
                        if port.Name == "" || port.ContainerPort == 0 {
×
79
                                continue
×
80
                        }
81

82
                        if _, ok := n.namedPortMap[ns]; ok {
×
83
                                if _, ok := n.namedPortMap[ns][port.Name]; ok {
×
84
                                        if n.namedPortMap[ns][port.Name].PortID == port.ContainerPort {
×
85
                                                n.namedPortMap[ns][port.Name].Pods.Add(podName)
×
86
                                        } else {
×
NEW
87
                                                klog.Warningf("named port %s has already been defined with portID %d",
×
88
                                                        port.Name, n.namedPortMap[ns][port.Name].PortID)
×
89
                                        }
×
90
                                        continue
×
91
                                }
92
                        } else {
×
93
                                n.namedPortMap[ns] = make(map[string]*util.NamedPortInfo)
×
94
                        }
×
95
                        n.namedPortMap[ns][port.Name] = &util.NamedPortInfo{
×
96
                                PortID: port.ContainerPort,
×
97
                                Pods:   strset.New(podName),
×
98
                        }
×
99
                }
100
        }
101
}
102

103
func (n *NamedPort) DeleteNamedPortByPod(pod *v1.Pod) {
×
104
        n.mutex.Lock()
×
105
        defer n.mutex.Unlock()
×
106

×
107
        ns := pod.Namespace
×
108
        podName := pod.Name
×
109

×
110
        if pod.Spec.Containers == nil {
×
111
                return
×
112
        }
×
113

114
        for _, container := range pod.Spec.Containers {
×
115
                if container.Ports == nil {
×
116
                        continue
×
117
                }
118

119
                for _, port := range container.Ports {
×
120
                        if port.Name == "" {
×
121
                                continue
×
122
                        }
123

124
                        if _, ok := n.namedPortMap[ns]; !ok {
×
125
                                continue
×
126
                        }
127

128
                        if _, ok := n.namedPortMap[ns][port.Name]; !ok {
×
129
                                continue
×
130
                        }
131

132
                        if !n.namedPortMap[ns][port.Name].Pods.Has(podName) {
×
133
                                continue
×
134
                        }
135

136
                        n.namedPortMap[ns][port.Name].Pods.Remove(podName)
×
137
                        if n.namedPortMap[ns][port.Name].Pods.Size() == 0 {
×
138
                                delete(n.namedPortMap[ns], port.Name)
×
139
                                if len(n.namedPortMap[ns]) == 0 {
×
140
                                        delete(n.namedPortMap, ns)
×
141
                                }
×
142
                        }
143
                }
144
        }
145
}
146

147
func (n *NamedPort) GetNamedPortByNs(namespace string) map[string]*util.NamedPortInfo {
×
148
        n.mutex.RLock()
×
149
        defer n.mutex.RUnlock()
×
150

×
151
        if result, ok := n.namedPortMap[namespace]; ok {
×
152
                for portName, info := range result {
×
153
                        klog.Infof("namespace %s's namedPort portname is %s with info %v", namespace, portName, info)
×
154
                }
×
155
                return result
×
156
        }
157
        return nil
×
158
}
159

160
func isPodAlive(p *v1.Pod) bool {
×
161
        if !p.DeletionTimestamp.IsZero() && p.DeletionGracePeriodSeconds != nil {
×
162
                now := time.Now()
×
163
                deletionTime := p.DeletionTimestamp.Time
×
164
                gracePeriod := time.Duration(*p.DeletionGracePeriodSeconds) * time.Second
×
165
                if now.After(deletionTime.Add(gracePeriod)) {
×
166
                        return false
×
167
                }
×
168
        }
169
        return isPodStatusPhaseAlive(p)
×
170
}
171

172
func isPodStatusPhaseAlive(p *v1.Pod) bool {
×
173
        if p.Status.Phase == v1.PodSucceeded && p.Spec.RestartPolicy != v1.RestartPolicyAlways {
×
174
                return false
×
175
        }
×
176

177
        if p.Status.Phase == v1.PodFailed && p.Spec.RestartPolicy == v1.RestartPolicyNever {
×
178
                return false
×
179
        }
×
180

181
        if p.Status.Phase == v1.PodFailed && p.Status.Reason == "Evicted" {
×
182
                return false
×
183
        }
×
184
        return true
×
185
}
186

187
func (c *Controller) enqueueAddPod(obj any) {
×
188
        p := obj.(*v1.Pod)
×
189
        if p.Spec.HostNetwork {
×
190
                return
×
191
        }
×
192

193
        // Pod might be targeted by manual endpoints and we need to recompute its port mappings
194
        c.enqueueStaticEndpointUpdateInNamespace(p.Namespace)
×
195

×
196
        // TODO: we need to find a way to reduce duplicated np added to the queue
×
197
        if c.config.EnableNP {
×
198
                c.namedPort.AddNamedPortByPod(p)
×
199
                if p.Status.PodIP != "" {
×
200
                        for _, np := range c.podMatchNetworkPolicies(p) {
×
201
                                klog.V(3).Infof("enqueue update network policy %s", np)
×
202
                                c.updateNpQueue.Add(np)
×
203
                        }
×
204
                }
205
        }
206

207
        key := cache.MetaObjectToName(p).String()
×
208
        if !isPodAlive(p) {
×
209
                isStateful, statefulSetName, statefulSetUID := isStatefulSetPod(p)
×
210
                isVMPod, vmName := isVMPod(p)
×
211
                if isStateful || (isVMPod && c.config.EnableKeepVMIP) {
×
212
                        if isStateful && isStatefulSetPodToDel(c.config.KubeClient, p, statefulSetName, statefulSetUID) {
×
213
                                klog.V(3).Infof("enqueue delete pod %s", key)
×
214
                                c.deletingPodObjMap.Store(key, p)
×
215
                                c.deletePodQueue.Add(key)
×
216
                        }
×
217
                        if isVMPod && c.isVMToDel(p, vmName) {
×
218
                                klog.V(3).Infof("enqueue delete pod %s", key)
×
219
                                c.deletingPodObjMap.Store(key, p)
×
220
                                c.deletePodQueue.Add(key)
×
221
                        }
×
222
                } else {
×
223
                        klog.V(3).Infof("enqueue delete pod %s", key)
×
224
                        c.deletingPodObjMap.Store(key, p)
×
225
                        c.deletePodQueue.Add(key)
×
226
                }
×
227
                return
×
228
        }
229

230
        need, err := c.podNeedSync(p)
×
231
        if err != nil {
×
232
                klog.Errorf("invalid pod net: %v", err)
×
233
                return
×
234
        }
×
235
        if need {
×
236
                klog.Infof("enqueue add pod %s", key)
×
237
                c.addOrUpdatePodQueue.Add(key)
×
238
        }
×
239

240
        if err = c.handlePodEventForVpcEgressGateway(p); err != nil {
×
241
                klog.Errorf("failed to handle pod event for vpc egress gateway: %v", err)
×
242
        }
×
243
}
244

245
func (c *Controller) getNsLabels(nsName, podName string) map[string]string {
×
246
        podNs, err := c.namespacesLister.Get(nsName)
×
247
        if err != nil {
×
248
                if k8serrors.IsNotFound(err) {
×
249
                        klog.V(3).Infof("namespace %s not found for pod %s, use empty ns labels", nsName, podName)
×
250
                } else {
×
251
                        klog.Errorf("failed to get namespace %s: %v, use empty ns labels", nsName, err)
×
252
                }
×
253
                return nil
×
254
        }
255
        return podNs.Labels
×
256
}
257

258
func (c *Controller) enqueueDeletePod(obj any) {
×
259
        var p *v1.Pod
×
260
        switch t := obj.(type) {
×
261
        case *v1.Pod:
×
262
                p = t
×
263
        case cache.DeletedFinalStateUnknown:
×
264
                pod, ok := t.Obj.(*v1.Pod)
×
265
                if !ok {
×
266
                        klog.Warningf("unexpected object type: %T", t.Obj)
×
267
                        return
×
268
                }
×
269
                p = pod
×
270
        default:
×
271
                klog.Warningf("unexpected type: %T", obj)
×
272
                return
×
273
        }
274

275
        if p.Spec.HostNetwork {
×
276
                return
×
277
        }
×
278

279
        // Pod might be targeted by manual endpoints and we need to recompute its port mappings
280
        c.enqueueStaticEndpointUpdateInNamespace(p.Namespace)
×
281

×
282
        if c.config.EnableNP {
×
283
                c.namedPort.DeleteNamedPortByPod(p)
×
284
                for _, np := range c.podMatchNetworkPolicies(p) {
×
285
                        c.updateNpQueue.Add(np)
×
286
                }
×
287
        }
288

289
        if c.config.EnableANP {
×
290
                nsLabels := c.getNsLabels(p.Namespace, p.Name)
×
291
                c.updateAnpsByLabelsMatch(nsLabels, p.Labels)
×
292
                c.updateCnpsByLabelsMatch(nsLabels, p.Labels)
×
293
        }
×
294

295
        key := cache.MetaObjectToName(p).String()
×
296
        klog.Infof("enqueue delete pod %s", key)
×
297
        c.deletingPodObjMap.Store(key, p)
×
298
        c.deletePodQueue.Add(key)
×
299
}
300

301
func (c *Controller) enqueueUpdatePod(oldObj, newObj any) {
×
302
        oldPod := oldObj.(*v1.Pod)
×
303
        newPod := newObj.(*v1.Pod)
×
304

×
305
        // Pod might be targeted by manual endpoints and we need to recompute its port mappings
×
306
        c.enqueueStaticEndpointUpdateInNamespace(oldPod.Namespace)
×
307

×
308
        if oldPod.Annotations[util.AAPsAnnotation] != "" || newPod.Annotations[util.AAPsAnnotation] != "" {
×
309
                oldAAPs := strings.Split(oldPod.Annotations[util.AAPsAnnotation], ",")
×
310
                newAAPs := strings.Split(newPod.Annotations[util.AAPsAnnotation], ",")
×
311
                var vipNames []string
×
312
                for _, vipName := range oldAAPs {
×
313
                        vipNames = append(vipNames, strings.TrimSpace(vipName))
×
314
                }
×
315
                for _, vipName := range newAAPs {
×
316
                        vipName = strings.TrimSpace(vipName)
×
317
                        if !slices.Contains(vipNames, vipName) {
×
318
                                vipNames = append(vipNames, vipName)
×
319
                        }
×
320
                }
321
                for _, vipName := range vipNames {
×
322
                        if vip, err := c.virtualIpsLister.Get(vipName); err == nil {
×
323
                                if vip.Spec.Namespace != newPod.Namespace {
×
324
                                        continue
×
325
                                }
326
                                klog.Infof("enqueue update virtual parents for %s", vipName)
×
327
                                c.updateVirtualParentsQueue.Add(vipName)
×
328
                        }
329
                }
330
        }
331

332
        if newPod.Spec.HostNetwork || oldPod.ResourceVersion == newPod.ResourceVersion {
×
333
                return
×
334
        }
×
335

336
        podNets, err := c.getPodKubeovnNets(newPod)
×
337
        if err != nil {
×
338
                klog.Errorf("failed to get newPod nets %v", err)
×
339
                return
×
340
        }
×
341

342
        key := cache.MetaObjectToName(newPod).String()
×
343
        if c.config.EnableNP {
×
344
                c.namedPort.AddNamedPortByPod(newPod)
×
345
                newNp := c.podMatchNetworkPolicies(newPod)
×
346
                if !maps.Equal(oldPod.Labels, newPod.Labels) {
×
347
                        oldNp := c.podMatchNetworkPolicies(oldPod)
×
348
                        for _, np := range util.DiffStringSlice(oldNp, newNp) {
×
349
                                c.updateNpQueue.Add(np)
×
350
                        }
×
351
                }
352

353
                for _, podNet := range podNets {
×
354
                        oldAllocated := oldPod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, podNet.ProviderName)]
×
355
                        newAllocated := newPod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, podNet.ProviderName)]
×
356
                        if oldAllocated != newAllocated {
×
357
                                for _, np := range newNp {
×
358
                                        klog.V(3).Infof("enqueue update network policy %s for pod %s", np, key)
×
359
                                        c.updateNpQueue.Add(np)
×
360
                                }
×
361
                                break
×
362
                        }
363
                }
364
        }
365

366
        if c.config.EnableANP {
×
367
                nsLabels := c.getNsLabels(newPod.Namespace, newPod.Name)
×
368
                if !maps.Equal(oldPod.Labels, newPod.Labels) {
×
369
                        c.updateAnpsByLabelsMatch(nsLabels, newPod.Labels)
×
370
                        c.updateCnpsByLabelsMatch(nsLabels, newPod.Labels)
×
371
                }
×
372

373
                for _, podNet := range podNets {
×
374
                        oldAllocated := oldPod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, podNet.ProviderName)]
×
375
                        newAllocated := newPod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, podNet.ProviderName)]
×
376
                        if oldAllocated != newAllocated {
×
377
                                c.updateAnpsByLabelsMatch(nsLabels, newPod.Labels)
×
378
                                c.updateCnpsByLabelsMatch(nsLabels, newPod.Labels)
×
379
                                break
×
380
                        }
381
                }
382
        }
383

384
        isStateful, statefulSetName, statefulSetUID := isStatefulSetPod(newPod)
×
385
        isVMPod, vmName := isVMPod(newPod)
×
386
        if !isPodStatusPhaseAlive(newPod) && !isStateful && !isVMPod {
×
387
                klog.V(3).Infof("enqueue delete pod %s", key)
×
388
                c.deletingPodObjMap.Store(key, newPod)
×
389
                c.deletePodQueue.Add(key)
×
390
                return
×
391
        }
×
392

393
        // enqueue delay
394
        var delay time.Duration
×
395
        if newPod.Spec.TerminationGracePeriodSeconds != nil {
×
396
                if !newPod.DeletionTimestamp.IsZero() {
×
397
                        delay = time.Until(newPod.DeletionTimestamp.Add(time.Duration(*newPod.Spec.TerminationGracePeriodSeconds) * time.Second))
×
398
                } else {
×
399
                        delay = time.Duration(*newPod.Spec.TerminationGracePeriodSeconds) * time.Second
×
400
                }
×
401
        }
402

403
        if !newPod.DeletionTimestamp.IsZero() && !isStateful && !isVMPod {
×
404
                go func() {
×
405
                        // In case node get lost and pod can not be deleted,
×
406
                        // the ip address will not be recycled
×
407
                        klog.V(3).Infof("enqueue delete pod %s after %v", key, delay)
×
408
                        c.deletingPodObjMap.Store(key, newPod)
×
409
                        c.deletePodQueue.AddAfter(key, delay)
×
410
                }()
×
411
                return
×
412
        }
413

414
        if err = c.handlePodEventForVpcEgressGateway(newPod); err != nil {
×
415
                klog.Errorf("failed to handle pod event for vpc egress gateway: %v", err)
×
416
        }
×
417

418
        // do not delete statefulset/vm pod unless ownerReferences is deleted
419
        shouldDelete := (isStateful && isStatefulSetPodToDel(c.config.KubeClient, newPod, statefulSetName, statefulSetUID)) ||
×
420
                (isVMPod && c.isVMToDel(newPod, vmName))
×
421
        if shouldDelete {
×
422
                go func() {
×
423
                        klog.V(3).Infof("enqueue delete pod %s after %v", key, delay)
×
424
                        c.deletingPodObjMap.Store(key, newPod)
×
425
                        c.deletePodQueue.AddAfter(key, delay)
×
426
                }()
×
427
                return
×
428
        }
429
        klog.Infof("enqueue update pod %s", key)
×
430
        c.addOrUpdatePodQueue.Add(key)
×
431

×
432
        // security policy changed
×
433
        for _, podNet := range podNets {
×
434
                oldSecurity := oldPod.Annotations[fmt.Sprintf(util.PortSecurityAnnotationTemplate, podNet.ProviderName)]
×
435
                newSecurity := newPod.Annotations[fmt.Sprintf(util.PortSecurityAnnotationTemplate, podNet.ProviderName)]
×
436
                oldSg := oldPod.Annotations[fmt.Sprintf(util.SecurityGroupAnnotationTemplate, podNet.ProviderName)]
×
437
                newSg := newPod.Annotations[fmt.Sprintf(util.SecurityGroupAnnotationTemplate, podNet.ProviderName)]
×
438
                oldVips := oldPod.Annotations[fmt.Sprintf(util.PortVipAnnotationTemplate, podNet.ProviderName)]
×
439
                newVips := newPod.Annotations[fmt.Sprintf(util.PortVipAnnotationTemplate, podNet.ProviderName)]
×
440
                oldAAPs := oldPod.Annotations[util.AAPsAnnotation]
×
441
                newAAPs := newPod.Annotations[util.AAPsAnnotation]
×
442
                if oldSecurity != newSecurity || oldSg != newSg || oldVips != newVips || oldAAPs != newAAPs {
×
443
                        c.updatePodSecurityQueue.Add(key)
×
444
                        break
×
445
                }
446
        }
447
}
448

449
func (c *Controller) getPodKubeovnNets(pod *v1.Pod) ([]*kubeovnNet, error) {
1✔
450
        attachmentNets, err := c.getPodAttachmentNet(pod)
1✔
451
        if err != nil {
1✔
452
                klog.Error(err)
×
453
                return nil, err
×
454
        }
×
455

456
        podNets := attachmentNets
1✔
457
        // When Kube-OVN is run as non-primary CNI, we do not add default network configuration to pod.
1✔
458
        // We only add network attachment defined by the user to pod.
1✔
459
        if c.config.EnableNonPrimaryCNI {
2✔
460
                return podNets, nil
1✔
461
        }
1✔
462

463
        defaultSubnet, err := c.getPodDefaultSubnet(pod)
1✔
464
        if err != nil {
1✔
465
                klog.Error(err)
×
466
                return nil, err
×
467
        }
×
468

469
        // pod annotation default subnet not found
470
        if defaultSubnet == nil {
1✔
471
                klog.Errorf("pod %s/%s has no default subnet, skip adding default network", pod.Namespace, pod.Name)
×
472
                return attachmentNets, nil
×
473
        }
×
474

475
        if _, hasOtherDefaultNet := pod.Annotations[util.DefaultNetworkAnnotation]; !hasOtherDefaultNet {
2✔
476
                podNets = append(attachmentNets, &kubeovnNet{
1✔
477
                        Type:         providerTypeOriginal,
1✔
478
                        ProviderName: util.OvnProvider,
1✔
479
                        Subnet:       defaultSubnet,
1✔
480
                        IsDefault:    true,
1✔
481
                })
1✔
482
        }
1✔
483

484
        return podNets, nil
1✔
485
}
486

487
func (c *Controller) handleAddOrUpdatePod(key string) (err error) {
×
488
        now := time.Now()
×
489
        klog.Infof("handle add/update pod %s", key)
×
490

×
491
        namespace, name, err := cache.SplitMetaNamespaceKey(key)
×
492
        if err != nil {
×
493
                utilruntime.HandleError(fmt.Errorf("invalid resource key: %s", key))
×
494
                return nil
×
495
        }
×
496

497
        c.podKeyMutex.LockKey(key)
×
498
        defer func() {
×
499
                _ = c.podKeyMutex.UnlockKey(key)
×
500
                last := time.Since(now)
×
501
                klog.Infof("take %d ms to handle add or update pod %s", last.Milliseconds(), key)
×
502
        }()
×
503

504
        pod, err := c.podsLister.Pods(namespace).Get(name)
×
505
        if err != nil {
×
506
                if k8serrors.IsNotFound(err) {
×
507
                        return nil
×
508
                }
×
509
                klog.Error(err)
×
510
                return err
×
511
        }
512
        if err := util.ValidatePodNetwork(pod.Annotations); err != nil {
×
513
                klog.Errorf("validate pod %s/%s failed: %v", namespace, name, err)
×
514
                c.recorder.Eventf(pod, v1.EventTypeWarning, "ValidatePodNetworkFailed", err.Error())
×
515
                return err
×
516
        }
×
517

518
        podNets, err := c.getPodKubeovnNets(pod)
×
519
        if err != nil {
×
520
                klog.Errorf("failed to get pod nets %v", err)
×
521
                return err
×
522
        }
×
523

524
        // check and do hotnoplug nic
525
        if pod, err = c.syncKubeOvnNet(pod, podNets); err != nil {
×
526
                klog.Errorf("failed to sync pod nets %v", err)
×
527
                return err
×
528
        }
×
529
        if pod == nil {
×
530
                // pod has been deleted
×
531
                return nil
×
532
        }
×
533
        needAllocatePodNets := needAllocateSubnets(pod, podNets)
×
534
        if len(needAllocatePodNets) != 0 {
×
535
                if pod, err = c.reconcileAllocateSubnets(pod, needAllocatePodNets); err != nil {
×
536
                        klog.Error(err)
×
537
                        return err
×
538
                }
×
539
                if pod == nil {
×
540
                        // pod has been deleted
×
541
                        return nil
×
542
                }
×
543
        }
544

545
        isVpcNatGw, vpcGwName := c.checkIsPodVpcNatGw(pod)
×
546
        if isVpcNatGw {
×
547
                if needRestartNatGatewayPod(pod) {
×
548
                        klog.Infof("restarting vpc nat gateway %s", vpcGwName)
×
549
                        c.addOrUpdateVpcNatGatewayQueue.Add(vpcGwName)
×
550
                }
×
551
        }
552

553
        // check if route subnet is need.
554
        return c.reconcileRouteSubnets(pod, needRouteSubnets(pod, podNets))
×
555
}
556

557
// do the same thing as add pod
558
func (c *Controller) reconcileAllocateSubnets(pod *v1.Pod, needAllocatePodNets []*kubeovnNet) (*v1.Pod, error) {
×
559
        namespace := pod.Namespace
×
560
        name := pod.Name
×
561
        klog.Infof("sync pod %s/%s allocated", namespace, name)
×
562

×
563
        vipsMap := c.getVirtualIPs(pod, needAllocatePodNets)
×
564
        isVMPod, vmName := isVMPod(pod)
×
565
        podType := getPodType(pod)
×
566
        podName := c.getNameByPod(pod)
×
567
        // todo: isVmPod, getPodType, getNameByPod has duplicated logic
×
568

×
569
        var err error
×
570
        var vmKey string
×
571
        if isVMPod && c.config.EnableKeepVMIP {
×
572
                vmKey = fmt.Sprintf("%s/%s", namespace, vmName)
×
573
        }
×
574
        // Avoid create lsp for already running pod in ovn-nb when controller restart
575
        patch := util.KVPatch{}
×
576
        for _, podNet := range needAllocatePodNets {
×
577
                // the subnet may changed when alloc static ip from the latter subnet after ns supports multi subnets
×
578
                v4IP, v6IP, mac, subnet, err := c.acquireAddress(pod, podNet)
×
579
                if err != nil {
×
580
                        c.recorder.Eventf(pod, v1.EventTypeWarning, "AcquireAddressFailed", err.Error())
×
581
                        klog.Error(err)
×
582
                        return nil, err
×
583
                }
×
584
                ipStr := util.GetStringIP(v4IP, v6IP)
×
585
                patch[fmt.Sprintf(util.IPAddressAnnotationTemplate, podNet.ProviderName)] = ipStr
×
586
                if mac == "" {
×
587
                        patch[fmt.Sprintf(util.MacAddressAnnotationTemplate, podNet.ProviderName)] = nil
×
588
                } else {
×
589
                        patch[fmt.Sprintf(util.MacAddressAnnotationTemplate, podNet.ProviderName)] = mac
×
590
                }
×
591
                patch[fmt.Sprintf(util.CidrAnnotationTemplate, podNet.ProviderName)] = subnet.Spec.CIDRBlock
×
592
                patch[fmt.Sprintf(util.GatewayAnnotationTemplate, podNet.ProviderName)] = subnet.Spec.Gateway
×
593
                if isOvnSubnet(podNet.Subnet) {
×
594
                        patch[fmt.Sprintf(util.LogicalSwitchAnnotationTemplate, podNet.ProviderName)] = subnet.Name
×
595
                        if pod.Annotations[fmt.Sprintf(util.PodNicAnnotationTemplate, podNet.ProviderName)] == "" {
×
596
                                patch[fmt.Sprintf(util.PodNicAnnotationTemplate, podNet.ProviderName)] = c.config.PodNicType
×
597
                        }
×
598
                } else {
×
599
                        patch[fmt.Sprintf(util.LogicalSwitchAnnotationTemplate, podNet.ProviderName)] = nil
×
600
                        patch[fmt.Sprintf(util.PodNicAnnotationTemplate, podNet.ProviderName)] = nil
×
601
                }
×
602
                patch[fmt.Sprintf(util.AllocatedAnnotationTemplate, podNet.ProviderName)] = "true"
×
603
                if vmKey != "" {
×
604
                        patch[fmt.Sprintf(util.VMAnnotationTemplate, podNet.ProviderName)] = vmName
×
605
                }
×
606
                if err := util.ValidateNetworkBroadcast(podNet.Subnet.Spec.CIDRBlock, ipStr); err != nil {
×
607
                        klog.Errorf("validate pod %s/%s failed: %v", namespace, name, err)
×
608
                        c.recorder.Eventf(pod, v1.EventTypeWarning, "ValidatePodNetworkFailed", err.Error())
×
609
                        return nil, err
×
610
                }
×
611

612
                if podNet.Type != providerTypeIPAM {
×
613
                        if (subnet.Spec.Vlan == "" || subnet.Spec.LogicalGateway || subnet.Spec.U2OInterconnection) && subnet.Spec.Vpc != "" {
×
614
                                patch[fmt.Sprintf(util.LogicalRouterAnnotationTemplate, podNet.ProviderName)] = subnet.Spec.Vpc
×
615
                        }
×
616

617
                        if subnet.Spec.Vlan != "" {
×
618
                                vlan, err := c.vlansLister.Get(subnet.Spec.Vlan)
×
619
                                if err != nil {
×
620
                                        klog.Error(err)
×
621
                                        c.recorder.Eventf(pod, v1.EventTypeWarning, "GetVlanInfoFailed", err.Error())
×
622
                                        return nil, err
×
623
                                }
×
624
                                patch[fmt.Sprintf(util.VlanIDAnnotationTemplate, podNet.ProviderName)] = strconv.Itoa(vlan.Spec.ID)
×
625
                                patch[fmt.Sprintf(util.ProviderNetworkTemplate, podNet.ProviderName)] = vlan.Spec.Provider
×
626
                        }
627

628
                        portSecurity := false
×
629
                        if pod.Annotations[fmt.Sprintf(util.PortSecurityAnnotationTemplate, podNet.ProviderName)] == "true" {
×
630
                                portSecurity = true
×
631
                        }
×
632

633
                        vips := vipsMap[fmt.Sprintf("%s.%s", podNet.Subnet.Name, podNet.ProviderName)]
×
634
                        for ip := range strings.SplitSeq(vips, ",") {
×
635
                                if ip != "" && net.ParseIP(ip) == nil {
×
636
                                        klog.Errorf("invalid vip address '%s' for pod %s", ip, name)
×
637
                                        vips = ""
×
638
                                        break
×
639
                                }
640
                        }
641

642
                        portName := ovs.PodNameToPortName(podName, namespace, podNet.ProviderName)
×
643
                        dhcpOptions := &ovs.DHCPOptionsUUIDs{
×
644
                                DHCPv4OptionsUUID: subnet.Status.DHCPv4OptionsUUID,
×
645
                                DHCPv6OptionsUUID: subnet.Status.DHCPv6OptionsUUID,
×
646
                        }
×
647

×
648
                        var oldSgList []string
×
649
                        if vmKey != "" {
×
650
                                existingLsp, err := c.OVNNbClient.GetLogicalSwitchPort(portName, true)
×
651
                                if err != nil {
×
652
                                        klog.Errorf("failed to get logical switch port %s: %v", portName, err)
×
653
                                        return nil, err
×
654
                                }
×
655
                                if existingLsp != nil {
×
656
                                        oldSgList, _ = c.getPortSg(existingLsp)
×
657
                                }
×
658
                        }
659

660
                        securityGroupAnnotation := pod.Annotations[fmt.Sprintf(util.SecurityGroupAnnotationTemplate, podNet.ProviderName)]
×
661
                        if err := c.OVNNbClient.CreateLogicalSwitchPort(subnet.Name, portName, ipStr, mac, podName, pod.Namespace,
×
662
                                portSecurity, securityGroupAnnotation, vips, podNet.Subnet.Spec.EnableDHCP, dhcpOptions, subnet.Spec.Vpc); err != nil {
×
663
                                c.recorder.Eventf(pod, v1.EventTypeWarning, "CreateOVNPortFailed", err.Error())
×
664
                                klog.Errorf("%v", err)
×
665
                                return nil, err
×
666
                        }
×
667

668
                        if pod.Annotations[fmt.Sprintf(util.Layer2ForwardAnnotationTemplate, podNet.ProviderName)] == "true" {
×
669
                                if err := c.OVNNbClient.EnablePortLayer2forward(portName); err != nil {
×
670
                                        c.recorder.Eventf(pod, v1.EventTypeWarning, "SetOVNPortL2ForwardFailed", err.Error())
×
671
                                        klog.Errorf("%v", err)
×
672
                                        return nil, err
×
673
                                }
×
674
                        }
675

676
                        if securityGroupAnnotation != "" || oldSgList != nil {
×
677
                                securityGroups := strings.ReplaceAll(securityGroupAnnotation, " ", "")
×
678
                                newSgList := strings.Split(securityGroups, ",")
×
679
                                sgNames := util.UnionStringSlice(oldSgList, newSgList)
×
680
                                for _, sgName := range sgNames {
×
681
                                        if sgName != "" {
×
682
                                                c.syncSgPortsQueue.Add(sgName)
×
683
                                        }
×
684
                                }
685
                        }
686

687
                        if vips != "" {
×
688
                                c.syncVirtualPortsQueue.Add(podNet.Subnet.Name)
×
689
                        }
×
690
                }
691
                // CreatePort may fail, so put ip CR creation after CreatePort
692
                ipCRName := ovs.PodNameToPortName(podName, pod.Namespace, podNet.ProviderName)
×
693
                if err := c.createOrUpdateIPCR(ipCRName, podName, ipStr, mac, subnet.Name, pod.Namespace, pod.Spec.NodeName, podType); err != nil {
×
694
                        err = fmt.Errorf("failed to create ips CR %s.%s: %w", podName, pod.Namespace, err)
×
695
                        klog.Error(err)
×
696
                        return nil, err
×
697
                }
×
698
        }
699
        if err = util.PatchAnnotations(c.config.KubeClient.CoreV1().Pods(namespace), name, patch); err != nil {
×
700
                if k8serrors.IsNotFound(err) {
×
701
                        // Sometimes pod is deleted between kube-ovn configure ovn-nb and patch pod.
×
702
                        // Then we need to recycle the resource again.
×
703
                        key := strings.Join([]string{namespace, name}, "/")
×
704
                        c.deletingPodObjMap.Store(key, pod)
×
705
                        c.deletePodQueue.AddRateLimited(key)
×
706
                        return nil, nil
×
707
                }
×
708
                klog.Errorf("failed to patch pod %s/%s: %v", namespace, name, err)
×
709
                return nil, err
×
710
        }
711

712
        if pod, err = c.config.KubeClient.CoreV1().Pods(namespace).Get(context.TODO(), name, metav1.GetOptions{}); err != nil {
×
713
                if k8serrors.IsNotFound(err) {
×
714
                        key := strings.Join([]string{namespace, name}, "/")
×
715
                        c.deletingPodObjMap.Store(key, pod)
×
716
                        c.deletePodQueue.AddRateLimited(key)
×
717
                        return nil, nil
×
718
                }
×
719
                klog.Errorf("failed to get pod %s/%s: %v", namespace, name, err)
×
720
                return nil, err
×
721
        }
722

723
        // Check if pod is a vpc nat gateway. Annotation set will have subnet provider name as prefix
724
        isVpcNatGw, vpcGwName := c.checkIsPodVpcNatGw(pod)
×
725
        if isVpcNatGw {
×
726
                klog.Infof("init vpc nat gateway pod %s/%s with name %s", namespace, name, vpcGwName)
×
727
                c.initVpcNatGatewayQueue.Add(vpcGwName)
×
728
        }
×
729

730
        return pod, nil
×
731
}
732

733
// do the same thing as update pod
734
func (c *Controller) reconcileRouteSubnets(pod *v1.Pod, needRoutePodNets []*kubeovnNet) error {
×
735
        // the lb-svc pod has dependencies on Running state, check it when pod state get updated
×
736
        if err := c.checkAndReInitLbSvcPod(pod); err != nil {
×
737
                klog.Errorf("failed to init iptable rules for load-balancer pod %s/%s: %v", pod.Namespace, pod.Name, err)
×
738
        }
×
739

740
        if len(needRoutePodNets) == 0 {
×
741
                return nil
×
742
        }
×
743

744
        namespace := pod.Namespace
×
745
        name := pod.Name
×
746
        podName := c.getNameByPod(pod)
×
747

×
748
        klog.Infof("sync pod %s/%s routed", namespace, name)
×
749

×
750
        node, err := c.nodesLister.Get(pod.Spec.NodeName)
×
751
        if err != nil {
×
752
                klog.Errorf("failed to get node %s: %v", pod.Spec.NodeName, err)
×
753
                return err
×
754
        }
×
755

756
        portGroups, err := c.OVNNbClient.ListPortGroups(map[string]string{"node": "", networkPolicyKey: ""})
×
757
        if err != nil {
×
758
                klog.Errorf("failed to list port groups: %v", err)
×
759
                return err
×
760
        }
×
761

762
        var nodePortGroups []string
×
763
        nodePortGroup := strings.ReplaceAll(node.Annotations[util.PortNameAnnotation], "-", ".")
×
764
        for _, pg := range portGroups {
×
765
                if pg.Name != nodePortGroup && pg.ExternalIDs["subnet"] == "" {
×
766
                        nodePortGroups = append(nodePortGroups, pg.Name)
×
767
                }
×
768
        }
769

770
        var podIP string
×
771
        var subnet *kubeovnv1.Subnet
×
772
        patch := util.KVPatch{}
×
773
        for _, podNet := range needRoutePodNets {
×
774
                // in case update handler overlap the annotation when cache is not in sync
×
775
                if pod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, podNet.ProviderName)] == "" {
×
776
                        return fmt.Errorf("no address has been allocated to %s/%s", namespace, name)
×
777
                }
×
778

779
                podIP = pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, podNet.ProviderName)]
×
780
                subnet = podNet.Subnet
×
781

×
782
                // Check if pod uses nodeSwitch subnet
×
783
                if subnet.Name == c.config.NodeSwitch {
×
784
                        return fmt.Errorf("NodeSwitch subnet %s is unavailable for pod", subnet.Name)
×
785
                }
×
786

787
                if portGroups, err = c.OVNNbClient.ListPortGroups(map[string]string{"subnet": subnet.Name, "node": "", networkPolicyKey: ""}); err != nil {
×
788
                        klog.Errorf("failed to list port groups: %v", err)
×
789
                        return err
×
790
                }
×
791

792
                pgName := getOverlaySubnetsPortGroupName(subnet.Name, pod.Spec.NodeName)
×
793
                portName := ovs.PodNameToPortName(podName, pod.Namespace, podNet.ProviderName)
×
794
                subnetPortGroups := make([]string, 0, len(portGroups))
×
795
                for _, pg := range portGroups {
×
796
                        if pg.Name != pgName {
×
797
                                subnetPortGroups = append(subnetPortGroups, pg.Name)
×
798
                        }
×
799
                }
800

801
                if (!c.config.EnableLb || (subnet.Spec.EnableLb == nil || !*subnet.Spec.EnableLb)) &&
×
802
                        subnet.Spec.Vpc == c.config.ClusterRouter &&
×
803
                        subnet.Spec.U2OInterconnection &&
×
804
                        subnet.Spec.Vlan != "" &&
×
805
                        !subnet.Spec.LogicalGateway {
×
806
                        // remove lsp from other port groups
×
807
                        // we need to do this because the pod, e.g. a sts/vm, can be rescheduled to another node
×
808
                        if err = c.OVNNbClient.RemovePortFromPortGroups(portName, subnetPortGroups...); err != nil {
×
809
                                klog.Errorf("failed to remove port %s from port groups %v: %v", portName, subnetPortGroups, err)
×
810
                                return err
×
811
                        }
×
812
                        // add lsp to the port group
813
                        if err := c.OVNNbClient.PortGroupAddPorts(pgName, portName); err != nil {
×
814
                                klog.Errorf("failed to add port to u2o port group %s: %v", pgName, err)
×
815
                                return err
×
816
                        }
×
817
                }
818

819
                if podIP != "" && (subnet.Spec.Vlan == "" || subnet.Spec.LogicalGateway) && subnet.Spec.Vpc == c.config.ClusterRouter {
×
820
                        node, err := c.nodesLister.Get(pod.Spec.NodeName)
×
821
                        if err != nil {
×
822
                                klog.Errorf("failed to get node %s: %v", pod.Spec.NodeName, err)
×
823
                                return err
×
824
                        }
×
825

826
                        // remove lsp from other port groups
827
                        // we need to do this because the pod, e.g. a sts/vm, can be rescheduled to another node
828
                        if err = c.OVNNbClient.RemovePortFromPortGroups(portName, nodePortGroups...); err != nil {
×
829
                                klog.Errorf("failed to remove port %s from port groups %v: %v", portName, nodePortGroups, err)
×
830
                                return err
×
831
                        }
×
832
                        // add lsp to the port group
833
                        if err = c.OVNNbClient.PortGroupAddPorts(nodePortGroup, portName); err != nil {
×
834
                                klog.Errorf("failed to add port %s to port group %s: %v", portName, nodePortGroup, err)
×
835
                                return err
×
836
                        }
×
837

838
                        if c.config.EnableEipSnat && (pod.Annotations[util.EipAnnotation] != "" || pod.Annotations[util.SnatAnnotation] != "") {
×
839
                                cm, err := c.configMapsLister.ConfigMaps(c.config.ExternalGatewayConfigNS).Get(util.ExternalGatewayConfig)
×
840
                                if err != nil {
×
841
                                        klog.Errorf("failed to get ex-gateway config, %v", err)
×
842
                                        return err
×
843
                                }
×
844
                                nextHop := cm.Data["external-gw-addr"]
×
845
                                if nextHop == "" {
×
846
                                        externalSubnet, err := c.subnetsLister.Get(c.config.ExternalGatewaySwitch)
×
847
                                        if err != nil {
×
848
                                                klog.Errorf("failed to get subnet %s, %v", c.config.ExternalGatewaySwitch, err)
×
849
                                                return err
×
850
                                        }
×
851
                                        nextHop = externalSubnet.Spec.Gateway
×
852
                                        if nextHop == "" {
×
853
                                                klog.Errorf("no available gateway address")
×
854
                                                return errors.New("no available gateway address")
×
855
                                        }
×
856
                                }
857
                                if strings.Contains(nextHop, "/") {
×
858
                                        nextHop = strings.Split(nextHop, "/")[0]
×
859
                                }
×
860

861
                                if err := c.addPolicyRouteToVpc(
×
862
                                        subnet.Spec.Vpc,
×
863
                                        &kubeovnv1.PolicyRoute{
×
864
                                                Priority:  util.NorthGatewayRoutePolicyPriority,
×
865
                                                Match:     "ip4.src == " + podIP,
×
866
                                                Action:    kubeovnv1.PolicyRouteActionReroute,
×
867
                                                NextHopIP: nextHop,
×
868
                                        },
×
869
                                        map[string]string{
×
870
                                                "vendor": util.CniTypeName,
×
871
                                                "subnet": subnet.Name,
×
872
                                        },
×
873
                                ); err != nil {
×
874
                                        klog.Errorf("failed to add policy route, %v", err)
×
875
                                        return err
×
876
                                }
×
877

878
                                // remove lsp from port group to make EIP/SNAT work
879
                                if err = c.OVNNbClient.PortGroupRemovePorts(pgName, portName); err != nil {
×
880
                                        klog.Error(err)
×
881
                                        return err
×
882
                                }
×
883
                        } else {
×
884
                                if subnet.Spec.GatewayType == kubeovnv1.GWDistributedType && pod.Annotations[util.NorthGatewayAnnotation] == "" {
×
885
                                        nodeTunlIPAddr, err := getNodeTunlIP(node)
×
886
                                        if err != nil {
×
887
                                                klog.Error(err)
×
888
                                                return err
×
889
                                        }
×
890

891
                                        var added bool
×
892
                                        for _, nodeAddr := range nodeTunlIPAddr {
×
893
                                                for podAddr := range strings.SplitSeq(podIP, ",") {
×
894
                                                        if util.CheckProtocol(nodeAddr.String()) != util.CheckProtocol(podAddr) {
×
895
                                                                continue
×
896
                                                        }
897

898
                                                        // remove lsp from other port groups
899
                                                        // we need to do this because the pod, e.g. a sts/vm, can be rescheduled to another node
900
                                                        if err = c.OVNNbClient.RemovePortFromPortGroups(portName, subnetPortGroups...); err != nil {
×
901
                                                                klog.Errorf("failed to remove port %s from port groups %v: %v", portName, subnetPortGroups, err)
×
902
                                                                return err
×
903
                                                        }
×
904
                                                        if err := c.OVNNbClient.PortGroupAddPorts(pgName, portName); err != nil {
×
905
                                                                klog.Errorf("failed to add port %s to port group %s: %v", portName, pgName, err)
×
906
                                                                return err
×
907
                                                        }
×
908

909
                                                        added = true
×
910
                                                        break
×
911
                                                }
912
                                                if added {
×
913
                                                        break
×
914
                                                }
915
                                        }
916
                                }
917

918
                                if pod.Annotations[util.NorthGatewayAnnotation] != "" && pod.Annotations[util.IPAddressAnnotation] != "" {
×
919
                                        for podAddr := range strings.SplitSeq(pod.Annotations[util.IPAddressAnnotation], ",") {
×
920
                                                if util.CheckProtocol(podAddr) != util.CheckProtocol(pod.Annotations[util.NorthGatewayAnnotation]) {
×
921
                                                        continue
×
922
                                                }
923
                                                ipSuffix := "ip4"
×
924
                                                if util.CheckProtocol(podAddr) == kubeovnv1.ProtocolIPv6 {
×
925
                                                        ipSuffix = "ip6"
×
926
                                                }
×
927

928
                                                if err := c.addPolicyRouteToVpc(
×
929
                                                        subnet.Spec.Vpc,
×
930
                                                        &kubeovnv1.PolicyRoute{
×
931
                                                                Priority:  util.NorthGatewayRoutePolicyPriority,
×
932
                                                                Match:     fmt.Sprintf("%s.src == %s", ipSuffix, podAddr),
×
933
                                                                Action:    kubeovnv1.PolicyRouteActionReroute,
×
934
                                                                NextHopIP: pod.Annotations[util.NorthGatewayAnnotation],
×
935
                                                        },
×
936
                                                        map[string]string{
×
937
                                                                "vendor": util.CniTypeName,
×
938
                                                                "subnet": subnet.Name,
×
939
                                                        },
×
940
                                                ); err != nil {
×
941
                                                        klog.Errorf("failed to add policy route, %v", err)
×
942
                                                        return err
×
943
                                                }
×
944
                                        }
945
                                } else if c.config.EnableEipSnat {
×
946
                                        if err = c.deleteStaticRouteFromVpc(
×
947
                                                c.config.ClusterRouter,
×
948
                                                subnet.Spec.RouteTable,
×
949
                                                podIP,
×
950
                                                "",
×
951
                                                kubeovnv1.PolicyDst,
×
952
                                        ); err != nil {
×
953
                                                klog.Error(err)
×
954
                                                return err
×
955
                                        }
×
956
                                }
957
                        }
958

959
                        if c.config.EnableEipSnat {
×
960
                                for ipStr := range strings.SplitSeq(podIP, ",") {
×
961
                                        if eip := pod.Annotations[util.EipAnnotation]; eip == "" {
×
962
                                                if err = c.OVNNbClient.DeleteNats(c.config.ClusterRouter, ovnnb.NATTypeDNATAndSNAT, ipStr); err != nil {
×
963
                                                        klog.Errorf("failed to delete nat rules: %v", err)
×
964
                                                }
×
965
                                        } else if util.CheckProtocol(eip) == util.CheckProtocol(ipStr) {
×
966
                                                if err = c.OVNNbClient.UpdateDnatAndSnat(c.config.ClusterRouter, eip, ipStr, fmt.Sprintf("%s.%s", podName, pod.Namespace), pod.Annotations[util.MacAddressAnnotation], c.ExternalGatewayType); err != nil {
×
967
                                                        klog.Errorf("failed to add nat rules, %v", err)
×
968
                                                        return err
×
969
                                                }
×
970
                                        }
971
                                        if eip := pod.Annotations[util.SnatAnnotation]; eip == "" {
×
972
                                                if err = c.OVNNbClient.DeleteNats(c.config.ClusterRouter, ovnnb.NATTypeSNAT, ipStr); err != nil {
×
973
                                                        klog.Errorf("failed to delete nat rules: %v", err)
×
974
                                                }
×
975
                                        } else if util.CheckProtocol(eip) == util.CheckProtocol(ipStr) {
×
976
                                                if err = c.OVNNbClient.UpdateSnat(c.config.ClusterRouter, eip, ipStr); err != nil {
×
977
                                                        klog.Errorf("failed to add nat rules, %v", err)
×
978
                                                        return err
×
979
                                                }
×
980
                                        }
981
                                }
982
                        }
983
                }
984

985
                if pod.Annotations[fmt.Sprintf(util.ActivationStrategyTemplate, podNet.ProviderName)] != "" {
×
986
                        if err := c.OVNNbClient.SetLogicalSwitchPortActivationStrategy(portName, pod.Spec.NodeName); err != nil {
×
987
                                klog.Errorf("failed to set activation strategy for lsp %s: %v", portName, err)
×
988
                                return err
×
989
                        }
×
990
                }
991

992
                patch[fmt.Sprintf(util.RoutedAnnotationTemplate, podNet.ProviderName)] = "true"
×
993
        }
994
        if err := util.PatchAnnotations(c.config.KubeClient.CoreV1().Pods(namespace), name, patch); err != nil {
×
995
                if k8serrors.IsNotFound(err) {
×
996
                        // Sometimes pod is deleted between kube-ovn configure ovn-nb and patch pod.
×
997
                        // Then we need to recycle the resource again.
×
998
                        key := strings.Join([]string{namespace, name}, "/")
×
999
                        c.deletingPodObjMap.Store(key, pod)
×
1000
                        c.deletePodQueue.AddRateLimited(key)
×
1001
                        return nil
×
1002
                }
×
1003
                klog.Errorf("failed to patch pod %s/%s: %v", namespace, name, err)
×
1004
                return err
×
1005
        }
1006
        return nil
×
1007
}
1008

1009
func (c *Controller) handleDeletePod(key string) (err error) {
×
1010
        pod, ok := c.deletingPodObjMap.Load(key)
×
1011
        if !ok {
×
1012
                return nil
×
1013
        }
×
1014
        now := time.Now()
×
1015
        klog.Infof("handle delete pod %s", key)
×
1016
        podName := c.getNameByPod(pod)
×
1017
        c.podKeyMutex.LockKey(key)
×
1018
        defer func() {
×
1019
                _ = c.podKeyMutex.UnlockKey(key)
×
1020
                if err == nil {
×
1021
                        c.deletingPodObjMap.Delete(key)
×
1022
                }
×
1023
                last := time.Since(now)
×
1024
                klog.Infof("take %d ms to handle delete pod %s", last.Milliseconds(), key)
×
1025
        }()
1026

1027
        p, _ := c.podsLister.Pods(pod.Namespace).Get(pod.Name)
×
1028
        if p != nil && p.UID != pod.UID {
×
1029
                // Pod with same name exists, just return here
×
1030
                return nil
×
1031
        }
×
1032

1033
        if aaps := pod.Annotations[util.AAPsAnnotation]; aaps != "" {
×
1034
                for vipName := range strings.SplitSeq(aaps, ",") {
×
1035
                        if vip, err := c.virtualIpsLister.Get(vipName); err == nil {
×
1036
                                if vip.Spec.Namespace != pod.Namespace {
×
1037
                                        continue
×
1038
                                }
1039
                                klog.Infof("enqueue update virtual parents for %s", vipName)
×
1040
                                c.updateVirtualParentsQueue.Add(vipName)
×
1041
                        }
1042
                }
1043
        }
1044

1045
        podKey := fmt.Sprintf("%s/%s", pod.Namespace, podName)
×
1046

×
1047
        var keepIPCR, isOwnerRefToDel, isOwnerRefDeleted bool
×
1048
        var ipcrToDelete []string
×
1049
        isStsPod, stsName, stsUID := isStatefulSetPod(pod)
×
1050
        if isStsPod {
×
1051
                if !pod.DeletionTimestamp.IsZero() {
×
1052
                        klog.Infof("handle deletion of sts pod %s", podKey)
×
1053
                        isOwnerRefToDel = isStatefulSetPodToDel(c.config.KubeClient, pod, stsName, stsUID)
×
1054
                        if !isOwnerRefToDel {
×
1055
                                klog.Infof("try keep ip for sts pod %s", podKey)
×
1056
                                keepIPCR = true
×
1057
                        }
×
1058
                }
1059
                if keepIPCR {
×
1060
                        isOwnerRefDeleted, ipcrToDelete, err = appendCheckPodNetToDel(c, pod, stsName, util.KindStatefulSet)
×
1061
                        if err != nil {
×
1062
                                klog.Error(err)
×
1063
                                return err
×
1064
                        }
×
1065
                        if isOwnerRefDeleted || len(ipcrToDelete) != 0 {
×
1066
                                klog.Infof("not keep ip for sts pod %s", podKey)
×
1067
                                keepIPCR = false
×
1068
                        }
×
1069
                }
1070
        }
1071
        isVMPod, vmName := isVMPod(pod)
×
1072
        if isVMPod && c.config.EnableKeepVMIP {
×
1073
                ports, err := c.OVNNbClient.ListNormalLogicalSwitchPorts(true, map[string]string{"pod": podKey})
×
1074
                if err != nil {
×
1075
                        klog.Errorf("failed to list lsps of pod %s: %v", podKey, err)
×
1076
                        return err
×
1077
                }
×
1078
                for _, port := range ports {
×
1079
                        if err := c.OVNNbClient.CleanLogicalSwitchPortMigrateOptions(port.Name); err != nil {
×
1080
                                err = fmt.Errorf("failed to clean migrate options for vm lsp %s, %w", port.Name, err)
×
1081
                                klog.Error(err)
×
1082
                                return err
×
1083
                        }
×
1084
                }
1085
                if pod.DeletionTimestamp != nil {
×
1086
                        klog.Infof("handle deletion of vm pod %s", podKey)
×
1087
                        isOwnerRefToDel = c.isVMToDel(pod, vmName)
×
1088
                        if !isOwnerRefToDel {
×
1089
                                klog.Infof("try keep ip for vm pod %s", podKey)
×
1090
                                keepIPCR = true
×
1091
                        }
×
1092
                }
1093
                if keepIPCR {
×
1094
                        isOwnerRefDeleted, ipcrToDelete, err = appendCheckPodNetToDel(c, pod, vmName, util.KindVirtualMachineInstance)
×
1095
                        if err != nil {
×
1096
                                klog.Error(err)
×
1097
                                return err
×
1098
                        }
×
1099
                        if isOwnerRefDeleted || len(ipcrToDelete) != 0 {
×
1100
                                klog.Infof("not keep ip for vm pod %s", podKey)
×
1101
                                keepIPCR = false
×
1102
                        }
×
1103
                }
1104
        }
1105

1106
        podNets, err := c.getPodKubeovnNets(pod)
×
1107
        if err != nil {
×
1108
                klog.Errorf("failed to get kube-ovn nets of pod %s: %v", podKey, err)
×
1109
        }
×
1110
        ports, err := c.OVNNbClient.ListNormalLogicalSwitchPorts(true, map[string]string{"pod": podKey})
×
1111
        if err != nil {
×
1112
                klog.Errorf("failed to list lsps of pod %s: %v", podKey, err)
×
1113
                return err
×
1114
        }
×
1115
        if keepIPCR {
×
1116
                // always remove lsp from port groups
×
1117
                for _, port := range ports {
×
1118
                        klog.Infof("remove lsp %s from all port groups", port.Name)
×
1119
                        if err = c.OVNNbClient.RemovePortFromPortGroups(port.Name); err != nil {
×
1120
                                klog.Errorf("failed to remove lsp %s from all port groups: %v", port.Name, err)
×
1121
                                return err
×
1122
                        }
×
1123
                }
1124
        } else {
×
1125
                if len(ports) != 0 {
×
1126
                        addresses := c.ipam.GetPodAddress(podKey)
×
1127
                        for _, address := range addresses {
×
1128
                                if strings.TrimSpace(address.IP) == "" {
×
1129
                                        continue
×
1130
                                }
1131
                                subnet, err := c.subnetsLister.Get(address.Subnet.Name)
×
1132
                                if k8serrors.IsNotFound(err) {
×
1133
                                        continue
×
1134
                                } else if err != nil {
×
1135
                                        klog.Error(err)
×
1136
                                        return err
×
1137
                                }
×
1138
                                vpc, err := c.vpcsLister.Get(subnet.Spec.Vpc)
×
1139
                                if k8serrors.IsNotFound(err) {
×
1140
                                        continue
×
1141
                                } else if err != nil {
×
1142
                                        klog.Error(err)
×
1143
                                        return err
×
1144
                                }
×
1145

1146
                                ipSuffix := "ip4"
×
1147
                                if util.CheckProtocol(address.IP) == kubeovnv1.ProtocolIPv6 {
×
1148
                                        ipSuffix = "ip6"
×
1149
                                }
×
1150
                                if err = c.deletePolicyRouteFromVpc(
×
1151
                                        vpc.Name,
×
1152
                                        util.NorthGatewayRoutePolicyPriority,
×
1153
                                        fmt.Sprintf("%s.src == %s", ipSuffix, address.IP),
×
1154
                                ); err != nil {
×
1155
                                        klog.Errorf("failed to delete static route, %v", err)
×
1156
                                        return err
×
1157
                                }
×
1158

1159
                                if c.config.EnableEipSnat {
×
1160
                                        if pod.Annotations[util.EipAnnotation] != "" {
×
1161
                                                if err = c.OVNNbClient.DeleteNat(c.config.ClusterRouter, ovnnb.NATTypeDNATAndSNAT, pod.Annotations[util.EipAnnotation], address.IP); err != nil {
×
1162
                                                        klog.Errorf("failed to delete nat rules: %v", err)
×
1163
                                                }
×
1164
                                        }
1165
                                        if pod.Annotations[util.SnatAnnotation] != "" {
×
1166
                                                if err = c.OVNNbClient.DeleteNat(c.config.ClusterRouter, ovnnb.NATTypeSNAT, "", address.IP); err != nil {
×
1167
                                                        klog.Errorf("failed to delete nat rules: %v", err)
×
1168
                                                }
×
1169
                                        }
1170
                                }
1171
                        }
1172
                }
1173
                for _, port := range ports {
×
1174
                        // when lsp is deleted, the port of pod is deleted from any port-group automatically.
×
1175
                        klog.Infof("delete logical switch port %s", port.Name)
×
1176
                        if err := c.OVNNbClient.DeleteLogicalSwitchPort(port.Name); err != nil {
×
1177
                                klog.Errorf("failed to delete lsp %s, %v", port.Name, err)
×
1178
                                return err
×
1179
                        }
×
1180
                }
1181
                klog.Infof("try release all ip address for deleting pod %s", podKey)
×
1182
                for _, podNet := range podNets {
×
1183
                        portName := ovs.PodNameToPortName(podName, pod.Namespace, podNet.ProviderName)
×
1184
                        // if the OwnerRef has been deleted or is in the process of being deleted, all associated IPCRs must be cleaned up
×
1185
                        if (isStsPod || isVMPod) && !isOwnerRefToDel && !isOwnerRefDeleted &&
×
1186
                                !slices.Contains(ipcrToDelete, portName) {
×
1187
                                klog.Infof("skip clean ip CR %s", portName)
×
1188
                                continue
×
1189
                        }
1190
                        ipCR, err := c.ipsLister.Get(portName)
×
1191
                        if err != nil {
×
1192
                                if k8serrors.IsNotFound(err) {
×
1193
                                        continue
×
1194
                                }
1195
                                klog.Errorf("failed to get ip %s, %v", portName, err)
×
1196
                                return err
×
1197
                        }
1198
                        if ipCR.Labels[util.IPReservedLabel] != "true" {
×
1199
                                klog.Infof("delete ip CR %s", ipCR.Name)
×
1200
                                if err := c.config.KubeOvnClient.KubeovnV1().IPs().Delete(context.Background(), ipCR.Name, metav1.DeleteOptions{}); err != nil {
×
1201
                                        if !k8serrors.IsNotFound(err) {
×
1202
                                                klog.Errorf("failed to delete ip %s, %v", ipCR.Name, err)
×
1203
                                                return err
×
1204
                                        }
×
1205
                                }
1206
                                // release ipam address after delete ip CR
1207
                                c.ipam.ReleaseAddressByNic(podKey, portName, podNet.Subnet.Name)
×
1208
                                // Trigger subnet status update after IPAM release
×
1209
                                // This is needed when IP CR is deleted without finalizer (race condition)
×
1210
                                c.updateSubnetStatusQueue.Add(podNet.Subnet.Name)
×
1211
                        }
1212
                }
1213
                if pod.Annotations[util.VipAnnotation] != "" {
×
1214
                        if err = c.releaseVip(pod.Annotations[util.VipAnnotation]); err != nil {
×
1215
                                klog.Errorf("failed to clean label from vip %s, %v", pod.Annotations[util.VipAnnotation], err)
×
1216
                                return err
×
1217
                        }
×
1218
                }
1219
        }
1220
        for _, podNet := range podNets {
×
1221
                // Skip non-OVN subnets for security group synchronization
×
1222
                if !isOvnSubnet(podNet.Subnet) {
×
1223
                        continue
×
1224
                }
1225

1226
                c.syncVirtualPortsQueue.Add(podNet.Subnet.Name)
×
1227
                securityGroupAnnotation := pod.Annotations[fmt.Sprintf(util.SecurityGroupAnnotationTemplate, podNet.ProviderName)]
×
1228
                if securityGroupAnnotation != "" {
×
1229
                        securityGroups := strings.ReplaceAll(securityGroupAnnotation, " ", "")
×
1230
                        for sgName := range strings.SplitSeq(securityGroups, ",") {
×
1231
                                if sgName != "" {
×
1232
                                        c.syncSgPortsQueue.Add(sgName)
×
1233
                                }
×
1234
                        }
1235
                }
1236
        }
1237
        return nil
×
1238
}
1239

1240
func (c *Controller) handleUpdatePodSecurity(key string) error {
×
1241
        now := time.Now()
×
1242
        klog.Infof("handle add/update pod security group %s", key)
×
1243

×
1244
        namespace, name, err := cache.SplitMetaNamespaceKey(key)
×
1245
        if err != nil {
×
1246
                utilruntime.HandleError(fmt.Errorf("invalid resource key: %s", key))
×
1247
                return nil
×
1248
        }
×
1249

1250
        c.podKeyMutex.LockKey(key)
×
1251
        defer func() {
×
1252
                _ = c.podKeyMutex.UnlockKey(key)
×
1253
                last := time.Since(now)
×
1254
                klog.Infof("take %d ms to handle sg for pod %s", last.Milliseconds(), key)
×
1255
        }()
×
1256

1257
        pod, err := c.podsLister.Pods(namespace).Get(name)
×
1258
        if err != nil {
×
1259
                if k8serrors.IsNotFound(err) {
×
1260
                        return nil
×
1261
                }
×
1262
                klog.Error(err)
×
1263
                return err
×
1264
        }
1265
        podName := c.getNameByPod(pod)
×
1266

×
1267
        podNets, err := c.getPodKubeovnNets(pod)
×
1268
        if err != nil {
×
1269
                klog.Errorf("failed to pod nets %v", err)
×
1270
                return err
×
1271
        }
×
1272

1273
        vipsMap := c.getVirtualIPs(pod, podNets)
×
1274

×
1275
        // associated with security group
×
1276
        for _, podNet := range podNets {
×
1277
                // Skip non-OVN subnets (e.g., macvlan) that don't create OVN logical switch ports
×
1278
                if !isOvnSubnet(podNet.Subnet) {
×
1279
                        continue
×
1280
                }
1281

1282
                portSecurity := false
×
1283
                if pod.Annotations[fmt.Sprintf(util.PortSecurityAnnotationTemplate, podNet.ProviderName)] == "true" {
×
1284
                        portSecurity = true
×
1285
                }
×
1286

1287
                mac := pod.Annotations[fmt.Sprintf(util.MacAddressAnnotationTemplate, podNet.ProviderName)]
×
1288
                ipStr := pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, podNet.ProviderName)]
×
1289
                vips := vipsMap[fmt.Sprintf("%s.%s", podNet.Subnet.Name, podNet.ProviderName)]
×
1290
                portName := ovs.PodNameToPortName(podName, namespace, podNet.ProviderName)
×
1291
                if err = c.OVNNbClient.SetLogicalSwitchPortSecurity(portSecurity, portName, mac, ipStr, vips); err != nil {
×
1292
                        klog.Errorf("failed to set security for logical switch port %s: %v", portName, err)
×
1293
                        return err
×
1294
                }
×
1295

1296
                c.syncVirtualPortsQueue.Add(podNet.Subnet.Name)
×
1297
                securityGroupAnnotation := pod.Annotations[fmt.Sprintf(util.SecurityGroupAnnotationTemplate, podNet.ProviderName)]
×
1298
                var securityGroups string
×
1299
                if securityGroupAnnotation != "" {
×
1300
                        securityGroups = strings.ReplaceAll(securityGroupAnnotation, " ", "")
×
1301
                        for sgName := range strings.SplitSeq(securityGroups, ",") {
×
1302
                                if sgName != "" {
×
1303
                                        c.syncSgPortsQueue.Add(sgName)
×
1304
                                }
×
1305
                        }
1306
                }
1307
                if err = c.reconcilePortSg(portName, securityGroups); err != nil {
×
1308
                        klog.Errorf("reconcilePortSg failed. %v", err)
×
1309
                        return err
×
1310
                }
×
1311
        }
1312
        return nil
×
1313
}
1314

1315
func (c *Controller) syncKubeOvnNet(pod *v1.Pod, podNets []*kubeovnNet) (*v1.Pod, error) {
×
1316
        podName := c.getNameByPod(pod)
×
1317
        key := cache.NewObjectName(pod.Namespace, podName).String()
×
1318
        targetPortNameList := strset.NewWithSize(len(podNets))
×
1319
        portsNeedToDel := []string{}
×
1320
        annotationsNeedToDel := []string{}
×
1321
        annotationsNeedToAdd := make(map[string]string)
×
1322
        subnetUsedByPort := make(map[string]string)
×
1323

×
1324
        for _, podNet := range podNets {
×
1325
                portName := ovs.PodNameToPortName(podName, pod.Namespace, podNet.ProviderName)
×
1326
                targetPortNameList.Add(portName)
×
1327
                if podNet.IPRequest != "" {
×
1328
                        klog.Infof("pod %s/%s use custom IP %s for provider %s", pod.Namespace, pod.Name, podNet.IPRequest, podNet.ProviderName)
×
1329
                        annotationsNeedToAdd[fmt.Sprintf(util.IPAddressAnnotationTemplate, podNet.ProviderName)] = podNet.IPRequest
×
1330
                }
×
1331

1332
                if podNet.MacRequest != "" {
×
1333
                        klog.Infof("pod %s/%s use custom MAC %s for provider %s", pod.Namespace, pod.Name, podNet.MacRequest, podNet.ProviderName)
×
1334
                        annotationsNeedToAdd[fmt.Sprintf(util.MacAddressAnnotationTemplate, podNet.ProviderName)] = podNet.MacRequest
×
1335
                }
×
1336
        }
1337

1338
        ports, err := c.OVNNbClient.ListNormalLogicalSwitchPorts(true, map[string]string{"pod": key})
×
1339
        if err != nil {
×
1340
                klog.Errorf("failed to list lsps of pod '%s', %v", pod.Name, err)
×
1341
                return nil, err
×
1342
        }
×
1343

1344
        for _, port := range ports {
×
1345
                if !targetPortNameList.Has(port.Name) {
×
1346
                        portsNeedToDel = append(portsNeedToDel, port.Name)
×
1347
                        subnetUsedByPort[port.Name] = port.ExternalIDs["ls"]
×
1348
                        portNameSlice := strings.Split(port.Name, ".")
×
1349
                        providerName := strings.Join(portNameSlice[2:], ".")
×
1350
                        if providerName == util.OvnProvider {
×
1351
                                continue
×
1352
                        }
1353
                        annotationsNeedToDel = append(annotationsNeedToDel, providerName)
×
1354
                }
1355
        }
1356

1357
        if len(portsNeedToDel) == 0 && len(annotationsNeedToAdd) == 0 {
×
1358
                return pod, nil
×
1359
        }
×
1360

1361
        for _, portNeedDel := range portsNeedToDel {
×
1362
                klog.Infof("release port %s for pod %s", portNeedDel, podName)
×
1363
                if subnet, ok := c.ipam.Subnets[subnetUsedByPort[portNeedDel]]; ok {
×
1364
                        subnet.ReleaseAddressWithNicName(podName, portNeedDel)
×
1365
                }
×
1366
                if err := c.OVNNbClient.DeleteLogicalSwitchPort(portNeedDel); err != nil {
×
1367
                        klog.Errorf("failed to delete lsp %s, %v", portNeedDel, err)
×
1368
                        return nil, err
×
1369
                }
×
1370
                if err := c.config.KubeOvnClient.KubeovnV1().IPs().Delete(context.Background(), portNeedDel, metav1.DeleteOptions{}); err != nil {
×
1371
                        if !k8serrors.IsNotFound(err) {
×
1372
                                klog.Errorf("failed to delete ip %s, %v", portNeedDel, err)
×
1373
                                return nil, err
×
1374
                        }
×
1375
                }
1376
        }
1377

1378
        patch := util.KVPatch{}
×
1379
        for _, providerName := range annotationsNeedToDel {
×
1380
                for key := range pod.Annotations {
×
1381
                        if strings.HasPrefix(key, providerName) {
×
1382
                                patch[key] = nil
×
1383
                        }
×
1384
                }
1385
        }
1386

1387
        for key, value := range annotationsNeedToAdd {
×
1388
                patch[key] = value
×
1389
        }
×
1390

1391
        if len(patch) == 0 {
×
1392
                return pod, nil
×
1393
        }
×
1394

1395
        if err = util.PatchAnnotations(c.config.KubeClient.CoreV1().Pods(pod.Namespace), pod.Name, patch); err != nil {
×
1396
                if k8serrors.IsNotFound(err) {
×
1397
                        return nil, nil
×
1398
                }
×
1399
                klog.Errorf("failed to clean annotations for pod %s/%s: %v", pod.Namespace, pod.Name, err)
×
1400
                return nil, err
×
1401
        }
1402

1403
        if pod, err = c.config.KubeClient.CoreV1().Pods(pod.Namespace).Get(context.TODO(), pod.Name, metav1.GetOptions{}); err != nil {
×
1404
                if k8serrors.IsNotFound(err) {
×
1405
                        return nil, nil
×
1406
                }
×
1407
                klog.Errorf("failed to get pod %s/%s: %v", pod.Namespace, pod.Name, err)
×
1408
                return nil, err
×
1409
        }
1410

1411
        return pod, nil
×
1412
}
1413

1414
func isStatefulSetPod(pod *v1.Pod) (bool, string, types.UID) {
1✔
1415
        for _, owner := range pod.OwnerReferences {
1✔
1416
                if owner.Kind == util.KindStatefulSet && strings.HasPrefix(owner.APIVersion, appsv1.SchemeGroupVersion.Group+"/") {
×
1417
                        if strings.HasPrefix(pod.Name, owner.Name) {
×
1418
                                return true, owner.Name, owner.UID
×
1419
                        }
×
1420
                }
1421
        }
1422
        return false, "", ""
1✔
1423
}
1424

1425
func isStatefulSetPodToDel(c kubernetes.Interface, pod *v1.Pod, statefulSetName string, statefulSetUID types.UID) bool {
×
1426
        // only delete statefulset pod lsp when statefulset deleted or down scaled
×
1427
        sts, err := c.AppsV1().StatefulSets(pod.Namespace).Get(context.Background(), statefulSetName, metav1.GetOptions{})
×
1428
        if err != nil {
×
1429
                // statefulset is deleted
×
1430
                if k8serrors.IsNotFound(err) {
×
1431
                        klog.Infof("statefulset %s/%s has been deleted", pod.Namespace, statefulSetName)
×
1432
                        return true
×
1433
                }
×
1434
                klog.Errorf("failed to get statefulset %s/%s: %v", pod.Namespace, statefulSetName, err)
×
1435
                return false
×
1436
        }
1437

1438
        // statefulset is being deleted, or it's a newly created one
1439
        if !sts.DeletionTimestamp.IsZero() {
×
1440
                klog.Infof("statefulset %s/%s is being deleted", pod.Namespace, statefulSetName)
×
1441
                return true
×
1442
        }
×
1443
        if sts.UID != statefulSetUID {
×
1444
                klog.Infof("statefulset %s/%s is a newly created one", pod.Namespace, statefulSetName)
×
1445
                return true
×
1446
        }
×
1447

1448
        // down scale statefulset
1449
        tempStrs := strings.Split(pod.Name, "-")
×
1450
        numStr := tempStrs[len(tempStrs)-1]
×
1451
        index, err := strconv.ParseInt(numStr, 10, 0)
×
1452
        if err != nil {
×
1453
                klog.Errorf("failed to parse %s to int", numStr)
×
1454
                return false
×
1455
        }
×
1456
        // down scaled
1457
        var startOrdinal int64
×
1458
        if sts.Spec.Ordinals != nil {
×
1459
                startOrdinal = int64(sts.Spec.Ordinals.Start)
×
1460
        }
×
1461
        if index >= startOrdinal+int64(*sts.Spec.Replicas) {
×
1462
                klog.Infof("statefulset %s/%s is down scaled", pod.Namespace, statefulSetName)
×
1463
                return true
×
1464
        }
×
1465
        return false
×
1466
}
1467

1468
// only gc statefulset pod lsp when:
1469
// 1. the statefulset has been deleted or is being deleted
1470
// 2. the statefulset has been deleted and recreated
1471
// 3. the statefulset is down scaled and the pod is not alive
1472
func isStatefulSetPodToGC(c kubernetes.Interface, pod *v1.Pod, statefulSetName string, statefulSetUID types.UID) bool {
×
1473
        sts, err := c.AppsV1().StatefulSets(pod.Namespace).Get(context.Background(), statefulSetName, metav1.GetOptions{})
×
1474
        if err != nil {
×
1475
                // the statefulset has been deleted
×
1476
                if k8serrors.IsNotFound(err) {
×
1477
                        klog.Infof("statefulset %s/%s has been deleted", pod.Namespace, statefulSetName)
×
1478
                        return true
×
1479
                }
×
1480
                klog.Errorf("failed to get statefulset %s/%s: %v", pod.Namespace, statefulSetName, err)
×
1481
                return false
×
1482
        }
1483

1484
        // statefulset is being deleted
1485
        if !sts.DeletionTimestamp.IsZero() {
×
1486
                klog.Infof("statefulset %s/%s is being deleted", pod.Namespace, statefulSetName)
×
1487
                return true
×
1488
        }
×
1489
        // the statefulset has been deleted and recreated
1490
        if sts.UID != statefulSetUID {
×
1491
                klog.Infof("statefulset %s/%s is a newly created one", pod.Namespace, statefulSetName)
×
1492
                return true
×
1493
        }
×
1494

1495
        // the statefulset is down scaled and the pod is not alive
1496

1497
        tempStrs := strings.Split(pod.Name, "-")
×
1498
        numStr := tempStrs[len(tempStrs)-1]
×
1499
        index, err := strconv.ParseInt(numStr, 10, 0)
×
1500
        if err != nil {
×
1501
                klog.Errorf("failed to parse %s to int", numStr)
×
1502
                return false
×
1503
        }
×
1504
        // down scaled
1505
        var startOrdinal int64
×
1506
        if sts.Spec.Ordinals != nil {
×
1507
                startOrdinal = int64(sts.Spec.Ordinals.Start)
×
1508
        }
×
1509
        if index >= startOrdinal+int64(*sts.Spec.Replicas) {
×
1510
                klog.Infof("statefulset %s/%s is down scaled", pod.Namespace, statefulSetName)
×
1511
                if !isPodAlive(pod) {
×
1512
                        // we must check whether the pod is alive because we have to consider the following case:
×
1513
                        // 1. the statefulset is down scaled to zero
×
1514
                        // 2. the lsp gc is triggered
×
1515
                        // 3. gc interval, e.g. 90s, is passed and the second gc is triggered
×
1516
                        // 4. the sts is up scaled to the original replicas
×
1517
                        // 5. the pod is still running and it will not be recreated
×
1518
                        return true
×
1519
                }
×
1520
        }
1521

1522
        return false
×
1523
}
1524

1525
func getNodeTunlIP(node *v1.Node) ([]net.IP, error) {
×
1526
        var nodeTunlIPAddr []net.IP
×
1527
        nodeTunlIP := node.Annotations[util.IPAddressAnnotation]
×
1528
        if nodeTunlIP == "" {
×
1529
                return nil, errors.New("node has no tunnel ip annotation")
×
1530
        }
×
1531

1532
        for ip := range strings.SplitSeq(nodeTunlIP, ",") {
×
1533
                nodeTunlIPAddr = append(nodeTunlIPAddr, net.ParseIP(ip))
×
1534
        }
×
1535
        return nodeTunlIPAddr, nil
×
1536
}
1537

1538
func getNextHopByTunnelIP(gw []net.IP) string {
×
1539
        // validation check by caller
×
1540
        nextHop := gw[0].String()
×
1541
        if len(gw) == 2 {
×
1542
                nextHop = gw[0].String() + "," + gw[1].String()
×
1543
        }
×
1544
        return nextHop
×
1545
}
1546

1547
func needAllocateSubnets(pod *v1.Pod, nets []*kubeovnNet) []*kubeovnNet {
×
1548
        // check if allocate from subnet is need.
×
1549
        // allocate subnet when change subnet to hotplug nic
×
1550
        // allocate subnet when migrate vm
×
1551
        if !isPodAlive(pod) {
×
1552
                return nil
×
1553
        }
×
1554

1555
        if pod.Annotations == nil {
×
1556
                return nets
×
1557
        }
×
1558

1559
        migrate := false
×
1560
        if job, ok := pod.Annotations[kubevirtv1.MigrationJobNameAnnotation]; ok {
×
1561
                klog.Infof("pod %s/%s is in the migration job %s", pod.Namespace, pod.Name, job)
×
1562
                migrate = true
×
1563
        }
×
1564

1565
        result := make([]*kubeovnNet, 0, len(nets))
×
1566
        for _, n := range nets {
×
1567
                if migrate || pod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, n.ProviderName)] != "true" {
×
1568
                        result = append(result, n)
×
1569
                }
×
1570
        }
1571
        return result
×
1572
}
1573

1574
func needRestartNatGatewayPod(pod *v1.Pod) bool {
×
1575
        for _, psc := range pod.Status.ContainerStatuses {
×
1576
                if psc.Name != "vpc-nat-gw" {
×
1577
                        continue
×
1578
                }
1579
                if psc.RestartCount > 0 {
×
1580
                        return true
×
1581
                }
×
1582
        }
1583
        return false
×
1584
}
1585

1586
func (c *Controller) podNeedSync(pod *v1.Pod) (bool, error) {
×
1587
        // 1. check annotations
×
1588
        if pod.Annotations == nil {
×
1589
                return true, nil
×
1590
        }
×
1591
        // 2. check annotation ovn subnet
1592
        if pod.Annotations[util.RoutedAnnotation] != "true" {
×
1593
                return true, nil
×
1594
        }
×
1595
        // 3. check multus subnet
1596
        attachmentNets, err := c.getPodAttachmentNet(pod)
×
1597
        if err != nil {
×
1598
                klog.Error(err)
×
1599
                return false, err
×
1600
        }
×
1601

1602
        podName := c.getNameByPod(pod)
×
1603
        for _, n := range attachmentNets {
×
1604
                if pod.Annotations[fmt.Sprintf(util.RoutedAnnotationTemplate, n.ProviderName)] != "true" {
×
1605
                        return true, nil
×
1606
                }
×
1607
                ipName := ovs.PodNameToPortName(podName, pod.Namespace, n.ProviderName)
×
1608
                if _, err = c.ipsLister.Get(ipName); err != nil {
×
1609
                        if !k8serrors.IsNotFound(err) {
×
1610
                                err = fmt.Errorf("failed to get ip %s: %w", ipName, err)
×
1611
                                klog.Error(err)
×
1612
                                return false, err
×
1613
                        }
×
1614
                        klog.Infof("ip %s not found", ipName)
×
1615
                        // need to sync to create ip
×
1616
                        return true, nil
×
1617
                }
1618
        }
1619
        return false, nil
×
1620
}
1621

1622
func needRouteSubnets(pod *v1.Pod, nets []*kubeovnNet) []*kubeovnNet {
×
1623
        if !isPodAlive(pod) {
×
1624
                return nil
×
1625
        }
×
1626

1627
        if pod.Annotations == nil {
×
1628
                return nets
×
1629
        }
×
1630

1631
        result := make([]*kubeovnNet, 0, len(nets))
×
1632
        for _, n := range nets {
×
1633
                if !isOvnSubnet(n.Subnet) {
×
1634
                        continue
×
1635
                }
1636

1637
                if pod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, n.ProviderName)] == "true" && pod.Spec.NodeName != "" {
×
1638
                        if pod.Annotations[fmt.Sprintf(util.RoutedAnnotationTemplate, n.ProviderName)] != "true" {
×
1639
                                result = append(result, n)
×
1640
                        }
×
1641
                }
1642
        }
1643
        return result
×
1644
}
1645

1646
func (c *Controller) getPodDefaultSubnet(pod *v1.Pod) (*kubeovnv1.Subnet, error) {
1✔
1647
        // ignore to clean its ip crd in existing subnets
1✔
1648
        ignoreSubnetNotExist := !pod.DeletionTimestamp.IsZero()
1✔
1649

1✔
1650
        // check pod annotations
1✔
1651
        if lsName := pod.Annotations[util.LogicalSwitchAnnotation]; lsName != "" {
2✔
1652
                // annotations only has one default subnet
1✔
1653
                subnet, err := c.subnetsLister.Get(lsName)
1✔
1654
                if err != nil {
1✔
1655
                        klog.Errorf("failed to get subnet %s: %v", lsName, err)
×
1656
                        if k8serrors.IsNotFound(err) {
×
1657
                                if ignoreSubnetNotExist {
×
1658
                                        klog.Errorf("deleting pod %s/%s default subnet %s already not exist, gc will clean its ip cr", pod.Namespace, pod.Name, lsName)
×
1659
                                        return nil, nil
×
1660
                                }
×
1661
                        }
1662
                        return nil, err
×
1663
                }
1664
                return subnet, nil
1✔
1665
        }
1666

1667
        ns, err := c.namespacesLister.Get(pod.Namespace)
1✔
1668
        if err != nil {
1✔
1669
                klog.Errorf("failed to get namespace %s: %v", pod.Namespace, err)
×
1670
                return nil, err
×
1671
        }
×
1672
        if len(ns.Annotations) == 0 {
1✔
1673
                err = fmt.Errorf("namespace %s network annotations is empty", ns.Name)
×
1674
                klog.Error(err)
×
1675
                return nil, err
×
1676
        }
×
1677

1678
        subnetNames := ns.Annotations[util.LogicalSwitchAnnotation]
1✔
1679
        for subnetName := range strings.SplitSeq(subnetNames, ",") {
2✔
1680
                if subnetName == "" {
1✔
1681
                        err = fmt.Errorf("namespace %s default logical switch is not found", ns.Name)
×
1682
                        klog.Error(err)
×
1683
                        return nil, err
×
1684
                }
×
1685
                subnet, err := c.subnetsLister.Get(subnetName)
1✔
1686
                if err != nil {
1✔
1687
                        klog.Errorf("failed to get subnet %s: %v", subnetName, err)
×
1688
                        if k8serrors.IsNotFound(err) {
×
1689
                                if ignoreSubnetNotExist {
×
1690
                                        klog.Errorf("deleting pod %s/%s namespace subnet %s already not exist, gc will clean its ip cr", pod.Namespace, pod.Name, subnetName)
×
1691
                                        // ip name is unique, it is ok if any subnet release it
×
1692
                                        // gc will handle their ip cr, if all subnets are not exist
×
1693
                                        continue
×
1694
                                }
1695
                        }
1696
                        return nil, err
×
1697
                }
1698

1699
                switch subnet.Spec.Protocol {
1✔
1700
                case kubeovnv1.ProtocolDual:
×
1701
                        if subnet.Status.V6AvailableIPs == 0 && !c.podCanUseExcludeIPs(pod, subnet) {
×
1702
                                klog.Infof("there's no available ipv6 address in subnet %s, try next one", subnet.Name)
×
1703
                                continue
×
1704
                        }
1705
                        fallthrough
×
1706
                case kubeovnv1.ProtocolIPv4:
1✔
1707
                        if subnet.Status.V4AvailableIPs == 0 && !c.podCanUseExcludeIPs(pod, subnet) {
1✔
1708
                                klog.Infof("there's no available ipv4 address in subnet %s, try next one", subnet.Name)
×
1709
                                continue
×
1710
                        }
1711
                case kubeovnv1.ProtocolIPv6:
×
1712
                        if subnet.Status.V6AvailableIPs == 0 && !c.podCanUseExcludeIPs(pod, subnet) {
×
1713
                                klog.Infof("there's no available ipv6 address in subnet %s, try next one", subnet.Name)
×
1714
                                continue
×
1715
                        }
1716
                }
1717
                return subnet, nil
1✔
1718
        }
1719
        return nil, ipam.ErrNoAvailable
×
1720
}
1721

1722
func (c *Controller) podCanUseExcludeIPs(pod *v1.Pod, subnet *kubeovnv1.Subnet) bool {
×
1723
        if ipAddr := pod.Annotations[util.IPAddressAnnotation]; ipAddr != "" {
×
1724
                return c.checkIPsInExcludeList(ipAddr, subnet.Spec.ExcludeIps, subnet.Spec.CIDRBlock)
×
1725
        }
×
1726
        if ipPool := pod.Annotations[util.IPPoolAnnotation]; ipPool != "" {
×
1727
                return c.checkIPsInExcludeList(ipPool, subnet.Spec.ExcludeIps, subnet.Spec.CIDRBlock)
×
1728
        }
×
1729

1730
        return false
×
1731
}
1732

1733
func (c *Controller) checkIPsInExcludeList(ips string, excludeIPs []string, cidr string) bool {
×
1734
        expandedExcludeIPs := util.ExpandExcludeIPs(excludeIPs, cidr)
×
1735

×
1736
        for ipAddr := range strings.SplitSeq(strings.TrimSpace(ips), ",") {
×
1737
                ipAddr = strings.TrimSpace(ipAddr)
×
1738
                if ipAddr == "" {
×
1739
                        continue
×
1740
                }
1741

1742
                for _, excludeIP := range expandedExcludeIPs {
×
1743
                        if util.ContainsIPs(excludeIP, ipAddr) {
×
1744
                                klog.V(3).Infof("IP %s is found in exclude IP %s, allowing allocation", ipAddr, excludeIP)
×
1745
                                return true
×
1746
                        }
×
1747
                }
1748
        }
1749
        return false
×
1750
}
1751

1752
type providerType int
1753

1754
const (
1755
        providerTypeIPAM providerType = iota
1756
        providerTypeOriginal
1757
)
1758

1759
type kubeovnNet struct {
1760
        Type               providerType
1761
        ProviderName       string
1762
        Subnet             *kubeovnv1.Subnet
1763
        IsDefault          bool
1764
        AllowLiveMigration bool
1765
        IPRequest          string
1766
        MacRequest         string
1767
        NadName            string
1768
        NadNamespace       string
1769
        InterfaceName      string
1770
}
1771

1772
func (c *Controller) getPodAttachmentNet(pod *v1.Pod) ([]*kubeovnNet, error) {
1✔
1773
        var multusNets []*nadv1.NetworkSelectionElement
1✔
1774
        defaultAttachNetworks := pod.Annotations[util.DefaultNetworkAnnotation]
1✔
1775
        if defaultAttachNetworks != "" {
1✔
1776
                attachments, err := nadutils.ParseNetworkAnnotation(defaultAttachNetworks, pod.Namespace)
×
1777
                if err != nil {
×
1778
                        klog.Errorf("failed to parse default attach net for pod '%s', %v", pod.Name, err)
×
1779
                        return nil, err
×
1780
                }
×
1781
                multusNets = attachments
×
1782
        }
1783

1784
        attachNetworks := pod.Annotations[nadv1.NetworkAttachmentAnnot]
1✔
1785
        if attachNetworks != "" {
2✔
1786
                attachments, err := nadutils.ParseNetworkAnnotation(attachNetworks, pod.Namespace)
1✔
1787
                if err != nil {
1✔
1788
                        klog.Errorf("failed to parse attach net for pod '%s', %v", pod.Name, err)
×
1789
                        return nil, err
×
1790
                }
×
1791
                multusNets = append(multusNets, attachments...)
1✔
1792
        }
1793
        subnets, err := c.subnetsLister.List(labels.Everything())
1✔
1794
        if err != nil {
1✔
1795
                klog.Errorf("failed to list subnets: %v", err)
×
1796
                return nil, err
×
1797
        }
×
1798

1799
        // ignore to return all existing subnets to clean its ip crd
1800
        ignoreSubnetNotExist := !pod.DeletionTimestamp.IsZero()
1✔
1801

1✔
1802
        nadCounts := make(map[string]int)
1✔
1803
        for _, attach := range multusNets {
2✔
1804
                nadCounts[fmt.Sprintf("%s/%s", attach.Namespace, attach.Name)]++
1✔
1805
        }
1✔
1806

1807
        result := make([]*kubeovnNet, 0, len(multusNets))
1✔
1808
        for _, attach := range multusNets {
2✔
1809
                nadKey := fmt.Sprintf("%s/%s", attach.Namespace, attach.Name)
1✔
1810
                network, err := c.netAttachLister.NetworkAttachmentDefinitions(attach.Namespace).Get(attach.Name)
1✔
1811
                if err != nil {
1✔
1812
                        klog.Errorf("failed to get net-attach-def %s, %v", attach.Name, err)
×
1813
                        if k8serrors.IsNotFound(err) && ignoreSubnetNotExist {
×
1814
                                // NAD deleted before pod, find subnet for cleanup
×
1815
                                providerName := fmt.Sprintf("%s.%s.%s", attach.Name, attach.Namespace, util.OvnProvider)
×
1816
                                if nadCounts[nadKey] > 1 && attach.InterfaceRequest != "" {
×
1817
                                        providerName = fmt.Sprintf("%s.%s", providerName, attach.InterfaceRequest)
×
1818
                                }
×
1819
                                subnetName := pod.Annotations[fmt.Sprintf(util.LogicalSwitchAnnotationTemplate, providerName)]
×
1820
                                if subnetName == "" {
×
1821
                                        for _, subnet := range subnets {
×
1822
                                                if subnet.Spec.Provider == providerName {
×
1823
                                                        subnetName = subnet.Name
×
1824
                                                        break
×
1825
                                                }
1826
                                        }
1827
                                }
1828

1829
                                if subnetName == "" {
×
1830
                                        klog.Errorf("deleting pod %s/%s net-attach-def %s not found and cannot determine subnet, gc will clean its ip cr", pod.Namespace, pod.Name, attach.Name)
×
1831
                                        continue
×
1832
                                }
1833

1834
                                subnet, err := c.subnetsLister.Get(subnetName)
×
1835
                                if err != nil {
×
1836
                                        klog.Errorf("failed to get subnet %s, %v", subnetName, err)
×
1837
                                        if k8serrors.IsNotFound(err) {
×
1838
                                                klog.Errorf("deleting pod %s/%s attach subnet %s already not exist, gc will clean its ip cr", pod.Namespace, pod.Name, subnetName)
×
1839
                                                continue
×
1840
                                        }
1841
                                        return nil, err
×
1842
                                }
1843

1844
                                klog.Infof("pod %s/%s net-attach-def %s not found, using subnet %s for cleanup", pod.Namespace, pod.Name, attach.Name, subnetName)
×
1845
                                result = append(result, &kubeovnNet{
×
1846
                                        Type:          providerTypeIPAM,
×
1847
                                        ProviderName:  providerName,
×
1848
                                        Subnet:        subnet,
×
1849
                                        IsDefault:     util.IsDefaultNet(pod.Annotations[util.DefaultNetworkAnnotation], attach),
×
1850
                                        NadName:       attach.Name,
×
1851
                                        NadNamespace:  attach.Namespace,
×
1852
                                        InterfaceName: attach.InterfaceRequest,
×
1853
                                })
×
1854
                                continue
×
1855
                        }
1856
                        return nil, err
×
1857
                }
1858

1859
                if network.Spec.Config == "" {
1✔
1860
                        continue
×
1861
                }
1862

1863
                netCfg, err := loadNetConf([]byte(network.Spec.Config))
1✔
1864
                if err != nil {
1✔
1865
                        klog.Errorf("failed to load config of net-attach-def %s, %v", attach.Name, err)
×
1866
                        return nil, err
×
1867
                }
×
1868

1869
                // allocate kubeovn network
1870
                var providerName string
1✔
1871
                if util.IsOvnNetwork(netCfg) {
2✔
1872
                        allowLiveMigration := false
1✔
1873
                        isDefault := util.IsDefaultNet(pod.Annotations[util.DefaultNetworkAnnotation], attach)
1✔
1874

1✔
1875
                        providerName = fmt.Sprintf("%s.%s.%s", attach.Name, attach.Namespace, util.OvnProvider)
1✔
1876
                        if nadCounts[nadKey] > 1 && attach.InterfaceRequest != "" {
1✔
1877
                                providerName = fmt.Sprintf("%s.%s", providerName, attach.InterfaceRequest)
×
1878
                        }
×
1879
                        if pod.Annotations[kubevirtv1.MigrationJobNameAnnotation] != "" {
1✔
1880
                                allowLiveMigration = true
×
1881
                        }
×
1882

1883
                        subnetName := pod.Annotations[fmt.Sprintf(util.LogicalSwitchAnnotationTemplate, providerName)]
1✔
1884
                        if subnetName == "" {
1✔
1885
                                for _, subnet := range subnets {
×
1886
                                        if subnet.Spec.Provider == providerName {
×
1887
                                                subnetName = subnet.Name
×
1888
                                                break
×
1889
                                        }
1890
                                }
1891
                        }
1892
                        var subnet *kubeovnv1.Subnet
1✔
1893
                        if subnetName == "" {
1✔
1894
                                // attachment network not specify subnet, use pod default subnet or namespace subnet
×
1895
                                subnet, err = c.getPodDefaultSubnet(pod)
×
1896
                                if err != nil {
×
1897
                                        klog.Errorf("failed to pod default subnet, %v", err)
×
1898
                                        if k8serrors.IsNotFound(err) {
×
1899
                                                if ignoreSubnetNotExist {
×
1900
                                                        klog.Errorf("deleting pod %s/%s attach subnet %s already not exist, gc will clean its ip cr", pod.Namespace, pod.Name, subnetName)
×
1901
                                                        continue
×
1902
                                                }
1903
                                        }
1904
                                        return nil, err
×
1905
                                }
1906
                                // default subnet may change after pod restart
1907
                                klog.Infof("pod %s/%s attachment network %s use default subnet %s", pod.Namespace, pod.Name, attach.Name, subnet.Name)
×
1908
                        } else {
1✔
1909
                                subnet, err = c.subnetsLister.Get(subnetName)
1✔
1910
                                if err != nil {
1✔
1911
                                        klog.Errorf("failed to get subnet %s, %v", subnetName, err)
×
1912
                                        if k8serrors.IsNotFound(err) {
×
1913
                                                if ignoreSubnetNotExist {
×
1914
                                                        klog.Errorf("deleting pod %s/%s attach subnet %s already not exist, gc will clean its ip cr", pod.Namespace, pod.Name, subnetName)
×
1915
                                                        // just continue to next attach subnet
×
1916
                                                        // ip name is unique, so it is ok if the other subnet release it
×
1917
                                                        continue
×
1918
                                                }
1919
                                        }
1920
                                        return nil, err
×
1921
                                }
1922
                        }
1923

1924
                        ret := &kubeovnNet{
1✔
1925
                                Type:               providerTypeOriginal,
1✔
1926
                                ProviderName:       providerName,
1✔
1927
                                Subnet:             subnet,
1✔
1928
                                IsDefault:          isDefault,
1✔
1929
                                AllowLiveMigration: allowLiveMigration,
1✔
1930
                                MacRequest:         attach.MacRequest,
1✔
1931
                                IPRequest:          strings.Join(attach.IPRequest, ","),
1✔
1932
                                NadName:            attach.Name,
1✔
1933
                                NadNamespace:       attach.Namespace,
1✔
1934
                                InterfaceName:      attach.InterfaceRequest,
1✔
1935
                        }
1✔
1936
                        result = append(result, ret)
1✔
1937
                } else {
×
1938
                        providerName = fmt.Sprintf("%s.%s", attach.Name, attach.Namespace)
×
1939
                        for _, subnet := range subnets {
×
1940
                                if subnet.Spec.Provider == providerName {
×
1941
                                        result = append(result, &kubeovnNet{
×
1942
                                                Type:          providerTypeIPAM,
×
1943
                                                ProviderName:  providerName,
×
1944
                                                Subnet:        subnet,
×
1945
                                                MacRequest:    attach.MacRequest,
×
1946
                                                IPRequest:     strings.Join(attach.IPRequest, ","),
×
1947
                                                NadName:       attach.Name,
×
1948
                                                NadNamespace:  attach.Namespace,
×
1949
                                                InterfaceName: attach.InterfaceRequest,
×
1950
                                        })
×
1951
                                        break
×
1952
                                }
1953
                        }
1954
                }
1955
        }
1956
        return result, nil
1✔
1957
}
1958

1959
func (c *Controller) validatePodIP(podName, subnetName, ipv4, ipv6 string) (bool, bool, error) {
×
1960
        subnet, err := c.subnetsLister.Get(subnetName)
×
1961
        if err != nil {
×
1962
                klog.Errorf("failed to get subnet %s: %v", subnetName, err)
×
1963
                return false, false, err
×
1964
        }
×
1965

1966
        if subnet.Spec.Vlan == "" && subnet.Spec.Vpc == c.config.ClusterRouter {
×
1967
                nodes, err := c.nodesLister.List(labels.Everything())
×
1968
                if err != nil {
×
1969
                        klog.Errorf("failed to list nodes: %v", err)
×
1970
                        return false, false, err
×
1971
                }
×
1972

1973
                for _, node := range nodes {
×
1974
                        nodeIPv4, nodeIPv6 := util.GetNodeInternalIP(*node)
×
1975
                        if ipv4 != "" && ipv4 == nodeIPv4 {
×
1976
                                klog.Errorf("IP address (%s) assigned to pod %s is the same with internal IP address of node %s, reallocating...", ipv4, podName, node.Name)
×
1977
                                return false, true, nil
×
1978
                        }
×
1979
                        if ipv6 != "" && ipv6 == nodeIPv6 {
×
1980
                                klog.Errorf("IP address (%s) assigned to pod %s is the same with internal IP address of node %s, reallocating...", ipv6, podName, node.Name)
×
1981
                                return true, false, nil
×
1982
                        }
×
1983
                }
1984
        }
1985

1986
        return true, true, nil
×
1987
}
1988

1989
func (c *Controller) acquireAddress(pod *v1.Pod, podNet *kubeovnNet) (string, string, string, *kubeovnv1.Subnet, error) {
1✔
1990
        podName := c.getNameByPod(pod)
1✔
1991
        key := cache.NewObjectName(pod.Namespace, podName).String()
1✔
1992
        portName := ovs.PodNameToPortName(podName, pod.Namespace, podNet.ProviderName)
1✔
1993

1✔
1994
        var checkVMPod bool
1✔
1995
        isStsPod, _, _ := isStatefulSetPod(pod)
1✔
1996
        // if pod has static vip
1✔
1997
        vipName := pod.Annotations[util.VipAnnotation]
1✔
1998
        if vipName != "" {
1✔
1999
                vip, err := c.virtualIpsLister.Get(vipName)
×
2000
                if err != nil {
×
2001
                        klog.Errorf("failed to get static vip '%s', %v", vipName, err)
×
2002
                        return "", "", "", podNet.Subnet, err
×
2003
                }
×
2004
                if c.config.EnableKeepVMIP {
×
2005
                        checkVMPod, _ = isVMPod(pod)
×
2006
                }
×
2007
                if err = c.podReuseVip(vipName, portName, isStsPod || checkVMPod); err != nil {
×
2008
                        return "", "", "", podNet.Subnet, err
×
2009
                }
×
2010
                return vip.Status.V4ip, vip.Status.V6ip, vip.Status.Mac, podNet.Subnet, nil
×
2011
        }
2012

2013
        var macPointer *string
1✔
2014
        if podNet.NadName != "" && podNet.NadNamespace != "" && podNet.InterfaceName != "" {
1✔
2015
                key := perInterfaceMACAnnotationKey(podNet.NadName, podNet.NadNamespace, podNet.InterfaceName)
×
2016
                if macStr := pod.Annotations[key]; macStr != "" {
×
2017
                        if _, err := net.ParseMAC(macStr); err != nil {
×
2018
                                return "", "", "", podNet.Subnet, err
×
2019
                        }
×
2020
                        macPointer = &macStr
×
2021
                }
2022
        }
2023

2024
        if macPointer == nil && isOvnSubnet(podNet.Subnet) {
2✔
2025
                annoMAC := pod.Annotations[fmt.Sprintf(util.MacAddressAnnotationTemplate, podNet.ProviderName)]
1✔
2026
                if annoMAC != "" {
1✔
2027
                        if _, err := net.ParseMAC(annoMAC); err != nil {
×
2028
                                return "", "", "", podNet.Subnet, err
×
2029
                        }
×
2030
                        macPointer = &annoMAC
×
2031
                }
2032
        } else if macPointer == nil {
×
2033
                macPointer = ptr.To("")
×
2034
        }
×
2035

2036
        var nsNets []*kubeovnNet
1✔
2037
        ippoolStr := pod.Annotations[fmt.Sprintf(util.IPPoolAnnotationTemplate, podNet.ProviderName)]
1✔
2038
        subnetStr := pod.Annotations[fmt.Sprintf(util.LogicalSwitchAnnotationTemplate, podNet.ProviderName)]
1✔
2039

1✔
2040
        // Prepare nsNets based on subnet annotation
1✔
2041
        var err error
1✔
2042
        if subnetStr != "" {
2✔
2043
                nsNets = []*kubeovnNet{podNet}
1✔
2044
        } else if nsNets, err = c.getNsAvailableSubnets(pod, podNet); err != nil {
2✔
2045
                klog.Errorf("failed to get available subnets for pod %s/%s, %v", pod.Namespace, pod.Name, err)
×
2046
                return "", "", "", podNet.Subnet, err
×
2047
        }
×
2048

2049
        if ippoolStr == "" && podNet.IsDefault {
2✔
2050
                // no ippool specified by pod annotation, use namespace ippools or ippools in the subnet specified by pod annotation
1✔
2051
                ns, err := c.namespacesLister.Get(pod.Namespace)
1✔
2052
                if err != nil {
1✔
2053
                        klog.Errorf("failed to get namespace %s: %v", pod.Namespace, err)
×
2054
                        return "", "", "", podNet.Subnet, err
×
2055
                }
×
2056
                subnetNames := make([]string, 0, len(nsNets))
1✔
2057
                for _, net := range nsNets {
2✔
2058
                        if net.Subnet.Name == subnetStr {
2✔
2059
                                // allocate from ippools in the subnet specified by pod annotation
1✔
2060
                                podNet.Subnet = net.Subnet
1✔
2061
                                subnetNames = []string{net.Subnet.Name}
1✔
2062
                                break
1✔
2063
                        }
2064
                        subnetNames = append(subnetNames, net.Subnet.Name)
1✔
2065
                }
2066

2067
                if subnetStr == "" || slices.Contains(subnetNames, subnetStr) {
2✔
2068
                        // no subnet specified by pod annotation or specified subnet is in namespace subnets
1✔
2069
                        if ipPoolList, ok := ns.Annotations[util.IPPoolAnnotation]; ok {
1✔
2070
                                for ipPoolName := range strings.SplitSeq(ipPoolList, ",") {
×
2071
                                        ippool, err := c.ippoolLister.Get(ipPoolName)
×
2072
                                        if err != nil {
×
2073
                                                klog.Errorf("failed to get ippool %s: %v", ipPoolName, err)
×
2074
                                                return "", "", "", podNet.Subnet, err
×
2075
                                        }
×
2076

2077
                                        switch podNet.Subnet.Spec.Protocol {
×
2078
                                        case kubeovnv1.ProtocolDual:
×
2079
                                                if ippool.Status.V4AvailableIPs.Int64() == 0 || ippool.Status.V6AvailableIPs.Int64() == 0 {
×
2080
                                                        continue
×
2081
                                                }
2082
                                        case kubeovnv1.ProtocolIPv4:
×
2083
                                                if ippool.Status.V4AvailableIPs.Int64() == 0 {
×
2084
                                                        continue
×
2085
                                                }
2086

2087
                                        default:
×
2088
                                                if ippool.Status.V6AvailableIPs.Int64() == 0 {
×
2089
                                                        continue
×
2090
                                                }
2091
                                        }
2092

2093
                                        for _, net := range nsNets {
×
2094
                                                if net.Subnet.Name == ippool.Spec.Subnet && slices.Contains(subnetNames, net.Subnet.Name) {
×
2095
                                                        ippoolStr = ippool.Name
×
2096
                                                        podNet.Subnet = net.Subnet
×
2097
                                                        break
×
2098
                                                }
2099
                                        }
2100
                                        if ippoolStr != "" {
×
2101
                                                break
×
2102
                                        }
2103
                                }
2104
                                if ippoolStr == "" {
×
2105
                                        klog.Infof("no available ippool in subnet(s) %s for pod %s/%s", strings.Join(subnetNames, ","), pod.Namespace, pod.Name)
×
2106
                                        return "", "", "", podNet.Subnet, ipam.ErrNoAvailable
×
2107
                                }
×
2108
                        }
2109
                }
2110
        }
2111

2112
        // Random allocate
2113
        if pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, podNet.ProviderName)] == "" &&
1✔
2114
                ippoolStr == "" {
1✔
2115
                // check new IP annotation
×
2116
                if podNet.NadName != "" && podNet.NadNamespace != "" && podNet.InterfaceName != "" {
×
2117
                        annoKey := perInterfaceIPAnnotationKey(podNet.NadName, podNet.NadNamespace, podNet.InterfaceName)
×
2118
                        if ipStr := pod.Annotations[annoKey]; ipStr != "" {
×
2119
                                return c.acquireStaticAddressHelper(pod, podNet, portName, macPointer, ippoolStr, nsNets, isStsPod, key)
×
2120
                        }
×
2121
                }
2122

2123
                var skippedAddrs []string
×
2124
                for {
×
2125
                        ipv4, ipv6, mac, err := c.ipam.GetRandomAddress(key, portName, macPointer, podNet.Subnet.Name, "", skippedAddrs, !podNet.AllowLiveMigration)
×
2126
                        if err != nil {
×
2127
                                klog.Error(err)
×
2128
                                return "", "", "", podNet.Subnet, err
×
2129
                        }
×
2130
                        ipv4OK, ipv6OK, err := c.validatePodIP(pod.Name, podNet.Subnet.Name, ipv4, ipv6)
×
2131
                        if err != nil {
×
2132
                                klog.Error(err)
×
2133
                                return "", "", "", podNet.Subnet, err
×
2134
                        }
×
2135
                        if ipv4OK && ipv6OK {
×
2136
                                return ipv4, ipv6, mac, podNet.Subnet, nil
×
2137
                        }
×
2138

2139
                        if !ipv4OK {
×
2140
                                skippedAddrs = append(skippedAddrs, ipv4)
×
2141
                        }
×
2142
                        if !ipv6OK {
×
2143
                                skippedAddrs = append(skippedAddrs, ipv6)
×
2144
                        }
×
2145
                }
2146
        }
2147

2148
        return c.acquireStaticAddressHelper(pod, podNet, portName, macPointer, ippoolStr, nsNets, isStsPod, key)
1✔
2149
}
2150

2151
func (c *Controller) acquireStaticAddressHelper(pod *v1.Pod, podNet *kubeovnNet, portName string, macPointer *string, ippoolStr string, nsNets []*kubeovnNet, isStsPod bool, key string) (string, string, string, *kubeovnv1.Subnet, error) {
1✔
2152
        var v4IP, v6IP, mac string
1✔
2153
        var err error
1✔
2154

1✔
2155
        // Static allocate
1✔
2156
        if podNet.NadName != "" && podNet.NadNamespace != "" && podNet.InterfaceName != "" {
1✔
2157
                key := perInterfaceIPAnnotationKey(podNet.NadName, podNet.NadNamespace, podNet.InterfaceName)
×
2158
                if ipStr := pod.Annotations[key]; ipStr != "" {
×
2159
                        for _, net := range nsNets {
×
2160
                                v4IP, v6IP, mac, err = c.acquireStaticAddress(key, portName, ipStr, macPointer, net.Subnet.Name, net.AllowLiveMigration)
×
2161
                                if err == nil {
×
2162
                                        return v4IP, v6IP, mac, net.Subnet, nil
×
2163
                                }
×
2164
                        }
2165
                        return v4IP, v6IP, mac, podNet.Subnet, err
×
2166
                }
2167
        }
2168

2169
        if ipStr := pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, podNet.ProviderName)]; ipStr != "" {
2✔
2170
                for _, net := range nsNets {
2✔
2171
                        v4IP, v6IP, mac, err = c.acquireStaticAddress(key, portName, ipStr, macPointer, net.Subnet.Name, net.AllowLiveMigration)
1✔
2172
                        if err == nil {
2✔
2173
                                return v4IP, v6IP, mac, net.Subnet, nil
1✔
2174
                        }
1✔
2175
                }
2176
                return v4IP, v6IP, mac, podNet.Subnet, err
1✔
2177
        }
2178

2179
        // IPPool allocate
2180
        if ippoolStr != "" {
×
2181
                var ipPool []string
×
2182
                if strings.ContainsRune(ippoolStr, ';') {
×
2183
                        ipPool = strings.Split(ippoolStr, ";")
×
2184
                } else {
×
2185
                        ipPool = strings.Split(ippoolStr, ",")
×
2186
                        if len(ipPool) == 2 && util.CheckProtocol(ipPool[0]) != util.CheckProtocol(ipPool[1]) {
×
2187
                                ipPool = []string{ippoolStr}
×
2188
                        }
×
2189
                }
2190
                for i, ip := range ipPool {
×
2191
                        ipPool[i] = strings.TrimSpace(ip)
×
2192
                }
×
2193

2194
                if len(ipPool) == 1 && (!strings.ContainsRune(ipPool[0], ',') && net.ParseIP(ipPool[0]) == nil) {
×
2195
                        var skippedAddrs []string
×
2196
                        pool, err := c.ippoolLister.Get(ipPool[0])
×
2197
                        if err != nil {
×
2198
                                klog.Errorf("failed to get ippool %s: %v", ipPool[0], err)
×
2199
                                return "", "", "", podNet.Subnet, err
×
2200
                        }
×
2201
                        for {
×
2202
                                ipv4, ipv6, mac, err := c.ipam.GetRandomAddress(key, portName, macPointer, pool.Spec.Subnet, ipPool[0], skippedAddrs, !podNet.AllowLiveMigration)
×
2203
                                if err != nil {
×
2204
                                        klog.Error(err)
×
2205
                                        return "", "", "", podNet.Subnet, err
×
2206
                                }
×
2207
                                ipv4OK, ipv6OK, err := c.validatePodIP(pod.Name, podNet.Subnet.Name, ipv4, ipv6)
×
2208
                                if err != nil {
×
2209
                                        klog.Error(err)
×
2210
                                        return "", "", "", podNet.Subnet, err
×
2211
                                }
×
2212
                                if ipv4OK && ipv6OK {
×
2213
                                        return ipv4, ipv6, mac, podNet.Subnet, nil
×
2214
                                }
×
2215

2216
                                if !ipv4OK {
×
2217
                                        skippedAddrs = append(skippedAddrs, ipv4)
×
2218
                                }
×
2219
                                if !ipv6OK {
×
2220
                                        skippedAddrs = append(skippedAddrs, ipv6)
×
2221
                                }
×
2222
                        }
2223
                }
2224

2225
                if !isStsPod {
×
2226
                        for _, net := range nsNets {
×
2227
                                for _, staticIP := range ipPool {
×
2228
                                        var checkIP string
×
2229
                                        ipProtocol := util.CheckProtocol(staticIP)
×
2230
                                        if ipProtocol == kubeovnv1.ProtocolDual {
×
2231
                                                checkIP = strings.Split(staticIP, ",")[0]
×
2232
                                        } else {
×
2233
                                                checkIP = staticIP
×
2234
                                        }
×
2235

2236
                                        if assignedPod, ok := c.ipam.IsIPAssignedToOtherPod(checkIP, net.Subnet.Name, key); ok {
×
2237
                                                klog.Errorf("static address %s for %s has been assigned to %s", staticIP, key, assignedPod)
×
2238
                                                continue
×
2239
                                        }
2240

2241
                                        v4IP, v6IP, mac, err = c.acquireStaticAddress(key, portName, staticIP, macPointer, net.Subnet.Name, net.AllowLiveMigration)
×
2242
                                        if err == nil {
×
2243
                                                return v4IP, v6IP, mac, net.Subnet, nil
×
2244
                                        }
×
2245
                                }
2246
                        }
2247
                        klog.Errorf("acquire address from ippool %s for %s failed, %v", ippoolStr, key, err)
×
2248
                } else {
×
2249
                        tempStrs := strings.Split(pod.Name, "-")
×
2250
                        numStr := tempStrs[len(tempStrs)-1]
×
2251
                        index, _ := strconv.Atoi(numStr)
×
2252

×
2253
                        if index < len(ipPool) {
×
2254
                                for _, net := range nsNets {
×
2255
                                        v4IP, v6IP, mac, err = c.acquireStaticAddress(key, portName, ipPool[index], macPointer, net.Subnet.Name, net.AllowLiveMigration)
×
2256
                                        if err == nil {
×
2257
                                                return v4IP, v6IP, mac, net.Subnet, nil
×
2258
                                        }
×
2259
                                }
2260
                                klog.Errorf("acquire address %s for %s failed, %v", ipPool[index], key, err)
×
2261
                        }
2262
                }
2263
        }
2264
        klog.Errorf("allocate address for %s failed, return NoAvailableAddress", key)
×
2265
        return "", "", "", podNet.Subnet, ipam.ErrNoAvailable
×
2266
}
2267

2268
func (c *Controller) acquireStaticAddress(key, nicName, ip string, mac *string, subnet string, liveMigration bool) (string, string, string, error) {
1✔
2269
        var v4IP, v6IP, macStr string
1✔
2270
        var err error
1✔
2271
        for ipStr := range strings.SplitSeq(ip, ",") {
2✔
2272
                if net.ParseIP(ipStr) == nil {
1✔
2273
                        return "", "", "", fmt.Errorf("failed to parse IP %s", ipStr)
×
2274
                }
×
2275
        }
2276

2277
        if v4IP, v6IP, macStr, err = c.ipam.GetStaticAddress(key, nicName, ip, mac, subnet, !liveMigration); err != nil {
2✔
2278
                klog.Errorf("failed to get static ip %v, mac %v, subnet %v, err %v", ip, mac, subnet, err)
1✔
2279
                return "", "", "", err
1✔
2280
        }
1✔
2281
        return v4IP, v6IP, macStr, nil
1✔
2282
}
2283

2284
func appendCheckPodNetToDel(c *Controller, pod *v1.Pod, ownerRefName, ownerRefKind string) (bool, []string, error) {
×
2285
        // subnet for ns has been changed, and statefulset/vm pod's ip is not in the range of subnet's cidr anymore
×
2286
        podNs, err := c.namespacesLister.Get(pod.Namespace)
×
2287
        if err != nil {
×
2288
                klog.Errorf("failed to get namespace %s, %v", pod.Namespace, err)
×
2289
                return false, nil, err
×
2290
        }
×
2291

2292
        var ownerRefAnnotations map[string]string
×
2293
        switch ownerRefKind {
×
2294
        case util.KindStatefulSet:
×
2295
                ss, err := c.config.KubeClient.AppsV1().StatefulSets(pod.Namespace).Get(context.Background(), ownerRefName, metav1.GetOptions{})
×
2296
                if err != nil {
×
2297
                        if k8serrors.IsNotFound(err) {
×
2298
                                klog.Infof("Statefulset %s is not found", ownerRefName)
×
2299
                                return true, nil, nil
×
2300
                        }
×
2301
                        klog.Errorf("failed to get StatefulSet %s, %v", ownerRefName, err)
×
2302
                }
2303
                if ss.Spec.Template.Annotations != nil {
×
2304
                        ownerRefAnnotations = ss.Spec.Template.Annotations
×
2305
                }
×
2306

2307
        case util.KindVirtualMachineInstance:
×
2308
                vm, err := c.config.KubevirtClient.VirtualMachine(pod.Namespace).Get(context.Background(), ownerRefName, metav1.GetOptions{})
×
2309
                if err != nil {
×
2310
                        if k8serrors.IsNotFound(err) {
×
2311
                                klog.Infof("VirtualMachine %s is not found", ownerRefName)
×
2312
                                return true, nil, nil
×
2313
                        }
×
2314
                        klog.Errorf("failed to get VirtualMachine %s, %v", ownerRefName, err)
×
2315
                }
2316
                if vm != nil &&
×
2317
                        vm.Spec.Template != nil &&
×
2318
                        vm.Spec.Template.ObjectMeta.Annotations != nil {
×
2319
                        ownerRefAnnotations = vm.Spec.Template.ObjectMeta.Annotations
×
2320
                }
×
2321
        }
2322

2323
        var ipcrToDelete []string
×
2324
        if defaultIPCRName := appendCheckPodNonMultusNetToDel(c, pod, ownerRefName, ownerRefAnnotations, podNs); defaultIPCRName != "" {
×
2325
                ipcrToDelete = append(ipcrToDelete, defaultIPCRName)
×
2326
        }
×
2327

2328
        if multusIPCRNames := appendCheckPodMultusNetToDel(c, pod, ownerRefName, ownerRefAnnotations); len(multusIPCRNames) != 0 {
×
2329
                ipcrToDelete = append(ipcrToDelete, multusIPCRNames...)
×
2330
        }
×
2331

2332
        return false, ipcrToDelete, nil
×
2333
}
2334

2335
func appendCheckPodNonMultusNetToDel(c *Controller, pod *v1.Pod, ownerRefName string, ownerRefAnnotations map[string]string, podNs *v1.Namespace) string {
×
2336
        podDefaultSwitch := strings.TrimSpace(pod.Annotations[util.LogicalSwitchAnnotation])
×
2337
        if podDefaultSwitch != "" {
×
2338
                ownerRefSubnet := ownerRefAnnotations[util.LogicalSwitchAnnotation]
×
2339
                defaultIPCRName := ovs.PodNameToPortName(ownerRefName, pod.Namespace, util.OvnProvider)
×
2340
                if ownerRefSubnet == "" {
×
2341
                        nsSubnetNames := podNs.Annotations[util.LogicalSwitchAnnotation]
×
2342
                        // check if pod use the subnet of its ns
×
2343
                        if nsSubnetNames != "" && !slices.Contains(strings.Split(nsSubnetNames, ","), podDefaultSwitch) {
×
2344
                                klog.Infof("ns %s annotation subnet is %s, which is inconstant with subnet for pod %s, delete pod", pod.Namespace, nsSubnetNames, pod.Name)
×
2345
                                return defaultIPCRName
×
2346
                        }
×
2347
                } else {
×
2348
                        podIP := pod.Annotations[util.IPAddressAnnotation]
×
2349
                        if shouldCleanPodNet(c, pod, ownerRefName, ownerRefSubnet, podDefaultSwitch, podIP) {
×
2350
                                return defaultIPCRName
×
2351
                        }
×
2352
                }
2353
        }
2354
        return ""
×
2355
}
2356

2357
func appendCheckPodMultusNetToDel(c *Controller, pod *v1.Pod, ownerRefName string, ownerRefAnnotations map[string]string) []string {
×
2358
        var multusIPCRNames []string
×
2359
        attachmentNets, _ := c.getPodAttachmentNet(pod)
×
2360
        for _, attachmentNet := range attachmentNets {
×
2361
                ipCRName := ovs.PodNameToPortName(ownerRefName, pod.Namespace, attachmentNet.ProviderName)
×
2362
                podSwitch := strings.TrimSpace(pod.Annotations[fmt.Sprintf(util.LogicalSwitchAnnotationTemplate, attachmentNet.ProviderName)])
×
2363
                ownerRefSubnet := ownerRefAnnotations[fmt.Sprintf(util.LogicalSwitchAnnotationTemplate, attachmentNet.ProviderName)]
×
2364
                podIP := pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, attachmentNet.ProviderName)]
×
2365
                if shouldCleanPodNet(c, pod, ownerRefName, ownerRefSubnet, podSwitch, podIP) {
×
2366
                        multusIPCRNames = append(multusIPCRNames, ipCRName)
×
2367
                }
×
2368
        }
2369
        return multusIPCRNames
×
2370
}
2371

2372
func shouldCleanPodNet(c *Controller, pod *v1.Pod, ownerRefName, ownerRefSubnet, podSwitch, podIP string) bool {
×
2373
        // subnet cidr has been changed, and statefulset pod's ip is not in the range of subnet's cidr anymore
×
2374
        podSubnet, err := c.subnetsLister.Get(podSwitch)
×
2375
        if err != nil {
×
2376
                if k8serrors.IsNotFound(err) {
×
2377
                        klog.Infof("subnet %s not found for pod %s/%s, not auto clean ip", podSwitch, pod.Namespace, pod.Name)
×
2378
                        return false
×
2379
                }
×
2380
                klog.Errorf("failed to get subnet %s, %v, not auto clean ip", podSwitch, err)
×
2381
                return false
×
2382
        }
2383
        if podSubnet == nil {
×
2384
                // TODO: remove: CRD get interface will retrun a nil subnet ?
×
2385
                klog.Errorf("pod %s/%s subnet %s is nil, not auto clean ip", pod.Namespace, pod.Name, podSwitch)
×
2386
                return false
×
2387
        }
×
2388
        if podIP == "" {
×
2389
                // delete pod just after it created < 1ms
×
2390
                klog.Infof("pod %s/%s annotaions has no ip address, not auto clean ip", pod.Namespace, pod.Name)
×
2391
                return false
×
2392
        }
×
2393
        podSubnetCidr := podSubnet.Spec.CIDRBlock
×
2394
        if podSubnetCidr == "" {
×
2395
                // subnet spec cidr changed by user
×
2396
                klog.Errorf("invalid pod subnet %s empty cidr %s, not auto clean ip", podSwitch, podSubnetCidr)
×
2397
                return false
×
2398
        }
×
2399
        if !util.CIDRContainIP(podSubnetCidr, podIP) {
×
2400
                klog.Infof("pod's ip %s is not in the range of subnet %s, delete pod", podIP, podSubnet.Name)
×
2401
                return true
×
2402
        }
×
2403
        // subnet of ownerReference(sts/vm) has been changed, it needs to handle delete pod and create port on the new logical switch
2404
        if ownerRefSubnet != "" && podSubnet.Name != ownerRefSubnet {
×
2405
                klog.Infof("Subnet of owner %s has been changed from %s to %s, delete pod %s/%s", ownerRefName, podSubnet.Name, ownerRefSubnet, pod.Namespace, pod.Name)
×
2406
                return true
×
2407
        }
×
2408

2409
        return false
×
2410
}
2411

2412
func isVMPod(pod *v1.Pod) (bool, string) {
×
2413
        for _, owner := range pod.OwnerReferences {
×
2414
                // The name of vmi is consistent with vm's name.
×
2415
                if owner.Kind == util.KindVirtualMachineInstance &&
×
2416
                        strings.HasPrefix(owner.APIVersion, kubevirtv1.SchemeGroupVersion.Group+"/") {
×
2417
                        return true, owner.Name
×
2418
                }
×
2419
        }
2420
        return false, ""
×
2421
}
2422

2423
func isOwnsByTheVM(vmi metav1.Object) (bool, string) {
×
2424
        for _, owner := range vmi.GetOwnerReferences() {
×
2425
                if owner.Kind == util.KindVirtualMachine &&
×
2426
                        strings.HasPrefix(owner.APIVersion, kubevirtv1.SchemeGroupVersion.Group+"/") {
×
2427
                        return true, owner.Name
×
2428
                }
×
2429
        }
2430
        return false, ""
×
2431
}
2432

2433
func (c *Controller) isVMToDel(pod *v1.Pod, vmiName string) bool {
×
2434
        var (
×
2435
                vmiAlive bool
×
2436
                vmName   string
×
2437
        )
×
2438
        // The vmi is also deleted when pod is deleted, only left vm exists.
×
2439
        vmi, err := c.config.KubevirtClient.VirtualMachineInstance(pod.Namespace).Get(context.Background(), vmiName, metav1.GetOptions{})
×
2440
        if err != nil {
×
2441
                if k8serrors.IsNotFound(err) {
×
2442
                        vmiAlive = false
×
2443
                        // The name of vmi is consistent with vm's name.
×
2444
                        vmName = vmiName
×
2445
                        klog.ErrorS(err, "failed to get vmi, will try to get the vm directly", "name", vmiName)
×
2446
                } else {
×
2447
                        klog.ErrorS(err, "failed to get vmi", "name", vmiName)
×
2448
                        return false
×
2449
                }
×
2450
        } else {
×
2451
                var ownsByVM bool
×
2452
                ownsByVM, vmName = isOwnsByTheVM(vmi)
×
2453
                if !ownsByVM && !vmi.DeletionTimestamp.IsZero() {
×
2454
                        klog.Infof("ephemeral vmi %s is deleting", vmiName)
×
2455
                        return true
×
2456
                }
×
2457
                vmiAlive = vmi.DeletionTimestamp.IsZero()
×
2458
        }
2459

2460
        if vmiAlive {
×
2461
                return false
×
2462
        }
×
2463

2464
        vm, err := c.config.KubevirtClient.VirtualMachine(pod.Namespace).Get(context.Background(), vmName, metav1.GetOptions{})
×
2465
        if err != nil {
×
2466
                // the vm has gone
×
2467
                if k8serrors.IsNotFound(err) {
×
2468
                        klog.ErrorS(err, "failed to get vm", "name", vmName)
×
2469
                        return true
×
2470
                }
×
2471
                klog.ErrorS(err, "failed to get vm", "name", vmName)
×
2472
                return false
×
2473
        }
2474

2475
        if !vm.DeletionTimestamp.IsZero() {
×
2476
                klog.Infof("vm %s is deleting", vmName)
×
2477
                return true
×
2478
        }
×
2479
        return false
×
2480
}
2481

2482
func (c *Controller) getNameByPod(pod *v1.Pod) string {
1✔
2483
        if c.config.EnableKeepVMIP {
1✔
2484
                if isVMPod, vmName := isVMPod(pod); isVMPod {
×
2485
                        return vmName
×
2486
                }
×
2487
        }
2488
        return pod.Name
1✔
2489
}
2490

2491
// When subnet's v4availableIPs is 0 but still there's available ip in exclude-ips, the static ip in exclude-ips can be allocated normal.
2492
func (c *Controller) getNsAvailableSubnets(pod *v1.Pod, podNet *kubeovnNet) ([]*kubeovnNet, error) {
1✔
2493
        // keep the annotation subnet of the pod in first position
1✔
2494
        result := []*kubeovnNet{podNet}
1✔
2495

1✔
2496
        ns, err := c.namespacesLister.Get(pod.Namespace)
1✔
2497
        if err != nil {
1✔
2498
                klog.Errorf("failed to get namespace %s, %v", pod.Namespace, err)
×
2499
                return nil, err
×
2500
        }
×
2501
        if ns.Annotations == nil {
1✔
2502
                return []*kubeovnNet{}, nil
×
2503
        }
×
2504

2505
        subnetNames := ns.Annotations[util.LogicalSwitchAnnotation]
1✔
2506
        for subnetName := range strings.SplitSeq(subnetNames, ",") {
2✔
2507
                if subnetName == "" || subnetName == podNet.Subnet.Name {
2✔
2508
                        continue
1✔
2509
                }
2510
                subnet, err := c.subnetsLister.Get(subnetName)
1✔
2511
                if err != nil {
1✔
2512
                        klog.Errorf("failed to get subnet %v", err)
×
2513
                        return nil, err
×
2514
                }
×
2515

2516
                result = append(result, &kubeovnNet{
1✔
2517
                        Type:         providerTypeOriginal,
1✔
2518
                        ProviderName: subnet.Spec.Provider,
1✔
2519
                        Subnet:       subnet,
1✔
2520
                })
1✔
2521
        }
2522

2523
        return result, nil
1✔
2524
}
2525

2526
func getPodType(pod *v1.Pod) string {
×
2527
        if ok, _, _ := isStatefulSetPod(pod); ok {
×
2528
                return util.KindStatefulSet
×
2529
        }
×
2530

2531
        if isVMPod, _ := isVMPod(pod); isVMPod {
×
2532
                return util.KindVirtualMachine
×
2533
        }
×
2534
        return ""
×
2535
}
2536

2537
func (c *Controller) getVirtualIPs(pod *v1.Pod, podNets []*kubeovnNet) map[string]string {
×
2538
        vipsListMap := make(map[string][]string)
×
2539
        var vipNamesList []string
×
2540
        for vipName := range strings.SplitSeq(strings.TrimSpace(pod.Annotations[util.AAPsAnnotation]), ",") {
×
2541
                if vipName = strings.TrimSpace(vipName); vipName == "" {
×
2542
                        continue
×
2543
                }
2544
                if !slices.Contains(vipNamesList, vipName) {
×
2545
                        vipNamesList = append(vipNamesList, vipName)
×
2546
                } else {
×
2547
                        continue
×
2548
                }
2549
                vip, err := c.virtualIpsLister.Get(vipName)
×
2550
                if err != nil {
×
2551
                        klog.Errorf("failed to get vip %s, %v", vipName, err)
×
2552
                        continue
×
2553
                }
2554
                if vip.Spec.Namespace != pod.Namespace || (vip.Status.V4ip == "" && vip.Status.V6ip == "") {
×
2555
                        continue
×
2556
                }
2557
                for _, podNet := range podNets {
×
2558
                        if podNet.Subnet.Name == vip.Spec.Subnet {
×
2559
                                key := fmt.Sprintf("%s.%s", podNet.Subnet.Name, podNet.ProviderName)
×
2560
                                vipsList := vipsListMap[key]
×
2561
                                if vipsList == nil {
×
2562
                                        vipsList = []string{}
×
2563
                                }
×
2564
                                // ipam will ensure the uniqueness of VIP
2565
                                if util.IsValidIP(vip.Status.V4ip) {
×
2566
                                        vipsList = append(vipsList, vip.Status.V4ip)
×
2567
                                }
×
2568
                                if util.IsValidIP(vip.Status.V6ip) {
×
2569
                                        vipsList = append(vipsList, vip.Status.V6ip)
×
2570
                                }
×
2571

2572
                                vipsListMap[key] = vipsList
×
2573
                        }
2574
                }
2575
        }
2576

2577
        for _, podNet := range podNets {
×
2578
                vipStr := pod.Annotations[fmt.Sprintf(util.PortVipAnnotationTemplate, podNet.ProviderName)]
×
2579
                if vipStr == "" {
×
2580
                        continue
×
2581
                }
2582
                key := fmt.Sprintf("%s.%s", podNet.Subnet.Name, podNet.ProviderName)
×
2583
                vipsList := vipsListMap[key]
×
2584
                if vipsList == nil {
×
2585
                        vipsList = []string{}
×
2586
                }
×
2587

2588
                for vip := range strings.SplitSeq(vipStr, ",") {
×
2589
                        if util.IsValidIP(vip) && !slices.Contains(vipsList, vip) {
×
2590
                                vipsList = append(vipsList, vip)
×
2591
                        }
×
2592
                }
2593

2594
                vipsListMap[key] = vipsList
×
2595
        }
2596

2597
        vipsMap := make(map[string]string)
×
2598
        for key, vipsList := range vipsListMap {
×
2599
                vipsMap[key] = strings.Join(vipsList, ",")
×
2600
        }
×
2601
        return vipsMap
×
2602
}
2603

2604
func setPodRoutesAnnotation(annotations map[string]string, provider string, routes []request.Route) error {
×
2605
        key := fmt.Sprintf(util.RoutesAnnotationTemplate, provider)
×
2606
        if len(routes) == 0 {
×
2607
                delete(annotations, key)
×
2608
                return nil
×
2609
        }
×
2610

2611
        buf, err := json.Marshal(routes)
×
2612
        if err != nil {
×
2613
                err = fmt.Errorf("failed to marshal routes %+v: %w", routes, err)
×
2614
                klog.Error(err)
×
2615
                return err
×
2616
        }
×
2617
        annotations[key] = string(buf)
×
2618

×
2619
        return nil
×
2620
}
2621

2622
// Check if pod is a VPC NAT gateway using pod annotations
2623
func (c *Controller) checkIsPodVpcNatGw(pod *v1.Pod) (bool, string) {
1✔
2624
        if pod == nil {
2✔
2625
                return false, ""
1✔
2626
        }
1✔
2627
        if pod.Annotations == nil {
2✔
2628
                return false, ""
1✔
2629
        }
1✔
2630
        vpcGwName, isVpcNatGw := pod.Annotations[util.VpcNatGatewayAnnotation]
1✔
2631
        if isVpcNatGw {
2✔
2632
                if vpcGwName == "" {
2✔
2633
                        klog.Errorf("pod %s is vpc nat gateway but name is empty", pod.Name)
1✔
2634
                        return false, ""
1✔
2635
                }
1✔
2636
                klog.Infof("pod %s is vpc nat gateway %s", pod.Name, vpcGwName)
1✔
2637
        }
2638
        return isVpcNatGw, vpcGwName
1✔
2639
}
2640

2641
func perInterfaceIPAnnotationKey(nadName, nadNamespace, ifaceName string) string {
×
2642
        return fmt.Sprintf("%s.%s.kubernetes.io/ip_address.%s", nadName, nadNamespace, ifaceName)
×
2643
}
×
2644

2645
func perInterfaceMACAnnotationKey(nadName, nadNamespace, ifaceName string) string {
×
2646
        return fmt.Sprintf("%s.%s.kubernetes.io/mac_address.%s", nadName, nadNamespace, ifaceName)
×
2647
}
×
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