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

kubeovn / kube-ovn / 14372473322

10 Apr 2025 04:42AM UTC coverage: 21.704% (-0.3%) from 22.009%
14372473322

Pull #5110

github

zbb88888
fix fmt

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

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

1053 existing lines in 9 files now uncovered.

10263 of 47286 relevant lines covered (21.7%)

0.25 hits per line

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

0.0
/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
        "gopkg.in/k8snetworkplumbingwg/multus-cni.v4/pkg/logging"
20
        multustypes "gopkg.in/k8snetworkplumbingwg/multus-cni.v4/pkg/types"
21
        v1 "k8s.io/api/core/v1"
22
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
23
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24
        "k8s.io/apimachinery/pkg/labels"
25
        "k8s.io/apimachinery/pkg/types"
26
        utilruntime "k8s.io/apimachinery/pkg/util/runtime"
27
        "k8s.io/client-go/kubernetes"
28
        "k8s.io/client-go/tools/cache"
29
        "k8s.io/klog/v2"
30
        "k8s.io/utils/ptr"
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 {
×
87
                                                klog.Warningf("named port %s has already be 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 interface{}) {
×
188
        p := obj.(*v1.Pod)
×
189
        if p.Spec.HostNetwork {
×
190
                return
×
191
        }
×
192

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

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

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

238
func (c *Controller) enqueueDeletePod(obj interface{}) {
×
239
        p := obj.(*v1.Pod)
×
240
        if p.Spec.HostNetwork {
×
241
                return
×
242
        }
×
243

244
        if c.config.EnableNP {
×
245
                c.namedPort.DeleteNamedPortByPod(p)
×
246
                for _, np := range c.podMatchNetworkPolicies(p) {
×
247
                        c.updateNpQueue.Add(np)
×
248
                }
×
249
        }
250

251
        if c.config.EnableANP {
×
252
                podNs, _ := c.namespacesLister.Get(obj.(*v1.Pod).Namespace)
×
253
                c.updateAnpsByLabelsMatch(podNs.Labels, obj.(*v1.Pod).Labels)
×
254
        }
×
255

256
        key := cache.MetaObjectToName(p).String()
×
257
        klog.Infof("enqueue delete pod %s", key)
×
258
        c.deletingPodObjMap.Store(key, p)
×
259
        c.deletePodQueue.Add(key)
×
260
}
261

262
func (c *Controller) enqueueUpdatePod(oldObj, newObj interface{}) {
×
263
        oldPod := oldObj.(*v1.Pod)
×
264
        newPod := newObj.(*v1.Pod)
×
265

×
266
        if oldPod.Annotations[util.AAPsAnnotation] != "" || newPod.Annotations[util.AAPsAnnotation] != "" {
×
267
                oldAAPs := strings.Split(oldPod.Annotations[util.AAPsAnnotation], ",")
×
268
                newAAPs := strings.Split(newPod.Annotations[util.AAPsAnnotation], ",")
×
269
                var vipNames []string
×
270
                for _, vipName := range oldAAPs {
×
271
                        vipNames = append(vipNames, strings.TrimSpace(vipName))
×
272
                }
×
273
                for _, vipName := range newAAPs {
×
274
                        vipName = strings.TrimSpace(vipName)
×
275
                        if !slices.Contains(vipNames, vipName) {
×
276
                                vipNames = append(vipNames, vipName)
×
277
                        }
×
278
                }
279
                for _, vipName := range vipNames {
×
280
                        if vip, err := c.virtualIpsLister.Get(vipName); err == nil {
×
281
                                if vip.Spec.Namespace != newPod.Namespace {
×
282
                                        continue
×
283
                                }
284
                                klog.Infof("enqueue update virtual parents for %s", vipName)
×
285
                                c.updateVirtualParentsQueue.Add(vipName)
×
286
                        }
287
                }
288
        }
289

290
        if oldPod.ResourceVersion == newPod.ResourceVersion {
×
291
                return
×
292
        }
×
293
        if newPod.Spec.HostNetwork {
×
294
                return
×
295
        }
×
296

297
        podNets, err := c.getPodKubeovnNets(newPod)
×
298
        if err != nil {
×
299
                klog.Errorf("failed to get newPod nets %v", err)
×
300
                return
×
301
        }
×
302

303
        key := cache.MetaObjectToName(newPod).String()
×
304
        if c.config.EnableNP {
×
305
                c.namedPort.AddNamedPortByPod(newPod)
×
306
                newNp := c.podMatchNetworkPolicies(newPod)
×
307
                if !maps.Equal(oldPod.Labels, newPod.Labels) {
×
308
                        oldNp := c.podMatchNetworkPolicies(oldPod)
×
309
                        for _, np := range util.DiffStringSlice(oldNp, newNp) {
×
310
                                c.updateNpQueue.Add(np)
×
311
                        }
×
312
                }
313

314
                for _, podNet := range podNets {
×
315
                        oldAllocated := oldPod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, podNet.ProviderName)]
×
316
                        newAllocated := newPod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, podNet.ProviderName)]
×
317
                        if oldAllocated != newAllocated {
×
318
                                for _, np := range newNp {
×
319
                                        klog.V(3).Infof("enqueue update network policy %s for pod %s", np, key)
×
320
                                        c.updateNpQueue.Add(np)
×
321
                                }
×
322
                                break
×
323
                        }
324
                }
325
        }
326

327
        if c.config.EnableANP {
×
328
                podNs, _ := c.namespacesLister.Get(newPod.Namespace)
×
329
                if !maps.Equal(oldPod.Labels, newPod.Labels) {
×
330
                        c.updateAnpsByLabelsMatch(podNs.Labels, newPod.Labels)
×
331
                }
×
332

333
                for _, podNet := range podNets {
×
334
                        oldAllocated := oldPod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, podNet.ProviderName)]
×
335
                        newAllocated := newPod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, podNet.ProviderName)]
×
336
                        if oldAllocated != newAllocated {
×
337
                                c.updateAnpsByLabelsMatch(podNs.Labels, newPod.Labels)
×
338
                                break
×
339
                        }
340
                }
341
        }
342

343
        isStateful, statefulSetName, statefulSetUID := isStatefulSetPod(newPod)
×
344
        isVMPod, vmName := isVMPod(newPod)
×
345
        if !isPodStatusPhaseAlive(newPod) && !isStateful && !isVMPod {
×
346
                klog.V(3).Infof("enqueue delete pod %s", key)
×
347
                c.deletingPodObjMap.Store(key, newPod)
×
348
                c.deletePodQueue.Add(key)
×
349
                return
×
350
        }
×
351

352
        // enqueue delay
353
        var delay time.Duration
×
354
        if newPod.Spec.TerminationGracePeriodSeconds != nil {
×
355
                if !newPod.DeletionTimestamp.IsZero() {
×
356
                        delay = time.Until(newPod.DeletionTimestamp.Add(time.Duration(*newPod.Spec.TerminationGracePeriodSeconds) * time.Second))
×
357
                } else {
×
358
                        delay = time.Duration(*newPod.Spec.TerminationGracePeriodSeconds) * time.Second
×
359
                }
×
360
        }
361

362
        if !newPod.DeletionTimestamp.IsZero() && !isStateful && !isVMPod {
×
363
                go func() {
×
364
                        // In case node get lost and pod can not be deleted,
×
365
                        // the ip address will not be recycled
×
366
                        klog.V(3).Infof("enqueue delete pod %s after %v", key, delay)
×
367
                        c.deletingPodObjMap.Store(key, newPod)
×
368
                        c.deletePodQueue.AddAfter(key, delay)
×
369
                }()
×
370
                return
×
371
        }
372

373
        // do not delete statefulset pod unless ownerReferences is deleted
374
        if isStateful && isStatefulSetPodToDel(c.config.KubeClient, newPod, statefulSetName, statefulSetUID) {
×
375
                go func() {
×
376
                        klog.V(3).Infof("enqueue delete pod %s after %v", key, delay)
×
377
                        c.deletingPodObjMap.Store(key, newPod)
×
378
                        c.deletePodQueue.AddAfter(key, delay)
×
379
                }()
×
380
                return
×
381
        }
382
        if isVMPod && c.isVMToDel(newPod, vmName) {
×
383
                go func() {
×
384
                        klog.V(3).Infof("enqueue delete pod %s after %v", key, delay)
×
385
                        c.deletingPodObjMap.Store(key, newPod)
×
386
                        c.deletePodQueue.AddAfter(key, delay)
×
387
                }()
×
388
                return
×
389
        }
390
        klog.Infof("enqueue update pod %s", key)
×
391
        c.addOrUpdatePodQueue.Add(key)
×
392

×
393
        // security policy changed
×
394
        for _, podNet := range podNets {
×
395
                oldSecurity := oldPod.Annotations[fmt.Sprintf(util.PortSecurityAnnotationTemplate, podNet.ProviderName)]
×
396
                newSecurity := newPod.Annotations[fmt.Sprintf(util.PortSecurityAnnotationTemplate, podNet.ProviderName)]
×
397
                oldSg := oldPod.Annotations[fmt.Sprintf(util.SecurityGroupAnnotationTemplate, podNet.ProviderName)]
×
398
                newSg := newPod.Annotations[fmt.Sprintf(util.SecurityGroupAnnotationTemplate, podNet.ProviderName)]
×
399
                oldVips := oldPod.Annotations[fmt.Sprintf(util.PortVipAnnotationTemplate, podNet.ProviderName)]
×
400
                newVips := newPod.Annotations[fmt.Sprintf(util.PortVipAnnotationTemplate, podNet.ProviderName)]
×
401
                oldAAPs := oldPod.Annotations[util.AAPsAnnotation]
×
402
                newAAPs := newPod.Annotations[util.AAPsAnnotation]
×
403
                if oldSecurity != newSecurity || oldSg != newSg || oldVips != newVips || oldAAPs != newAAPs {
×
404
                        c.updatePodSecurityQueue.Add(key)
×
405
                        break
×
406
                }
407
        }
408
}
409

410
func (c *Controller) getPodKubeovnNets(pod *v1.Pod) ([]*kubeovnNet, error) {
×
411
        defaultSubnet, err := c.getPodDefaultSubnet(pod)
×
412
        if err != nil {
×
413
                klog.Error(err)
×
414
                return nil, err
×
415
        }
×
416

417
        attachmentNets, err := c.getPodAttachmentNet(pod)
×
418
        if err != nil {
×
419
                klog.Error(err)
×
420
                return nil, err
×
421
        }
×
422

423
        podNets := attachmentNets
×
424
        if _, hasOtherDefaultNet := pod.Annotations[util.DefaultNetworkAnnotation]; !hasOtherDefaultNet {
×
425
                podNets = append(attachmentNets, &kubeovnNet{
×
426
                        Type:         providerTypeOriginal,
×
427
                        ProviderName: util.OvnProvider,
×
428
                        Subnet:       defaultSubnet,
×
429
                        IsDefault:    true,
×
430
                })
×
431
        }
×
432

433
        return podNets, nil
×
434
}
435

436
func (c *Controller) handleAddOrUpdatePod(key string) (err error) {
×
437
        namespace, name, err := cache.SplitMetaNamespaceKey(key)
×
438
        if err != nil {
×
439
                utilruntime.HandleError(fmt.Errorf("invalid resource key: %s", key))
×
440
                return nil
×
441
        }
×
442

443
        c.podKeyMutex.LockKey(key)
×
444
        defer func() { _ = c.podKeyMutex.UnlockKey(key) }()
×
445
        klog.Infof("handle add/update pod %s", key)
×
446

×
447
        pod, err := c.podsLister.Pods(namespace).Get(name)
×
448
        if err != nil {
×
449
                if k8serrors.IsNotFound(err) {
×
450
                        return nil
×
451
                }
×
452
                klog.Error(err)
×
453
                return err
×
454
        }
455
        if err := util.ValidatePodNetwork(pod.Annotations); err != nil {
×
456
                klog.Errorf("validate pod %s/%s failed: %v", namespace, name, err)
×
457
                c.recorder.Eventf(pod, v1.EventTypeWarning, "ValidatePodNetworkFailed", err.Error())
×
458
                return err
×
459
        }
×
460

461
        podNets, err := c.getPodKubeovnNets(pod)
×
462
        if err != nil {
×
463
                klog.Errorf("failed to get pod nets %v", err)
×
464
                return err
×
465
        }
×
466

467
        // check and do hotnoplug nic
468
        if pod, err = c.syncKubeOvnNet(pod, podNets); err != nil {
×
469
                klog.Errorf("failed to sync pod nets %v", err)
×
470
                return err
×
471
        }
×
472
        if pod == nil {
×
473
                // pod has been deleted
×
474
                return nil
×
475
        }
×
476
        needAllocatePodNets := needAllocateSubnets(pod, podNets)
×
477
        if len(needAllocatePodNets) != 0 {
×
478
                if pod, err = c.reconcileAllocateSubnets(pod, needAllocatePodNets); err != nil {
×
479
                        klog.Error(err)
×
480
                        return err
×
481
                }
×
482
                if pod == nil {
×
483
                        // pod has been deleted
×
484
                        return nil
×
485
                }
×
486
        }
487

488
        if vpcGwName, isVpcNatGw := pod.Annotations[util.VpcNatGatewayAnnotation]; isVpcNatGw {
×
489
                if needRestartNatGatewayPod(pod) {
×
490
                        c.addOrUpdateVpcNatGatewayQueue.Add(vpcGwName)
×
491
                }
×
492
        }
493

494
        // check if route subnet is need.
495
        return c.reconcileRouteSubnets(pod, needRouteSubnets(pod, podNets))
×
496
}
497

498
// do the same thing as add pod
499
func (c *Controller) reconcileAllocateSubnets(pod *v1.Pod, needAllocatePodNets []*kubeovnNet) (*v1.Pod, error) {
×
500
        namespace := pod.Namespace
×
501
        name := pod.Name
×
502
        klog.Infof("sync pod %s/%s allocated", namespace, name)
×
503

×
504
        vipsMap := c.getVirtualIPs(pod, needAllocatePodNets)
×
505
        isVMPod, vmName := isVMPod(pod)
×
506
        podType := getPodType(pod)
×
507
        podName := c.getNameByPod(pod)
×
508
        // todo: isVmPod, getPodType, getNameByPod has duplicated logic
×
509

×
510
        var err error
×
511
        var vmKey string
×
512
        if isVMPod && c.config.EnableKeepVMIP {
×
513
                vmKey = fmt.Sprintf("%s/%s", namespace, vmName)
×
514
        }
×
515
        // Avoid create lsp for already running pod in ovn-nb when controller restart
516
        patch := util.KVPatch{}
×
517
        for _, podNet := range needAllocatePodNets {
×
518
                // the subnet may changed when alloc static ip from the latter subnet after ns supports multi subnets
×
519
                v4IP, v6IP, mac, subnet, err := c.acquireAddress(pod, podNet)
×
520
                if err != nil {
×
521
                        c.recorder.Eventf(pod, v1.EventTypeWarning, "AcquireAddressFailed", err.Error())
×
522
                        klog.Error(err)
×
523
                        return nil, err
×
524
                }
×
525
                ipStr := util.GetStringIP(v4IP, v6IP)
×
526
                patch[fmt.Sprintf(util.IPAddressAnnotationTemplate, podNet.ProviderName)] = ipStr
×
527
                if mac == "" {
×
528
                        patch[fmt.Sprintf(util.MacAddressAnnotationTemplate, podNet.ProviderName)] = nil
×
529
                } else {
×
530
                        patch[fmt.Sprintf(util.MacAddressAnnotationTemplate, podNet.ProviderName)] = mac
×
531
                }
×
532
                patch[fmt.Sprintf(util.CidrAnnotationTemplate, podNet.ProviderName)] = subnet.Spec.CIDRBlock
×
533
                patch[fmt.Sprintf(util.GatewayAnnotationTemplate, podNet.ProviderName)] = subnet.Spec.Gateway
×
534
                if isOvnSubnet(podNet.Subnet) {
×
535
                        patch[fmt.Sprintf(util.LogicalSwitchAnnotationTemplate, podNet.ProviderName)] = subnet.Name
×
536
                        if pod.Annotations[fmt.Sprintf(util.PodNicAnnotationTemplate, podNet.ProviderName)] == "" {
×
537
                                patch[fmt.Sprintf(util.PodNicAnnotationTemplate, podNet.ProviderName)] = c.config.PodNicType
×
538
                        }
×
539
                } else {
×
540
                        patch[fmt.Sprintf(util.LogicalSwitchAnnotationTemplate, podNet.ProviderName)] = nil
×
541
                        patch[fmt.Sprintf(util.PodNicAnnotationTemplate, podNet.ProviderName)] = nil
×
542
                }
×
543
                patch[fmt.Sprintf(util.AllocatedAnnotationTemplate, podNet.ProviderName)] = "true"
×
544
                if vmKey != "" {
×
545
                        patch[fmt.Sprintf(util.VMAnnotationTemplate, podNet.ProviderName)] = vmName
×
546
                }
×
547
                if err := util.ValidateNetworkBroadcast(podNet.Subnet.Spec.CIDRBlock, ipStr); err != nil {
×
548
                        klog.Errorf("validate pod %s/%s failed: %v", namespace, name, err)
×
549
                        c.recorder.Eventf(pod, v1.EventTypeWarning, "ValidatePodNetworkFailed", err.Error())
×
550
                        return nil, err
×
551
                }
×
552

553
                if podNet.Type != providerTypeIPAM {
×
554
                        if (subnet.Spec.Vlan == "" || subnet.Spec.LogicalGateway || subnet.Spec.U2OInterconnection) && subnet.Spec.Vpc != "" {
×
555
                                patch[fmt.Sprintf(util.LogicalRouterAnnotationTemplate, podNet.ProviderName)] = subnet.Spec.Vpc
×
556
                        }
×
557

558
                        if subnet.Spec.Vlan != "" {
×
559
                                vlan, err := c.vlansLister.Get(subnet.Spec.Vlan)
×
560
                                if err != nil {
×
561
                                        klog.Error(err)
×
562
                                        c.recorder.Eventf(pod, v1.EventTypeWarning, "GetVlanInfoFailed", err.Error())
×
563
                                        return nil, err
×
564
                                }
×
565
                                patch[fmt.Sprintf(util.VlanIDAnnotationTemplate, podNet.ProviderName)] = strconv.Itoa(vlan.Spec.ID)
×
566
                                patch[fmt.Sprintf(util.ProviderNetworkTemplate, podNet.ProviderName)] = vlan.Spec.Provider
×
567
                        }
568

569
                        portSecurity := false
×
570
                        if pod.Annotations[fmt.Sprintf(util.PortSecurityAnnotationTemplate, podNet.ProviderName)] == "true" {
×
571
                                portSecurity = true
×
572
                        }
×
573

574
                        vips := vipsMap[fmt.Sprintf("%s.%s", podNet.Subnet.Name, podNet.ProviderName)]
×
575
                        for _, ip := range strings.Split(vips, ",") {
×
576
                                if ip != "" && net.ParseIP(ip) == nil {
×
577
                                        klog.Errorf("invalid vip address '%s' for pod %s", ip, name)
×
578
                                        vips = ""
×
579
                                        break
×
580
                                }
581
                        }
582

583
                        portName := ovs.PodNameToPortName(podName, namespace, podNet.ProviderName)
×
584
                        dhcpOptions := &ovs.DHCPOptionsUUIDs{
×
585
                                DHCPv4OptionsUUID: subnet.Status.DHCPv4OptionsUUID,
×
586
                                DHCPv6OptionsUUID: subnet.Status.DHCPv6OptionsUUID,
×
587
                        }
×
588

×
589
                        var oldSgList []string
×
590
                        if vmKey != "" {
×
591
                                existingLsp, err := c.OVNNbClient.GetLogicalSwitchPort(portName, true)
×
592
                                if err != nil {
×
593
                                        klog.Errorf("failed to get logical switch port %s: %v", portName, err)
×
594
                                        return nil, err
×
595
                                }
×
596
                                if existingLsp != nil {
×
597
                                        oldSgList, _ = c.getPortSg(existingLsp)
×
598
                                }
×
599
                        }
600

601
                        securityGroupAnnotation := pod.Annotations[fmt.Sprintf(util.SecurityGroupAnnotationTemplate, podNet.ProviderName)]
×
602
                        if err := c.OVNNbClient.CreateLogicalSwitchPort(subnet.Name, portName, ipStr, mac, podName, pod.Namespace,
×
603
                                portSecurity, securityGroupAnnotation, vips, podNet.Subnet.Spec.EnableDHCP, dhcpOptions, subnet.Spec.Vpc); err != nil {
×
604
                                c.recorder.Eventf(pod, v1.EventTypeWarning, "CreateOVNPortFailed", err.Error())
×
605
                                klog.Errorf("%v", err)
×
606
                                return nil, err
×
607
                        }
×
608

609
                        if pod.Annotations[fmt.Sprintf(util.Layer2ForwardAnnotationTemplate, podNet.ProviderName)] == "true" {
×
610
                                if err := c.OVNNbClient.EnablePortLayer2forward(portName); err != nil {
×
611
                                        c.recorder.Eventf(pod, v1.EventTypeWarning, "SetOVNPortL2ForwardFailed", err.Error())
×
612
                                        klog.Errorf("%v", err)
×
613
                                        return nil, err
×
614
                                }
×
615
                        }
616

617
                        if securityGroupAnnotation != "" || oldSgList != nil {
×
618
                                securityGroups := strings.ReplaceAll(securityGroupAnnotation, " ", "")
×
619
                                newSgList := strings.Split(securityGroups, ",")
×
620
                                sgNames := util.UnionStringSlice(oldSgList, newSgList)
×
621
                                for _, sgName := range sgNames {
×
622
                                        if sgName != "" {
×
623
                                                c.syncSgPortsQueue.Add(sgName)
×
624
                                        }
×
625
                                }
626
                        }
627

628
                        if vips != "" {
×
629
                                c.syncVirtualPortsQueue.Add(podNet.Subnet.Name)
×
630
                        }
×
631
                }
632
                // CreatePort may fail, so put ip CR creation after CreatePort
633
                ipCRName := ovs.PodNameToPortName(podName, pod.Namespace, podNet.ProviderName)
×
634
                if err := c.createOrUpdateIPCR(ipCRName, podName, ipStr, mac, subnet.Name, pod.Namespace, pod.Spec.NodeName, podType); err != nil {
×
635
                        err = fmt.Errorf("failed to create ips CR %s.%s: %w", podName, pod.Namespace, err)
×
636
                        klog.Error(err)
×
637
                        return nil, err
×
638
                }
×
639
        }
640
        if err = util.PatchAnnotations(c.config.KubeClient.CoreV1().Pods(namespace), name, patch); err != nil {
×
641
                if k8serrors.IsNotFound(err) {
×
642
                        // Sometimes pod is deleted between kube-ovn configure ovn-nb and patch pod.
×
643
                        // Then we need to recycle the resource again.
×
644
                        key := strings.Join([]string{namespace, name}, "/")
×
645
                        c.deletingPodObjMap.Store(key, pod)
×
646
                        c.deletePodQueue.AddRateLimited(key)
×
647
                        return nil, nil
×
648
                }
×
649
                klog.Errorf("failed to patch pod %s/%s: %v", namespace, name, err)
×
650
                return nil, err
×
651
        }
652

653
        if pod, err = c.config.KubeClient.CoreV1().Pods(namespace).Get(context.TODO(), name, metav1.GetOptions{}); err != nil {
×
654
                if k8serrors.IsNotFound(err) {
×
655
                        key := strings.Join([]string{namespace, name}, "/")
×
656
                        c.deletingPodObjMap.Store(key, pod)
×
657
                        c.deletePodQueue.AddRateLimited(key)
×
658
                        return nil, nil
×
659
                }
×
660
                klog.Errorf("failed to get pod %s/%s: %v", namespace, name, err)
×
661
                return nil, err
×
662
        }
663

664
        if vpcGwName, isVpcNatGw := pod.Annotations[util.VpcNatGatewayAnnotation]; isVpcNatGw {
×
665
                c.initVpcNatGatewayQueue.Add(vpcGwName)
×
666
        }
×
667
        return pod, nil
×
668
}
669

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

677
        if len(needRoutePodNets) == 0 {
×
678
                return nil
×
679
        }
×
680

681
        namespace := pod.Namespace
×
682
        name := pod.Name
×
683
        podName := c.getNameByPod(pod)
×
684

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

×
687
        var podIP string
×
688
        var subnet *kubeovnv1.Subnet
×
689
        patch := util.KVPatch{}
×
690
        for _, podNet := range needRoutePodNets {
×
691
                // in case update handler overlap the annotation when cache is not in sync
×
692
                if pod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, podNet.ProviderName)] == "" {
×
693
                        return fmt.Errorf("no address has been allocated to %s/%s", namespace, name)
×
694
                }
×
695

696
                podIP = pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, podNet.ProviderName)]
×
697
                subnet = podNet.Subnet
×
698

×
699
                // Check if pod uses nodeSwitch subnet
×
700
                if subnet.Name == c.config.NodeSwitch {
×
701
                        return fmt.Errorf("NodeSwitch subnet %s is unavailable for pod", subnet.Name)
×
702
                }
×
703

704
                portName := ovs.PodNameToPortName(podName, pod.Namespace, podNet.ProviderName)
×
705
                if (!c.config.EnableLb || (subnet.Spec.EnableLb == nil || !*subnet.Spec.EnableLb)) &&
×
706
                        subnet.Spec.Vpc == c.config.ClusterRouter &&
×
707
                        subnet.Spec.U2OInterconnection &&
×
708
                        subnet.Spec.Vlan != "" &&
×
709
                        !subnet.Spec.LogicalGateway {
×
710
                        pgName := getOverlaySubnetsPortGroupName(subnet.Name, pod.Spec.NodeName)
×
711
                        if err := c.OVNNbClient.PortGroupAddPorts(pgName, portName); err != nil {
×
712
                                klog.Errorf("failed to add port to u2o port group %s: %v", pgName, err)
×
713
                                return err
×
714
                        }
×
715
                }
716

717
                if podIP != "" && (subnet.Spec.Vlan == "" || subnet.Spec.LogicalGateway) && subnet.Spec.Vpc == c.config.ClusterRouter {
×
718
                        node, err := c.nodesLister.Get(pod.Spec.NodeName)
×
719
                        if err != nil {
×
720
                                klog.Errorf("failed to get node %s: %v", pod.Spec.NodeName, err)
×
721
                                return err
×
722
                        }
×
723

724
                        pgName := getOverlaySubnetsPortGroupName(subnet.Name, node.Name)
×
725
                        if c.config.EnableEipSnat && (pod.Annotations[util.EipAnnotation] != "" || pod.Annotations[util.SnatAnnotation] != "") {
×
726
                                cm, err := c.configMapsLister.ConfigMaps(c.config.ExternalGatewayConfigNS).Get(util.ExternalGatewayConfig)
×
727
                                if err != nil {
×
728
                                        klog.Errorf("failed to get ex-gateway config, %v", err)
×
729
                                        return err
×
730
                                }
×
731
                                nextHop := cm.Data["external-gw-addr"]
×
732
                                if nextHop == "" {
×
733
                                        externalSubnet, err := c.subnetsLister.Get(c.config.ExternalGatewaySwitch)
×
734
                                        if err != nil {
×
735
                                                klog.Errorf("failed to get subnet %s, %v", c.config.ExternalGatewaySwitch, err)
×
736
                                                return err
×
737
                                        }
×
738
                                        nextHop = externalSubnet.Spec.Gateway
×
739
                                        if nextHop == "" {
×
740
                                                klog.Errorf("no available gateway address")
×
741
                                                return errors.New("no available gateway address")
×
742
                                        }
×
743
                                }
744
                                if strings.Contains(nextHop, "/") {
×
745
                                        nextHop = strings.Split(nextHop, "/")[0]
×
746
                                }
×
747

748
                                if err := c.addPolicyRouteToVpc(
×
749
                                        subnet.Spec.Vpc,
×
750
                                        &kubeovnv1.PolicyRoute{
×
751
                                                Priority:  util.NorthGatewayRoutePolicyPriority,
×
752
                                                Match:     fmt.Sprintf("ip4.src == %s", podIP),
×
753
                                                Action:    kubeovnv1.PolicyRouteActionReroute,
×
754
                                                NextHopIP: nextHop,
×
755
                                        },
×
756
                                        map[string]string{
×
757
                                                "vendor": util.CniTypeName,
×
758
                                                "subnet": subnet.Name,
×
759
                                        },
×
760
                                ); err != nil {
×
761
                                        klog.Errorf("failed to add policy route, %v", err)
×
762
                                        return err
×
763
                                }
×
764

765
                                // remove lsp from port group to make EIP/SNAT work
766
                                if err = c.OVNNbClient.PortGroupRemovePorts(pgName, portName); err != nil {
×
767
                                        klog.Error(err)
×
768
                                        return err
×
769
                                }
×
770
                        } else {
×
771
                                if subnet.Spec.GatewayType == kubeovnv1.GWDistributedType && pod.Annotations[util.NorthGatewayAnnotation] == "" {
×
772
                                        nodeTunlIPAddr, err := getNodeTunlIP(node)
×
773
                                        if err != nil {
×
774
                                                klog.Error(err)
×
775
                                                return err
×
776
                                        }
×
777

778
                                        var added bool
×
779

×
780
                                        for _, nodeAddr := range nodeTunlIPAddr {
×
781
                                                for _, podAddr := range strings.Split(podIP, ",") {
×
782
                                                        if util.CheckProtocol(nodeAddr.String()) != util.CheckProtocol(podAddr) {
×
783
                                                                continue
×
784
                                                        }
785

786
                                                        if err := c.OVNNbClient.PortGroupAddPorts(pgName, portName); err != nil {
×
787
                                                                klog.Errorf("add port to port group %s: %v", pgName, err)
×
788
                                                                return err
×
789
                                                        }
×
790

791
                                                        added = true
×
792
                                                        break
×
793
                                                }
794
                                                if added {
×
795
                                                        break
×
796
                                                }
797
                                        }
798
                                }
799

800
                                if pod.Annotations[util.NorthGatewayAnnotation] != "" && pod.Annotations[util.IPAddressAnnotation] != "" {
×
801
                                        for _, podAddr := range strings.Split(pod.Annotations[util.IPAddressAnnotation], ",") {
×
802
                                                if util.CheckProtocol(podAddr) != util.CheckProtocol(pod.Annotations[util.NorthGatewayAnnotation]) {
×
803
                                                        continue
×
804
                                                }
805
                                                ipSuffix := "ip4"
×
806
                                                if util.CheckProtocol(podAddr) == kubeovnv1.ProtocolIPv6 {
×
807
                                                        ipSuffix = "ip6"
×
808
                                                }
×
809

810
                                                if err := c.addPolicyRouteToVpc(
×
811
                                                        subnet.Spec.Vpc,
×
812
                                                        &kubeovnv1.PolicyRoute{
×
813
                                                                Priority:  util.NorthGatewayRoutePolicyPriority,
×
814
                                                                Match:     fmt.Sprintf("%s.src == %s", ipSuffix, podAddr),
×
815
                                                                Action:    kubeovnv1.PolicyRouteActionReroute,
×
816
                                                                NextHopIP: pod.Annotations[util.NorthGatewayAnnotation],
×
817
                                                        },
×
818
                                                        map[string]string{
×
819
                                                                "vendor": util.CniTypeName,
×
820
                                                                "subnet": subnet.Name,
×
821
                                                        },
×
822
                                                ); err != nil {
×
823
                                                        klog.Errorf("failed to add policy route, %v", err)
×
824
                                                        return err
×
825
                                                }
×
826
                                        }
827
                                } else if c.config.EnableEipSnat {
×
828
                                        if err = c.deleteStaticRouteFromVpc(
×
829
                                                c.config.ClusterRouter,
×
830
                                                subnet.Spec.RouteTable,
×
831
                                                podIP,
×
832
                                                "",
×
833
                                                kubeovnv1.PolicyDst,
×
834
                                        ); err != nil {
×
835
                                                klog.Error(err)
×
836
                                                return err
×
837
                                        }
×
838
                                }
839
                        }
840

841
                        if c.config.EnableEipSnat {
×
842
                                for _, ipStr := range strings.Split(podIP, ",") {
×
843
                                        if eip := pod.Annotations[util.EipAnnotation]; eip == "" {
×
844
                                                if err = c.OVNNbClient.DeleteNats(c.config.ClusterRouter, ovnnb.NATTypeDNATAndSNAT, ipStr); err != nil {
×
845
                                                        klog.Errorf("failed to delete nat rules: %v", err)
×
846
                                                }
×
847
                                        } else if util.CheckProtocol(eip) == util.CheckProtocol(ipStr) {
×
848
                                                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 {
×
849
                                                        klog.Errorf("failed to add nat rules, %v", err)
×
850
                                                        return err
×
851
                                                }
×
852
                                        }
853
                                        if eip := pod.Annotations[util.SnatAnnotation]; eip == "" {
×
854
                                                if err = c.OVNNbClient.DeleteNats(c.config.ClusterRouter, ovnnb.NATTypeSNAT, ipStr); err != nil {
×
855
                                                        klog.Errorf("failed to delete nat rules: %v", err)
×
856
                                                }
×
857
                                        } else if util.CheckProtocol(eip) == util.CheckProtocol(ipStr) {
×
858
                                                if err = c.OVNNbClient.UpdateSnat(c.config.ClusterRouter, eip, ipStr); err != nil {
×
859
                                                        klog.Errorf("failed to add nat rules, %v", err)
×
860
                                                        return err
×
861
                                                }
×
862
                                        }
863
                                }
864
                        }
865
                }
866

867
                if pod.Annotations[fmt.Sprintf(util.ActivationStrategyTemplate, podNet.ProviderName)] != "" {
×
868
                        if err := c.OVNNbClient.SetLogicalSwitchPortActivationStrategy(portName, pod.Spec.NodeName); err != nil {
×
869
                                klog.Errorf("failed to set activation strategy for lsp %s: %v", portName, err)
×
870
                                return err
×
871
                        }
×
872
                }
873

874
                patch[fmt.Sprintf(util.RoutedAnnotationTemplate, podNet.ProviderName)] = "true"
×
875
        }
876
        if err := util.PatchAnnotations(c.config.KubeClient.CoreV1().Pods(namespace), name, patch); err != nil {
×
877
                if k8serrors.IsNotFound(err) {
×
878
                        // Sometimes pod is deleted between kube-ovn configure ovn-nb and patch pod.
×
879
                        // Then we need to recycle the resource again.
×
880
                        key := strings.Join([]string{namespace, name}, "/")
×
881
                        c.deletingPodObjMap.Store(key, pod)
×
882
                        c.deletePodQueue.AddRateLimited(key)
×
883
                        return nil
×
884
                }
×
885
                klog.Errorf("failed to patch pod %s/%s: %v", namespace, name, err)
×
886
                return err
×
887
        }
888
        return nil
×
889
}
890

891
func (c *Controller) handleDeletePod(key string) (err error) {
×
892
        pod, ok := c.deletingPodObjMap.Load(key)
×
893
        if !ok {
×
894
                return nil
×
895
        }
×
896
        podName := c.getNameByPod(pod)
×
897
        c.podKeyMutex.LockKey(key)
×
898
        defer func() {
×
899
                _ = c.podKeyMutex.UnlockKey(key)
×
900
                if err == nil {
×
901
                        c.deletingPodObjMap.Delete(key)
×
902
                }
×
903
        }()
904
        klog.Infof("handle delete pod %s", key)
×
905

×
906
        p, _ := c.podsLister.Pods(pod.Namespace).Get(pod.Name)
×
907
        if p != nil && p.UID != pod.UID {
×
908
                // Pod with same name exists, just return here
×
909
                return nil
×
910
        }
×
911

912
        if aaps := pod.Annotations[util.AAPsAnnotation]; aaps != "" {
×
913
                for _, vipName := range strings.Split(aaps, ",") {
×
914
                        if vip, err := c.virtualIpsLister.Get(vipName); err == nil {
×
915
                                if vip.Spec.Namespace != pod.Namespace {
×
916
                                        continue
×
917
                                }
918
                                klog.Infof("enqueue update virtual parents for %s", vipName)
×
919
                                c.updateVirtualParentsQueue.Add(vipName)
×
920
                        }
921
                }
922
        }
923

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

×
926
        var keepIPCR bool
×
927
        if ok, stsName, stsUID := isStatefulSetPod(pod); ok {
×
928
                if pod.DeletionTimestamp != nil {
×
929
                        klog.Infof("handle deletion of sts pod %s", podName)
×
930
                        toDel := isStatefulSetPodToDel(c.config.KubeClient, pod, stsName, stsUID)
×
931
                        if !toDel {
×
932
                                klog.Infof("try keep ip for sts pod %s", podKey)
×
933
                                keepIPCR = true
×
934
                        }
×
935
                }
936
                if keepIPCR {
×
937
                        isDelete, err := appendCheckPodToDel(c, pod, stsName, util.StatefulSet)
×
938
                        if err != nil {
×
939
                                klog.Error(err)
×
940
                                return err
×
941
                        }
×
942
                        if isDelete {
×
943
                                klog.Infof("not keep ip for sts pod %s", podKey)
×
944
                                keepIPCR = false
×
945
                        }
×
946
                }
947
        }
948
        isVMPod, vmName := isVMPod(pod)
×
949
        if isVMPod && c.config.EnableKeepVMIP {
×
950
                ports, err := c.OVNNbClient.ListNormalLogicalSwitchPorts(true, map[string]string{"pod": podKey})
×
951
                if err != nil {
×
952
                        klog.Errorf("failed to list lsps of pod '%s', %v", pod.Name, err)
×
953
                        return err
×
954
                }
×
955
                for _, port := range ports {
×
956
                        if err := c.OVNNbClient.CleanLogicalSwitchPortMigrateOptions(port.Name); err != nil {
×
957
                                err = fmt.Errorf("failed to clean migrate options for vm lsp %s, %w", port.Name, err)
×
958
                                klog.Error(err)
×
959
                                return err
×
960
                        }
×
961
                }
962
                if pod.DeletionTimestamp != nil {
×
963
                        klog.Infof("handle deletion of vm pod %s", podName)
×
964
                        vmToBeDel := c.isVMToDel(pod, vmName)
×
965
                        if !vmToBeDel {
×
966
                                klog.Infof("try keep ip for vm pod %s", podKey)
×
967
                                keepIPCR = true
×
968
                        }
×
969
                }
970
                if keepIPCR {
×
971
                        isDelete, err := appendCheckPodToDel(c, pod, vmName, util.VMInstance)
×
972
                        if err != nil {
×
973
                                klog.Error(err)
×
974
                                return err
×
975
                        }
×
976
                        if isDelete {
×
977
                                klog.Infof("not keep ip for vm pod %s", podKey)
×
978
                                keepIPCR = false
×
979
                        }
×
980
                }
981
        }
982

983
        podNets, err := c.getPodKubeovnNets(pod)
×
984
        if err != nil {
×
985
                klog.Errorf("failed to get pod nets %v", err)
×
986
        }
×
987
        if !keepIPCR {
×
988
                ports, err := c.OVNNbClient.ListNormalLogicalSwitchPorts(true, map[string]string{"pod": podKey})
×
989
                if err != nil {
×
990
                        klog.Errorf("failed to list lsps of pod '%s', %v", pod.Name, err)
×
991
                        return err
×
992
                }
×
993

994
                if len(ports) != 0 {
×
995
                        addresses := c.ipam.GetPodAddress(podKey)
×
996
                        for _, address := range addresses {
×
997
                                if strings.TrimSpace(address.IP) == "" {
×
998
                                        continue
×
999
                                }
1000
                                subnet, err := c.subnetsLister.Get(address.Subnet.Name)
×
1001
                                if k8serrors.IsNotFound(err) {
×
1002
                                        continue
×
1003
                                } else if err != nil {
×
1004
                                        klog.Error(err)
×
1005
                                        return err
×
1006
                                }
×
1007
                                vpc, err := c.vpcsLister.Get(subnet.Spec.Vpc)
×
1008
                                if k8serrors.IsNotFound(err) {
×
1009
                                        continue
×
1010
                                } else if err != nil {
×
1011
                                        klog.Error(err)
×
1012
                                        return err
×
1013
                                }
×
1014

1015
                                ipSuffix := "ip4"
×
1016
                                if util.CheckProtocol(address.IP) == kubeovnv1.ProtocolIPv6 {
×
1017
                                        ipSuffix = "ip6"
×
1018
                                }
×
1019
                                if err = c.deletePolicyRouteFromVpc(
×
1020
                                        vpc.Name,
×
1021
                                        util.NorthGatewayRoutePolicyPriority,
×
1022
                                        fmt.Sprintf("%s.src == %s", ipSuffix, address.IP),
×
1023
                                ); err != nil {
×
1024
                                        klog.Errorf("failed to delete static route, %v", err)
×
1025
                                        return err
×
1026
                                }
×
1027

1028
                                if c.config.EnableEipSnat {
×
1029
                                        if pod.Annotations[util.EipAnnotation] != "" {
×
1030
                                                if err = c.OVNNbClient.DeleteNat(c.config.ClusterRouter, ovnnb.NATTypeDNATAndSNAT, pod.Annotations[util.EipAnnotation], address.IP); err != nil {
×
1031
                                                        klog.Errorf("failed to delete nat rules: %v", err)
×
1032
                                                }
×
1033
                                        }
1034
                                        if pod.Annotations[util.SnatAnnotation] != "" {
×
1035
                                                if err = c.OVNNbClient.DeleteNat(c.config.ClusterRouter, ovnnb.NATTypeSNAT, "", address.IP); err != nil {
×
1036
                                                        klog.Errorf("failed to delete nat rules: %v", err)
×
1037
                                                }
×
1038
                                        }
1039
                                }
1040
                        }
1041
                }
1042
                for _, port := range ports {
×
1043
                        // when lsp is deleted, the port of pod is deleted from any port-group automatically.
×
1044
                        klog.Infof("delete logical switch port %s", port.Name)
×
1045
                        if err := c.OVNNbClient.DeleteLogicalSwitchPort(port.Name); err != nil {
×
1046
                                klog.Errorf("failed to delete lsp %s, %v", port.Name, err)
×
1047
                                return err
×
1048
                        }
×
1049
                }
1050
                klog.Infof("try release all ip address for deleting pod %s", podKey)
×
1051
                for _, podNet := range podNets {
×
1052
                        portName := ovs.PodNameToPortName(podName, pod.Namespace, podNet.ProviderName)
×
1053
                        ipCR, err := c.ipsLister.Get(portName)
×
1054
                        if err != nil {
×
1055
                                if k8serrors.IsNotFound(err) {
×
1056
                                        continue
×
1057
                                }
1058
                                klog.Errorf("failed to get ip %s, %v", portName, err)
×
1059
                                return err
×
1060
                        }
1061
                        if ipCR.Labels[util.IPReservedLabel] != "true" {
×
1062
                                klog.Infof("delete ip CR %s", ipCR.Name)
×
1063
                                if err := c.config.KubeOvnClient.KubeovnV1().IPs().Delete(context.Background(), ipCR.Name, metav1.DeleteOptions{}); err != nil {
×
1064
                                        if !k8serrors.IsNotFound(err) {
×
1065
                                                klog.Errorf("failed to delete ip %s, %v", ipCR.Name, err)
×
1066
                                                return err
×
1067
                                        }
×
1068
                                }
1069
                                // release ipam address after delete ip CR
1070
                                c.ipam.ReleaseAddressByPod(podKey, podNet.Subnet.Name)
×
1071
                        }
1072
                }
1073
                if pod.Annotations[util.VipAnnotation] != "" {
×
1074
                        if err = c.releaseVip(pod.Annotations[util.VipAnnotation]); err != nil {
×
1075
                                klog.Errorf("failed to clean label from vip %s, %v", pod.Annotations[util.VipAnnotation], err)
×
1076
                                return err
×
1077
                        }
×
1078
                }
1079
        }
1080
        for _, podNet := range podNets {
×
1081
                c.syncVirtualPortsQueue.Add(podNet.Subnet.Name)
×
1082
                securityGroupAnnotation := pod.Annotations[fmt.Sprintf(util.SecurityGroupAnnotationTemplate, podNet.ProviderName)]
×
1083
                if securityGroupAnnotation != "" {
×
1084
                        securityGroups := strings.ReplaceAll(securityGroupAnnotation, " ", "")
×
1085
                        for _, sgName := range strings.Split(securityGroups, ",") {
×
1086
                                if sgName != "" {
×
1087
                                        c.syncSgPortsQueue.Add(sgName)
×
1088
                                }
×
1089
                        }
1090
                }
1091
        }
1092
        return nil
×
1093
}
1094

1095
func (c *Controller) handleUpdatePodSecurity(key string) error {
×
1096
        namespace, name, err := cache.SplitMetaNamespaceKey(key)
×
1097
        if err != nil {
×
1098
                utilruntime.HandleError(fmt.Errorf("invalid resource key: %s", key))
×
1099
                return nil
×
1100
        }
×
1101

1102
        c.podKeyMutex.LockKey(key)
×
1103
        defer func() { _ = c.podKeyMutex.UnlockKey(key) }()
×
1104

1105
        pod, err := c.podsLister.Pods(namespace).Get(name)
×
1106
        if err != nil {
×
1107
                if k8serrors.IsNotFound(err) {
×
1108
                        return nil
×
1109
                }
×
1110
                klog.Error(err)
×
1111
                return err
×
1112
        }
1113
        podName := c.getNameByPod(pod)
×
1114

×
1115
        klog.Infof("update pod %s/%s security", namespace, name)
×
1116

×
1117
        podNets, err := c.getPodKubeovnNets(pod)
×
1118
        if err != nil {
×
1119
                klog.Errorf("failed to pod nets %v", err)
×
1120
                return err
×
1121
        }
×
1122

1123
        vipsMap := c.getVirtualIPs(pod, podNets)
×
1124

×
1125
        // associated with security group
×
1126
        for _, podNet := range podNets {
×
1127
                portSecurity := false
×
1128
                if pod.Annotations[fmt.Sprintf(util.PortSecurityAnnotationTemplate, podNet.ProviderName)] == "true" {
×
1129
                        portSecurity = true
×
1130
                }
×
1131

1132
                mac := pod.Annotations[fmt.Sprintf(util.MacAddressAnnotationTemplate, podNet.ProviderName)]
×
1133
                ipStr := pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, podNet.ProviderName)]
×
1134
                vips := vipsMap[fmt.Sprintf("%s.%s", podNet.Subnet.Name, podNet.ProviderName)]
×
1135

×
1136
                if err = c.OVNNbClient.SetLogicalSwitchPortSecurity(portSecurity, ovs.PodNameToPortName(podName, namespace, podNet.ProviderName), mac, ipStr, vips); err != nil {
×
1137
                        klog.Errorf("set logical switch port security: %v", err)
×
1138
                        return err
×
1139
                }
×
1140

1141
                c.syncVirtualPortsQueue.Add(podNet.Subnet.Name)
×
1142
                securityGroupAnnotation := pod.Annotations[fmt.Sprintf(util.SecurityGroupAnnotationTemplate, podNet.ProviderName)]
×
1143
                var securityGroups string
×
1144
                if securityGroupAnnotation != "" {
×
1145
                        securityGroups = strings.ReplaceAll(securityGroupAnnotation, " ", "")
×
1146
                        for _, sgName := range strings.Split(securityGroups, ",") {
×
1147
                                if sgName != "" {
×
1148
                                        c.syncSgPortsQueue.Add(sgName)
×
1149
                                }
×
1150
                        }
1151
                }
1152
                if err = c.reconcilePortSg(ovs.PodNameToPortName(podName, namespace, podNet.ProviderName), securityGroups); err != nil {
×
1153
                        klog.Errorf("reconcilePortSg failed. %v", err)
×
1154
                        return err
×
1155
                }
×
1156
        }
1157
        return nil
×
1158
}
1159

1160
func (c *Controller) syncKubeOvnNet(pod *v1.Pod, podNets []*kubeovnNet) (*v1.Pod, error) {
×
1161
        podName := c.getNameByPod(pod)
×
1162
        key := fmt.Sprintf("%s/%s", pod.Namespace, podName)
×
1163
        targetPortNameList := strset.NewWithSize(len(podNets))
×
1164
        portsNeedToDel := []string{}
×
1165
        annotationsNeedToDel := []string{}
×
1166
        annotationsNeedToAdd := make(map[string]string)
×
1167
        subnetUsedByPort := make(map[string]string)
×
1168

×
1169
        for _, podNet := range podNets {
×
1170
                portName := ovs.PodNameToPortName(podName, pod.Namespace, podNet.ProviderName)
×
1171
                targetPortNameList.Add(portName)
×
1172
                if podNet.IPRequest != "" {
×
1173
                        klog.Infof("pod %s/%s use custom IP %s for provider %s", pod.Namespace, pod.Name, podNet.IPRequest, podNet.ProviderName)
×
1174
                        annotationsNeedToAdd[fmt.Sprintf(util.IPAddressAnnotationTemplate, podNet.ProviderName)] = podNet.IPRequest
×
1175
                }
×
1176

1177
                if podNet.MacRequest != "" {
×
1178
                        klog.Infof("pod %s/%s use custom MAC %s for provider %s", pod.Namespace, pod.Name, podNet.MacRequest, podNet.ProviderName)
×
1179
                        annotationsNeedToAdd[fmt.Sprintf(util.MacAddressAnnotationTemplate, podNet.ProviderName)] = podNet.MacRequest
×
1180
                }
×
1181
        }
1182

1183
        ports, err := c.OVNNbClient.ListNormalLogicalSwitchPorts(true, map[string]string{"pod": key})
×
1184
        if err != nil {
×
1185
                klog.Errorf("failed to list lsps of pod '%s', %v", pod.Name, err)
×
1186
                return nil, err
×
1187
        }
×
1188

1189
        for _, port := range ports {
×
1190
                if !targetPortNameList.Has(port.Name) {
×
1191
                        portsNeedToDel = append(portsNeedToDel, port.Name)
×
1192
                        subnetUsedByPort[port.Name] = port.ExternalIDs["ls"]
×
1193
                        portNameSlice := strings.Split(port.Name, ".")
×
1194
                        providerName := strings.Join(portNameSlice[2:], ".")
×
1195
                        if providerName == util.OvnProvider {
×
1196
                                continue
×
1197
                        }
1198
                        annotationsNeedToDel = append(annotationsNeedToDel, providerName)
×
1199
                }
1200
        }
1201

1202
        if len(portsNeedToDel) == 0 && len(annotationsNeedToAdd) == 0 {
×
1203
                return pod, nil
×
1204
        }
×
1205

1206
        for _, portNeedDel := range portsNeedToDel {
×
1207
                klog.Infof("release port %s for pod %s", portNeedDel, podName)
×
1208
                if subnet, ok := c.ipam.Subnets[subnetUsedByPort[portNeedDel]]; ok {
×
1209
                        subnet.ReleaseAddressWithNicName(podName, portNeedDel)
×
1210
                }
×
1211
                if err := c.OVNNbClient.DeleteLogicalSwitchPort(portNeedDel); err != nil {
×
1212
                        klog.Errorf("failed to delete lsp %s, %v", portNeedDel, err)
×
1213
                        return nil, err
×
1214
                }
×
1215
                if err := c.config.KubeOvnClient.KubeovnV1().IPs().Delete(context.Background(), portNeedDel, metav1.DeleteOptions{}); err != nil {
×
1216
                        if !k8serrors.IsNotFound(err) {
×
1217
                                klog.Errorf("failed to delete ip %s, %v", portNeedDel, err)
×
1218
                                return nil, err
×
1219
                        }
×
1220
                }
1221
        }
1222

1223
        patch := util.KVPatch{}
×
1224
        for _, providerName := range annotationsNeedToDel {
×
1225
                for key := range pod.Annotations {
×
1226
                        if strings.HasPrefix(key, providerName) {
×
1227
                                patch[key] = nil
×
1228
                        }
×
1229
                }
1230
        }
1231

1232
        for key, value := range annotationsNeedToAdd {
×
1233
                patch[key] = value
×
1234
        }
×
1235

1236
        if len(patch) == 0 {
×
1237
                return pod, nil
×
1238
        }
×
1239

1240
        if err = util.PatchAnnotations(c.config.KubeClient.CoreV1().Pods(pod.Namespace), pod.Name, patch); err != nil {
×
1241
                if k8serrors.IsNotFound(err) {
×
1242
                        return nil, nil
×
1243
                }
×
1244
                klog.Errorf("failed to clean annotations for pod %s/%s: %v", pod.Namespace, pod.Name, err)
×
1245
                return nil, err
×
1246
        }
1247

1248
        if pod, err = c.config.KubeClient.CoreV1().Pods(pod.Namespace).Get(context.TODO(), pod.Name, metav1.GetOptions{}); err != nil {
×
1249
                if k8serrors.IsNotFound(err) {
×
1250
                        return nil, nil
×
1251
                }
×
1252
                klog.Errorf("failed to get pod %s/%s: %v", pod.Namespace, pod.Name, err)
×
1253
                return nil, err
×
1254
        }
1255

1256
        return pod, nil
×
1257
}
1258

1259
func isStatefulSetPod(pod *v1.Pod) (bool, string, types.UID) {
×
1260
        for _, owner := range pod.OwnerReferences {
×
1261
                if owner.Kind == util.StatefulSet && strings.HasPrefix(owner.APIVersion, "apps/") {
×
1262
                        if strings.HasPrefix(pod.Name, owner.Name) {
×
1263
                                return true, owner.Name, owner.UID
×
1264
                        }
×
1265
                }
1266
        }
1267
        return false, "", ""
×
1268
}
1269

1270
func isStatefulSetPodToDel(c kubernetes.Interface, pod *v1.Pod, statefulSetName string, statefulSetUID types.UID) bool {
×
1271
        // only delete statefulset pod lsp when statefulset deleted or down scaled
×
1272
        sts, err := c.AppsV1().StatefulSets(pod.Namespace).Get(context.Background(), statefulSetName, metav1.GetOptions{})
×
1273
        if err != nil {
×
1274
                // statefulset is deleted
×
1275
                if k8serrors.IsNotFound(err) {
×
1276
                        klog.Infof("statefulset %s is deleted", statefulSetName)
×
1277
                        return true
×
1278
                }
×
1279
                klog.Errorf("failed to get statefulset %v", err)
×
1280
                return false
×
1281
        }
1282

1283
        // statefulset is being deleted, or it's a newly created one
1284
        if !sts.DeletionTimestamp.IsZero() || sts.UID != statefulSetUID {
×
1285
                klog.Infof("statefulset %s is being deleted", statefulSetName)
×
1286
                return true
×
1287
        }
×
UNCOV
1288

×
UNCOV
1289
        // down scale statefulset
×
1290
        tempStrs := strings.Split(pod.Name, "-")
×
1291
        numStr := tempStrs[len(tempStrs)-1]
×
1292
        index, err := strconv.ParseInt(numStr, 10, 0)
1293
        if err != nil {
1294
                klog.Errorf("failed to parse %s to int", numStr)
×
1295
                return false
×
1296
        }
×
UNCOV
1297
        // down scaled
×
1298
        var startOrdinal int64
×
1299
        if sts.Spec.Ordinals != nil {
×
1300
                startOrdinal = int64(sts.Spec.Ordinals.Start)
×
1301
        }
1302
        if index >= startOrdinal+int64(*sts.Spec.Replicas) {
×
1303
                klog.Infof("statefulset %s is down scaled", statefulSetName)
×
1304
                return true
×
1305
        }
×
1306
        return false
×
UNCOV
1307
}
×
UNCOV
1308

×
1309
func getNodeTunlIP(node *v1.Node) ([]net.IP, error) {
×
1310
        var nodeTunlIPAddr []net.IP
×
1311
        nodeTunlIP := node.Annotations[util.IPAddressAnnotation]
1312
        if nodeTunlIP == "" {
1313
                return nil, errors.New("node has no tunnel ip annotation")
1314
        }
1315

1316
        for _, ip := range strings.Split(nodeTunlIP, ",") {
1317
                nodeTunlIPAddr = append(nodeTunlIPAddr, net.ParseIP(ip))
×
1318
        }
×
1319
        return nodeTunlIPAddr, nil
×
UNCOV
1320
}
×
UNCOV
1321

×
1322
func getNextHopByTunnelIP(gw []net.IP) string {
×
1323
        // validation check by caller
×
1324
        nextHop := gw[0].String()
×
1325
        if len(gw) == 2 {
×
1326
                nextHop = gw[0].String() + "," + gw[1].String()
×
1327
        }
1328
        return nextHop
1329
}
UNCOV
1330

×
1331
func needAllocateSubnets(pod *v1.Pod, nets []*kubeovnNet) []*kubeovnNet {
×
1332
        // check if allocate from subnet is need.
×
1333
        // allocate subnet when change subnet to hotplug nic
×
1334
        // allocate subnet when migrate vm
1335
        if !isPodAlive(pod) {
×
1336
                return nil
×
1337
        }
×
UNCOV
1338

×
1339
        if pod.Annotations == nil {
1340
                return nets
1341
        }
UNCOV
1342

×
1343
        migrate := false
×
1344
        if job, ok := pod.Annotations[util.MigrationJobAnnotation]; ok {
×
1345
                klog.Infof("pod %s/%s is in the migration job %s", pod.Namespace, pod.Name, job)
×
1346
                migrate = true
×
1347
        }
×
UNCOV
1348

×
1349
        result := make([]*kubeovnNet, 0, len(nets))
1350
        for _, n := range nets {
×
1351
                if migrate || pod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, n.ProviderName)] != "true" {
×
1352
                        result = append(result, n)
×
1353
                }
×
UNCOV
1354
        }
×
1355
        return result
×
UNCOV
1356
}
×
UNCOV
1357

×
1358
func needRestartNatGatewayPod(pod *v1.Pod) bool {
×
1359
        for _, psc := range pod.Status.ContainerStatuses {
×
1360
                if psc.Name != "vpc-nat-gw" {
×
1361
                        continue
×
UNCOV
1362
                }
×
1363
                if psc.RestartCount > 0 {
×
1364
                        return true
×
1365
                }
1366
        }
1367
        return false
×
1368
}
1369

1370
func (c *Controller) podNeedSync(pod *v1.Pod) (bool, error) {
×
1371
        // 1. check annotations
×
1372
        if pod.Annotations == nil {
×
1373
                return true, nil
×
1374
        }
×
UNCOV
1375
        // 2. check annotation ovn subnet
×
1376
        if pod.Annotations[util.RoutedAnnotation] != "true" {
1377
                return true, nil
×
1378
        }
×
UNCOV
1379
        // 3. check multus subnet
×
1380
        attachmentNets, err := c.getPodAttachmentNet(pod)
×
1381
        if err != nil {
1382
                klog.Error(err)
1383
                return false, err
×
1384
        }
×
1385
        for _, n := range attachmentNets {
×
1386
                if pod.Annotations[fmt.Sprintf(util.RoutedAnnotationTemplate, n.ProviderName)] != "true" {
×
1387
                        return true, nil
×
1388
                }
×
1389
                ipName := ovs.PodNameToPortName(pod.Name, pod.Namespace, n.ProviderName)
×
1390
                if _, err = c.ipsLister.Get(ipName); err != nil {
1391
                        err = fmt.Errorf("pod has no ip %s: %w", ipName, err)
1392
                        // need to sync to create ip
×
1393
                        klog.Error(err)
×
1394
                        return true, nil
×
1395
                }
×
UNCOV
1396
        }
×
1397
        return false, nil
×
UNCOV
1398
}
×
1399

1400
func needRouteSubnets(pod *v1.Pod, nets []*kubeovnNet) []*kubeovnNet {
×
1401
        if !isPodAlive(pod) {
×
1402
                return nil
×
1403
        }
UNCOV
1404

×
1405
        if pod.Annotations == nil {
×
1406
                return nets
×
1407
        }
×
UNCOV
1408

×
1409
        result := make([]*kubeovnNet, 0, len(nets))
1410
        for _, n := range nets {
×
1411
                if !isOvnSubnet(n.Subnet) {
×
1412
                        continue
×
UNCOV
1413
                }
×
UNCOV
1414

×
1415
                if pod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, n.ProviderName)] == "true" && pod.Spec.NodeName != "" {
1416
                        if pod.Annotations[fmt.Sprintf(util.RoutedAnnotationTemplate, n.ProviderName)] != "true" {
×
1417
                                result = append(result, n)
1418
                        }
UNCOV
1419
                }
×
UNCOV
1420
        }
×
1421
        return result
×
UNCOV
1422
}
×
1423

1424
func (c *Controller) getPodDefaultSubnet(pod *v1.Pod) (*kubeovnv1.Subnet, error) {
×
1425
        // check pod annotations
×
1426
        if lsName := pod.Annotations[util.LogicalSwitchAnnotation]; lsName != "" {
×
1427
                subnet, err := c.subnetsLister.Get(lsName)
1428
                if err != nil {
×
1429
                        klog.Errorf("failed to get subnet %s: %v", lsName, err)
1430
                        return nil, err
1431
                }
×
1432
                return subnet, nil
×
UNCOV
1433
        }
×
UNCOV
1434

×
1435
        ns, err := c.namespacesLister.Get(pod.Namespace)
×
1436
        if err != nil {
1437
                klog.Errorf("failed to get namespace %s: %v", pod.Namespace, err)
×
1438
                return nil, err
×
1439
        }
×
1440
        if len(ns.Annotations) == 0 {
1441
                err = fmt.Errorf("namespace %s network annotations is empty", ns.Name)
×
1442
                klog.Error(err)
×
1443
                return nil, err
×
1444
        }
×
UNCOV
1445

×
1446
        subnetNames := ns.Annotations[util.LogicalSwitchAnnotation]
×
1447
        for _, subnetName := range strings.Split(subnetNames, ",") {
×
1448
                if subnetName == "" {
×
1449
                        err = fmt.Errorf("namespace %s default logical switch is not found", ns.Name)
×
1450
                        klog.Error(err)
×
1451
                        return nil, err
×
1452
                }
×
1453
                subnet, err := c.subnetsLister.Get(subnetName)
×
1454
                if err != nil {
×
1455
                        klog.Errorf("failed to get subnet %s: %v", subnetName, err)
×
1456
                        return nil, err
×
1457
                }
UNCOV
1458

×
1459
                switch subnet.Spec.Protocol {
1460
                case kubeovnv1.ProtocolDual:
1461
                        if subnet.Status.V6AvailableIPs == 0 {
×
1462
                                klog.Infof("there's no available ipv6 address in subnet %s, try next one", subnet.Name)
×
1463
                                continue
×
UNCOV
1464
                        }
×
1465
                        fallthrough
1466
                case kubeovnv1.ProtocolIPv4:
×
1467
                        if subnet.Status.V4AvailableIPs == 0 {
×
1468
                                klog.Infof("there's no available ipv4 address in subnet %s, try next one", subnet.Name)
×
1469
                                continue
UNCOV
1470
                        }
×
1471
                case kubeovnv1.ProtocolIPv6:
×
1472
                        if subnet.Status.V6AvailableIPs == 0 {
×
1473
                                klog.Infof("there's no available ipv6 address in subnet %s, try next one", subnet.Name)
×
1474
                                continue
1475
                        }
UNCOV
1476
                }
×
1477
                return subnet, nil
×
UNCOV
1478
        }
×
1479
        return nil, ipam.ErrNoAvailable
×
1480
}
1481

1482
func loadNetConf(bytes []byte) (*multustypes.DelegateNetConf, error) {
×
1483
        delegateConf := &multustypes.DelegateNetConf{}
1484
        if err := json.Unmarshal(bytes, &delegateConf.Conf); err != nil {
1485
                return nil, logging.Errorf("LoadDelegateNetConf: error unmarshalling delegate config: %v", err)
×
1486
        }
×
UNCOV
1487

×
1488
        if delegateConf.Conf.Type == "" {
×
1489
                if err := multustypes.LoadDelegateNetConfList(bytes, delegateConf); err != nil {
×
1490
                        return nil, logging.Errorf("LoadDelegateNetConf: failed with: %v", err)
×
1491
                }
×
UNCOV
1492
        }
×
1493
        return delegateConf, nil
×
1494
}
1495

UNCOV
1496
type providerType int
×
UNCOV
1497

×
UNCOV
1498
const (
×
UNCOV
1499
        providerTypeIPAM providerType = iota
×
UNCOV
1500
        providerTypeOriginal
×
UNCOV
1501
)
×
UNCOV
1502

×
UNCOV
1503
type kubeovnNet struct {
×
UNCOV
1504
        Type               providerType
×
UNCOV
1505
        ProviderName       string
×
1506
        Subnet             *kubeovnv1.Subnet
UNCOV
1507
        IsDefault          bool
×
UNCOV
1508
        AllowLiveMigration bool
×
UNCOV
1509
        IPRequest          string
×
UNCOV
1510
        MacRequest         string
×
UNCOV
1511
}
×
UNCOV
1512

×
1513
func (c *Controller) getPodAttachmentNet(pod *v1.Pod) ([]*kubeovnNet, error) {
×
1514
        var multusNets []*nadv1.NetworkSelectionElement
×
1515
        defaultAttachNetworks := pod.Annotations[util.DefaultNetworkAnnotation]
×
1516
        if defaultAttachNetworks != "" {
×
1517
                attachments, err := nadutils.ParseNetworkAnnotation(defaultAttachNetworks, pod.Namespace)
×
1518
                if err != nil {
×
1519
                        klog.Errorf("failed to parse default attach net for pod '%s', %v", pod.Name, err)
1520
                        return nil, err
×
1521
                }
×
1522
                multusNets = attachments
×
UNCOV
1523
        }
×
UNCOV
1524

×
1525
        attachNetworks := pod.Annotations[nadv1.NetworkAttachmentAnnot]
1526
        if attachNetworks != "" {
×
1527
                attachments, err := nadutils.ParseNetworkAnnotation(attachNetworks, pod.Namespace)
×
1528
                if err != nil {
×
1529
                        klog.Errorf("failed to parse attach net for pod '%s', %v", pod.Name, err)
×
1530
                        return nil, err
×
1531
                }
1532
                multusNets = append(multusNets, attachments...)
×
UNCOV
1533
        }
×
1534
        subnets, err := c.subnetsLister.List(labels.Everything())
×
1535
        if err != nil {
×
1536
                return nil, err
1537
        }
UNCOV
1538

×
1539
        result := make([]*kubeovnNet, 0, len(multusNets))
1540
        for _, attach := range multusNets {
×
1541
                networkClient := c.config.AttachNetClient.K8sCniCncfIoV1().NetworkAttachmentDefinitions(attach.Namespace)
1542
                network, err := networkClient.Get(context.Background(), attach.Name, metav1.GetOptions{})
1543
                if err != nil {
×
1544
                        klog.Errorf("failed to get net-attach-def %s, %v", attach.Name, err)
×
1545
                        return nil, err
×
1546
                }
×
UNCOV
1547

×
1548
                netCfg, err := loadNetConf([]byte(network.Spec.Config))
1549
                if err != nil {
×
1550
                        klog.Errorf("failed to load config of net-attach-def %s, %v", attach.Name, err)
×
1551
                        return nil, err
×
1552
                }
×
1553

UNCOV
1554
                // allocate kubeovn network
×
1555
                var providerName string
1556
                if util.IsOvnNetwork(netCfg) {
1557
                        allowLiveMigration := false
1558
                        isDefault := util.IsDefaultNet(pod.Annotations[util.DefaultNetworkAnnotation], attach)
1559

1560
                        providerName = fmt.Sprintf("%s.%s.%s", attach.Name, attach.Namespace, util.OvnProvider)
1561
                        if pod.Annotations[util.MigrationJobAnnotation] != "" {
1562
                                allowLiveMigration = true
1563
                        }
1564

1565
                        subnetName := pod.Annotations[fmt.Sprintf(util.LogicalSwitchAnnotationTemplate, providerName)]
1566
                        if subnetName == "" {
1567
                                for _, subnet := range subnets {
1568
                                        if subnet.Spec.Provider == providerName {
1569
                                                subnetName = subnet.Name
1570
                                                break
1571
                                        }
1572
                                }
1573
                        }
1574
                        var subnet *kubeovnv1.Subnet
×
1575
                        if subnetName == "" {
×
1576
                                subnet, err = c.getPodDefaultSubnet(pod)
×
1577
                                if err != nil {
×
1578
                                        klog.Errorf("failed to pod default subnet, %v", err)
×
1579
                                        return nil, err
×
1580
                                }
×
1581
                        } else {
×
1582
                                subnet, err = c.subnetsLister.Get(subnetName)
×
1583
                                if err != nil {
×
1584
                                        klog.Errorf("failed to get subnet %s, %v", subnetName, err)
1585
                                        return nil, err
1586
                                }
×
UNCOV
1587
                        }
×
UNCOV
1588

×
1589
                        ret := &kubeovnNet{
×
1590
                                Type:               providerTypeOriginal,
×
1591
                                ProviderName:       providerName,
×
1592
                                Subnet:             subnet,
×
1593
                                IsDefault:          isDefault,
×
1594
                                AllowLiveMigration: allowLiveMigration,
1595
                                MacRequest:         attach.MacRequest,
×
1596
                                IPRequest:          strings.Join(attach.IPRequest, ","),
×
1597
                        }
×
1598
                        result = append(result, ret)
×
1599
                } else {
1600
                        providerName = fmt.Sprintf("%s.%s", attach.Name, attach.Namespace)
×
1601
                        for _, subnet := range subnets {
×
1602
                                if subnet.Spec.Provider == providerName {
×
1603
                                        result = append(result, &kubeovnNet{
×
1604
                                                Type:         providerTypeIPAM,
×
1605
                                                ProviderName: providerName,
×
1606
                                                Subnet:       subnet,
×
1607
                                                MacRequest:   attach.MacRequest,
×
1608
                                                IPRequest:    strings.Join(attach.IPRequest, ","),
1609
                                        })
×
1610
                                        break
×
UNCOV
1611
                                }
×
UNCOV
1612
                        }
×
UNCOV
1613
                }
×
1614
        }
1615
        return result, nil
UNCOV
1616
}
×
UNCOV
1617

×
1618
func (c *Controller) validatePodIP(podName, subnetName, ipv4, ipv6 string) (bool, bool, error) {
×
1619
        subnet, err := c.subnetsLister.Get(subnetName)
×
1620
        if err != nil {
×
1621
                klog.Errorf("failed to get subnet %s: %v", subnetName, err)
×
1622
                return false, false, err
×
1623
        }
×
UNCOV
1624

×
1625
        if subnet.Spec.Vlan == "" && subnet.Spec.Vpc == c.config.ClusterRouter {
1626
                nodes, err := c.nodesLister.List(labels.Everything())
×
1627
                if err != nil {
×
1628
                        klog.Errorf("failed to list nodes: %v", err)
×
1629
                        return false, false, err
×
1630
                }
×
UNCOV
1631

×
1632
                for _, node := range nodes {
1633
                        nodeIPv4, nodeIPv6 := util.GetNodeInternalIP(*node)
1634
                        if ipv4 != "" && ipv4 == nodeIPv4 {
1635
                                klog.Errorf("IP address (%s) assigned to pod %s is the same with internal IP address of node %s, reallocating...", ipv4, podName, node.Name)
×
1636
                                return false, true, nil
×
1637
                        }
×
1638
                        if ipv6 != "" && ipv6 == nodeIPv6 {
×
1639
                                klog.Errorf("IP address (%s) assigned to pod %s is the same with internal IP address of node %s, reallocating...", ipv6, podName, node.Name)
×
1640
                                return true, false, nil
×
1641
                        }
×
UNCOV
1642
                }
×
UNCOV
1643
        }
×
UNCOV
1644

×
1645
        return true, true, nil
×
UNCOV
1646
}
×
UNCOV
1647

×
1648
func (c *Controller) acquireAddress(pod *v1.Pod, podNet *kubeovnNet) (string, string, string, *kubeovnv1.Subnet, error) {
1649
        podName := c.getNameByPod(pod)
1650
        key := fmt.Sprintf("%s/%s", pod.Namespace, podName)
×
1651

×
1652
        var checkVMPod bool
×
1653
        isStsPod, _, _ := isStatefulSetPod(pod)
×
1654
        // if pod has static vip
×
1655
        vipName := pod.Annotations[util.VipAnnotation]
×
1656
        if vipName != "" {
×
1657
                vip, err := c.virtualIpsLister.Get(vipName)
×
1658
                if err != nil {
×
1659
                        klog.Errorf("failed to get static vip '%s', %v", vipName, err)
×
1660
                        return "", "", "", podNet.Subnet, err
×
1661
                }
×
1662
                portName := ovs.PodNameToPortName(podName, pod.Namespace, podNet.ProviderName)
×
1663
                if c.config.EnableKeepVMIP {
×
1664
                        checkVMPod, _ = isVMPod(pod)
×
1665
                }
×
1666
                if err = c.podReuseVip(vipName, portName, isStsPod || checkVMPod); err != nil {
×
1667
                        return "", "", "", podNet.Subnet, err
×
1668
                }
×
1669
                return vip.Status.V4ip, vip.Status.V6ip, vip.Status.Mac, podNet.Subnet, nil
×
UNCOV
1670
        }
×
UNCOV
1671

×
1672
        var macPointer *string
1673
        if isOvnSubnet(podNet.Subnet) {
1674
                annoMAC := pod.Annotations[fmt.Sprintf(util.MacAddressAnnotationTemplate, podNet.ProviderName)]
1675
                if annoMAC != "" {
1676
                        if _, err := net.ParseMAC(annoMAC); err != nil {
×
1677
                                return "", "", "", podNet.Subnet, err
1678
                        }
1679
                        macPointer = &annoMAC
×
UNCOV
1680
                }
×
1681
        } else {
×
1682
                macPointer = ptr.To("")
×
1683
        }
×
UNCOV
1684

×
1685
        ippoolStr := pod.Annotations[fmt.Sprintf(util.IPPoolAnnotationTemplate, podNet.ProviderName)]
1686
        if ippoolStr == "" {
×
1687
                ns, err := c.namespacesLister.Get(pod.Namespace)
×
1688
                if err != nil {
×
1689
                        klog.Errorf("failed to get namespace %s: %v", pod.Namespace, err)
×
1690
                        return "", "", "", podNet.Subnet, err
×
1691
                }
×
1692

1693
                if len(ns.Annotations) != 0 {
×
1694
                        if ipPoolList, ok := ns.Annotations[util.IPPoolAnnotation]; ok {
×
1695
                                for _, ipPoolName := range strings.Split(ipPoolList, ",") {
×
1696
                                        ippool, err := c.ippoolLister.Get(ipPoolName)
×
1697
                                        if err != nil {
×
1698
                                                klog.Errorf("failed to get ippool %s: %v", ipPoolName, err)
×
1699
                                                return "", "", "", podNet.Subnet, err
×
1700
                                        }
×
UNCOV
1701

×
1702
                                        switch podNet.Subnet.Spec.Protocol {
×
1703
                                        case kubeovnv1.ProtocolDual:
1704
                                                if ippool.Status.V4AvailableIPs.Int64() == 0 || ippool.Status.V6AvailableIPs.Int64() == 0 {
1705
                                                        continue
UNCOV
1706
                                                }
×
1707
                                        case kubeovnv1.ProtocolIPv4:
1708
                                                if ippool.Status.V4AvailableIPs.Int64() == 0 {
1709
                                                        continue
×
UNCOV
1710
                                                }
×
UNCOV
1711

×
1712
                                        default:
×
1713
                                                if ippool.Status.V6AvailableIPs.Int64() == 0 {
×
1714
                                                        continue
×
UNCOV
1715
                                                }
×
UNCOV
1716
                                        }
×
UNCOV
1717

×
1718
                                        if ippool.Spec.Subnet == podNet.Subnet.Name {
×
1719
                                                ippoolStr = ippool.Name
×
1720
                                                break
×
UNCOV
1721
                                        }
×
UNCOV
1722
                                }
×
UNCOV
1723
                        }
×
UNCOV
1724
                }
×
UNCOV
1725
        }
×
UNCOV
1726

×
UNCOV
1727
        // Random allocate
×
1728
        if pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, podNet.ProviderName)] == "" &&
×
1729
                ippoolStr == "" {
×
1730
                var skippedAddrs []string
×
1731
                for {
1732
                        portName := ovs.PodNameToPortName(podName, pod.Namespace, podNet.ProviderName)
1733

×
1734
                        ipv4, ipv6, mac, err := c.ipam.GetRandomAddress(key, portName, macPointer, podNet.Subnet.Name, "", skippedAddrs, !podNet.AllowLiveMigration)
×
1735
                        if err != nil {
×
1736
                                klog.Error(err)
×
1737
                                return "", "", "", podNet.Subnet, err
×
1738
                        }
×
1739
                        ipv4OK, ipv6OK, err := c.validatePodIP(pod.Name, podNet.Subnet.Name, ipv4, ipv6)
×
1740
                        if err != nil {
×
1741
                                klog.Error(err)
1742
                                return "", "", "", podNet.Subnet, err
×
1743
                        }
×
1744
                        if ipv4OK && ipv6OK {
×
1745
                                return ipv4, ipv6, mac, podNet.Subnet, nil
1746
                        }
×
UNCOV
1747

×
1748
                        if !ipv4OK {
×
1749
                                skippedAddrs = append(skippedAddrs, ipv4)
×
1750
                        }
×
1751
                        if !ipv6OK {
×
1752
                                skippedAddrs = append(skippedAddrs, ipv6)
×
1753
                        }
UNCOV
1754
                }
×
UNCOV
1755
        }
×
UNCOV
1756

×
1757
        portName := ovs.PodNameToPortName(podName, pod.Namespace, podNet.ProviderName)
×
1758

×
1759
        // The static ip can be assigned from any subnet after ns supports multi subnets
×
1760
        nsNets, _ := c.getNsAvailableSubnets(pod, podNet)
×
1761
        var v4IP, v6IP, mac string
×
1762
        var err error
1763

×
1764
        // Static allocate
×
1765
        if pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, podNet.ProviderName)] != "" {
×
1766
                ipStr := pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, podNet.ProviderName)]
×
1767

1768
                for _, net := range nsNets {
×
1769
                        v4IP, v6IP, mac, err = c.acquireStaticAddress(key, portName, ipStr, macPointer, net.Subnet.Name, net.AllowLiveMigration)
×
1770
                        if err == nil {
×
1771
                                return v4IP, v6IP, mac, net.Subnet, nil
1772
                        }
UNCOV
1773
                }
×
1774
                return v4IP, v6IP, mac, podNet.Subnet, err
×
UNCOV
1775
        }
×
1776

1777
        // IPPool allocate
1778
        if ippoolStr != "" {
1779
                var ipPool []string
×
1780
                if strings.ContainsRune(ippoolStr, ';') {
×
1781
                        ipPool = strings.Split(ippoolStr, ";")
×
1782
                } else {
1783
                        ipPool = strings.Split(ippoolStr, ",")
1784
                        if len(ipPool) == 2 && util.CheckProtocol(ipPool[0]) != util.CheckProtocol(ipPool[1]) {
1785
                                ipPool = []string{ippoolStr}
1786
                        }
1787
                }
1788
                for i, ip := range ipPool {
1789
                        ipPool[i] = strings.TrimSpace(ip)
×
1790
                }
×
UNCOV
1791

×
1792
                if len(ipPool) == 1 && (!strings.ContainsRune(ipPool[0], ',') && net.ParseIP(ipPool[0]) == nil) {
×
1793
                        var skippedAddrs []string
×
1794
                        for {
×
1795
                                portName := ovs.PodNameToPortName(podName, pod.Namespace, podNet.ProviderName)
×
1796
                                ipv4, ipv6, mac, err := c.ipam.GetRandomAddress(key, portName, macPointer, podNet.Subnet.Name, ipPool[0], skippedAddrs, !podNet.AllowLiveMigration)
×
1797
                                if err != nil {
×
1798
                                        klog.Error(err)
×
1799
                                        return "", "", "", podNet.Subnet, err
×
1800
                                }
×
1801
                                ipv4OK, ipv6OK, err := c.validatePodIP(pod.Name, podNet.Subnet.Name, ipv4, ipv6)
×
1802
                                if err != nil {
×
1803
                                        klog.Error(err)
×
1804
                                        return "", "", "", podNet.Subnet, err
×
1805
                                }
×
1806
                                if ipv4OK && ipv6OK {
×
1807
                                        return ipv4, ipv6, mac, podNet.Subnet, nil
×
1808
                                }
UNCOV
1809

×
1810
                                if !ipv4OK {
×
1811
                                        skippedAddrs = append(skippedAddrs, ipv4)
×
1812
                                }
×
1813
                                if !ipv6OK {
×
1814
                                        skippedAddrs = append(skippedAddrs, ipv6)
×
1815
                                }
1816
                        }
1817
                }
UNCOV
1818

×
1819
                if !isStsPod {
×
1820
                        for _, net := range nsNets {
×
1821
                                for _, staticIP := range ipPool {
×
1822
                                        var checkIP string
×
1823
                                        ipProtocol := util.CheckProtocol(staticIP)
×
1824
                                        if ipProtocol == kubeovnv1.ProtocolDual {
×
1825
                                                checkIP = strings.Split(staticIP, ",")[0]
×
1826
                                        } else {
×
1827
                                                checkIP = staticIP
×
1828
                                        }
×
UNCOV
1829

×
1830
                                        if assignedPod, ok := c.ipam.IsIPAssignedToOtherPod(checkIP, net.Subnet.Name, key); ok {
×
1831
                                                klog.Errorf("static address %s for %s has been assigned to %s", staticIP, key, assignedPod)
×
1832
                                                continue
×
UNCOV
1833
                                        }
×
1834

1835
                                        v4IP, v6IP, mac, err = c.acquireStaticAddress(key, portName, staticIP, macPointer, net.Subnet.Name, net.AllowLiveMigration)
×
1836
                                        if err == nil {
1837
                                                return v4IP, v6IP, mac, net.Subnet, nil
1838
                                        }
UNCOV
1839
                                }
×
UNCOV
1840
                        }
×
1841
                        klog.Errorf("acquire address from ippool %s for %s failed, %v", ippoolStr, key, err)
×
1842
                } else {
×
1843
                        tempStrs := strings.Split(pod.Name, "-")
×
1844
                        numStr := tempStrs[len(tempStrs)-1]
×
1845
                        index, _ := strconv.Atoi(numStr)
×
1846

×
1847
                        if index < len(ipPool) {
×
1848
                                for _, net := range nsNets {
1849
                                        v4IP, v6IP, mac, err = c.acquireStaticAddress(key, portName, ipPool[index], macPointer, net.Subnet.Name, net.AllowLiveMigration)
×
1850
                                        if err == nil {
×
1851
                                                return v4IP, v6IP, mac, net.Subnet, nil
×
1852
                                        }
UNCOV
1853
                                }
×
1854
                                klog.Errorf("acquire address %s for %s failed, %v", ipPool[index], key, err)
×
UNCOV
1855
                        }
×
UNCOV
1856
                }
×
UNCOV
1857
        }
×
1858
        klog.Errorf("allocate address for %s failed, return NoAvailableAddress", key)
×
1859
        return "", "", "", podNet.Subnet, ipam.ErrNoAvailable
×
UNCOV
1860
}
×
UNCOV
1861

×
1862
func (c *Controller) acquireStaticAddress(key, nicName, ip string, mac *string, subnet string, liveMigration bool) (string, string, string, error) {
×
1863
        var v4IP, v6IP, macStr string
×
1864
        var err error
×
1865
        for _, ipStr := range strings.Split(ip, ",") {
×
1866
                if net.ParseIP(ipStr) == nil {
×
1867
                        return "", "", "", fmt.Errorf("failed to parse IP %s", ipStr)
×
1868
                }
×
UNCOV
1869
        }
×
1870

1871
        if v4IP, v6IP, macStr, err = c.ipam.GetStaticAddress(key, nicName, ip, mac, subnet, !liveMigration); err != nil {
×
1872
                klog.Errorf("failed to get static ip %v, mac %v, subnet %v, err %v", ip, mac, subnet, err)
×
1873
                return "", "", "", err
×
1874
        }
×
1875
        return v4IP, v6IP, macStr, nil
×
UNCOV
1876
}
×
1877

1878
func appendCheckPodToDel(c *Controller, pod *v1.Pod, ownerRefName, ownerRefKind string) (bool, error) {
1879
        // subnet for ns has been changed, and statefulset pod's ip is not in the range of subnet's cidr anymore
1880
        podNs, err := c.namespacesLister.Get(pod.Namespace)
×
1881
        if err != nil {
×
1882
                klog.Errorf("failed to get namespace %s, %v", pod.Namespace, err)
×
1883
                return false, err
×
1884
        }
×
UNCOV
1885

×
UNCOV
1886
        // check if subnet exist in OwnerReference
×
1887
        var ownerRefSubnetExist bool
×
1888
        var ownerRefSubnet string
×
1889
        switch ownerRefKind {
×
1890
        case util.StatefulSet:
1891
                ss, err := c.config.KubeClient.AppsV1().StatefulSets(pod.Namespace).Get(context.Background(), ownerRefName, metav1.GetOptions{})
×
1892
                if err != nil {
×
1893
                        if k8serrors.IsNotFound(err) {
×
1894
                                klog.Infof("Statefulset %s is not found", ownerRefName)
1895
                                return true, nil
1896
                        }
×
1897
                        klog.Errorf("failed to get StatefulSet %s, %v", ownerRefName, err)
×
UNCOV
1898
                }
×
1899
                if ss.Spec.Template.Annotations[util.LogicalSwitchAnnotation] != "" {
×
1900
                        ownerRefSubnetExist = true
1901
                        ownerRefSubnet = ss.Spec.Template.Annotations[util.LogicalSwitchAnnotation]
1902
                }
×
UNCOV
1903

×
1904
        case util.VMInstance:
×
1905
                vm, err := c.config.KubevirtClient.VirtualMachine(pod.Namespace).Get(context.Background(), ownerRefName, metav1.GetOptions{})
×
1906
                if err != nil {
×
1907
                        if k8serrors.IsNotFound(err) {
×
1908
                                klog.Infof("VirtualMachine %s is not found", ownerRefName)
×
1909
                                return true, nil
×
1910
                        }
×
1911
                        klog.Errorf("failed to get VirtualMachine %s, %v", ownerRefName, err)
×
UNCOV
1912
                }
×
1913
                if vm != nil &&
×
1914
                        vm.Spec.Template != nil &&
1915
                        vm.Spec.Template.ObjectMeta.Annotations != nil &&
×
1916
                        vm.Spec.Template.ObjectMeta.Annotations[util.LogicalSwitchAnnotation] != "" {
1917
                        ownerRefSubnetExist = true
1918
                        ownerRefSubnet = vm.Spec.Template.ObjectMeta.Annotations[util.LogicalSwitchAnnotation]
1919
                }
×
UNCOV
1920
        }
×
1921
        podSwitch := strings.TrimSpace(pod.Annotations[util.LogicalSwitchAnnotation])
1922
        if !ownerRefSubnetExist {
1923
                nsSubnetNames := podNs.Annotations[util.LogicalSwitchAnnotation]
×
1924
                // check if pod use the subnet of its ns
×
1925
                if nsSubnetNames != "" && podSwitch != "" && !slices.Contains(strings.Split(nsSubnetNames, ","), podSwitch) {
×
1926
                        klog.Infof("ns %s annotation subnet is %s, which is inconstant with subnet for pod %s, delete pod", pod.Namespace, nsSubnetNames, pod.Name)
×
1927
                        return true, nil
×
1928
                }
×
UNCOV
1929
        }
×
1930

1931
        // subnet cidr has been changed, and statefulset pod's ip is not in the range of subnet's cidr anymore
1932
        podSubnet, err := c.subnetsLister.Get(podSwitch)
×
1933
        if err != nil {
×
1934
                klog.Errorf("failed to get subnet %s, %v, not auto clean ip", podSwitch, err)
×
1935
                return false, err
×
1936
        }
×
1937
        if podSubnet == nil {
1938
                // TODO: remove: CRD get interface will retrun a nil subnet ?
1939
                klog.Errorf("pod %s/%s subnet %s is nil, not auto clean ip", pod.Namespace, pod.Name, podSwitch)
×
1940
                return false, nil
×
1941
        }
×
1942
        podIP := pod.Annotations[util.IPAddressAnnotation]
×
1943
        if podIP == "" {
×
1944
                // delete pod just after it created < 1ms
×
1945
                klog.Infof("pod %s/%s annotaions has no ip address, not auto clean ip", pod.Namespace, pod.Name)
×
1946
                return false, nil
1947
        }
1948
        podSubnetCidr := podSubnet.Spec.CIDRBlock
×
1949
        if podSubnetCidr != "" {
×
1950
                // subnet spec cidr changed by user
×
1951
                klog.Errorf("invalid pod subnet %s empty cidr %s, not auto clean ip", podSwitch, podSubnetCidr)
×
1952
                return false, nil
×
1953
        }
×
1954
        if !util.CIDRContainIP(podSubnetCidr, podIP) {
×
1955
                klog.Infof("pod's ip %s is not in the range of subnet %s, delete pod", pod.Annotations[util.IPAddressAnnotation], podSubnet.Name)
×
1956
                return true, nil
×
1957
        }
×
UNCOV
1958
        // subnet of ownerReference(sts/vm) has been changed, it needs to handle delete pod and create port on the new logical switch
×
1959
        if ownerRefSubnet != "" && podSubnet.Name != ownerRefSubnet {
1960
                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)
×
1961
                return true, nil
×
1962
        }
×
UNCOV
1963

×
1964
        return false, nil
UNCOV
1965
}
×
UNCOV
1966

×
1967
func isVMPod(pod *v1.Pod) (bool, string) {
×
1968
        for _, owner := range pod.OwnerReferences {
×
1969
                // The name of vmi is consistent with vm's name.
×
1970
                if owner.Kind == util.VMInstance && strings.HasPrefix(owner.APIVersion, "kubevirt.io") {
×
1971
                        return true, owner.Name
×
1972
                }
×
1973
        }
1974
        return false, ""
×
UNCOV
1975
}
×
UNCOV
1976

×
1977
func isOwnsByTheVM(vmi metav1.Object) (bool, string) {
×
1978
        for _, owner := range vmi.GetOwnerReferences() {
×
1979
                if owner.Kind == util.VM && strings.HasPrefix(owner.APIVersion, "kubevirt.io") {
×
1980
                        return true, owner.Name
×
1981
                }
UNCOV
1982
        }
×
1983
        return false, ""
×
UNCOV
1984
}
×
UNCOV
1985

×
1986
func (c *Controller) isVMToDel(pod *v1.Pod, vmiName string) bool {
×
1987
        var (
×
1988
                vmiAlive bool
×
1989
                vmName   string
×
1990
        )
1991
        // The vmi is also deleted when pod is deleted, only left vm exists.
1992
        vmi, err := c.config.KubevirtClient.VirtualMachineInstance(pod.Namespace).Get(context.Background(), vmiName, metav1.GetOptions{})
1993
        if err != nil {
×
1994
                if k8serrors.IsNotFound(err) {
×
1995
                        vmiAlive = false
×
1996
                        // The name of vmi is consistent with vm's name.
×
1997
                        vmName = vmiName
×
1998
                        klog.ErrorS(err, "failed to get vmi, will try to get the vm directly", "name", vmiName)
×
1999
                } else {
×
2000
                        klog.ErrorS(err, "failed to get vmi", "name", vmiName)
×
2001
                        return false
×
2002
                }
×
2003
        } else {
×
2004
                var ownsByVM bool
×
2005
                ownsByVM, vmName = isOwnsByTheVM(vmi)
×
2006
                if !ownsByVM && !vmi.DeletionTimestamp.IsZero() {
×
2007
                        klog.Infof("ephemeral vmi %s is deleting", vmiName)
×
2008
                        return true
×
2009
                }
×
2010
                vmiAlive = vmi.DeletionTimestamp.IsZero()
×
UNCOV
2011
        }
×
UNCOV
2012

×
2013
        if vmiAlive {
×
2014
                return false
×
2015
        }
×
UNCOV
2016

×
2017
        vm, err := c.config.KubevirtClient.VirtualMachine(pod.Namespace).Get(context.Background(), vmName, metav1.GetOptions{})
×
2018
        if err != nil {
×
2019
                // the vm has gone
2020
                if k8serrors.IsNotFound(err) {
×
2021
                        klog.ErrorS(err, "failed to get vm", "name", vmName)
×
2022
                        return true
×
2023
                }
×
2024
                klog.ErrorS(err, "failed to get vm", "name", vmName)
2025
                return false
×
2026
        }
2027

2028
        if !vm.DeletionTimestamp.IsZero() {
×
2029
                klog.Infof("vm %s is deleting", vmName)
×
2030
                return true
×
2031
        }
×
2032
        return false
×
UNCOV
2033
}
×
2034

2035
func (c *Controller) getNameByPod(pod *v1.Pod) string {
×
2036
        if c.config.EnableKeepVMIP {
2037
                if isVMPod, vmName := isVMPod(pod); isVMPod {
2038
                        return vmName
×
2039
                }
×
UNCOV
2040
        }
×
2041
        return pod.Name
×
UNCOV
2042
}
×
2043

UNCOV
2044
// 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.
×
2045
func (c *Controller) getNsAvailableSubnets(pod *v1.Pod, podNet *kubeovnNet) ([]*kubeovnNet, error) {
2046
        var result []*kubeovnNet
2047
        // keep the annotation subnet of the pod in first position
×
2048
        result = append(result, podNet)
×
2049

×
2050
        ns, err := c.namespacesLister.Get(pod.Namespace)
×
2051
        if err != nil {
×
2052
                klog.Errorf("failed to get namespace %s, %v", pod.Namespace, err)
×
2053
                return nil, err
×
2054
        }
×
2055
        if ns.Annotations == nil {
×
2056
                return nil, nil
×
2057
        }
×
UNCOV
2058

×
2059
        subnetNames := ns.Annotations[util.LogicalSwitchAnnotation]
×
2060
        for _, subnetName := range strings.Split(subnetNames, ",") {
×
2061
                if subnetName == "" || subnetName == podNet.Subnet.Name {
×
2062
                        continue
×
UNCOV
2063
                }
×
2064
                subnet, err := c.subnetsLister.Get(subnetName)
×
2065
                if err != nil {
×
2066
                        klog.Errorf("failed to get subnet %v", err)
×
2067
                        return nil, err
×
2068
                }
×
UNCOV
2069

×
2070
                result = append(result, &kubeovnNet{
×
2071
                        Type:         providerTypeOriginal,
×
2072
                        ProviderName: subnet.Spec.Provider,
2073
                        Subnet:       subnet,
2074
                })
×
UNCOV
2075
        }
×
UNCOV
2076

×
2077
        return result, nil
UNCOV
2078
}
×
UNCOV
2079

×
2080
func getPodType(pod *v1.Pod) string {
×
2081
        if ok, _, _ := isStatefulSetPod(pod); ok {
×
2082
                return util.StatefulSet
×
2083
        }
×
UNCOV
2084

×
2085
        if isVMPod, _ := isVMPod(pod); isVMPod {
×
2086
                return util.VM
×
2087
        }
2088
        return ""
UNCOV
2089
}
×
UNCOV
2090

×
2091
func (c *Controller) getVirtualIPs(pod *v1.Pod, podNets []*kubeovnNet) map[string]string {
×
2092
        vipsListMap := make(map[string][]string)
×
2093
        var vipNamesList []string
×
2094
        for _, vipName := range strings.Split(strings.TrimSpace(pod.Annotations[util.AAPsAnnotation]), ",") {
2095
                if vipName = strings.TrimSpace(vipName); vipName == "" {
2096
                        continue
×
UNCOV
2097
                }
×
2098
                if !slices.Contains(vipNamesList, vipName) {
×
2099
                        vipNamesList = append(vipNamesList, vipName)
×
2100
                } else {
×
2101
                        continue
UNCOV
2102
                }
×
2103
                vip, err := c.virtualIpsLister.Get(vipName)
2104
                if err != nil {
2105
                        klog.Errorf("failed to get vip %s, %v", vipName, err)
2106
                        continue
×
UNCOV
2107
                }
×
2108
                if vip.Spec.Namespace != pod.Namespace || (vip.Status.V4ip == "" && vip.Status.V6ip == "") {
×
2109
                        continue
×
UNCOV
2110
                }
×
2111
                for _, podNet := range podNets {
×
2112
                        if podNet.Subnet.Name == vip.Spec.Subnet {
×
2113
                                key := fmt.Sprintf("%s.%s", podNet.Subnet.Name, podNet.ProviderName)
×
2114
                                vipsList := vipsListMap[key]
×
2115
                                if vipsList == nil {
×
2116
                                        vipsList = []string{}
×
2117
                                }
×
UNCOV
2118
                                // ipam will ensure the uniqueness of VIP
×
2119
                                if util.IsValidIP(vip.Status.V4ip) {
2120
                                        vipsList = append(vipsList, vip.Status.V4ip)
×
2121
                                }
×
2122
                                if util.IsValidIP(vip.Status.V6ip) {
×
2123
                                        vipsList = append(vipsList, vip.Status.V6ip)
×
2124
                                }
UNCOV
2125

×
2126
                                vipsListMap[key] = vipsList
×
UNCOV
2127
                        }
×
UNCOV
2128
                }
×
UNCOV
2129
        }
×
2130

2131
        for _, podNet := range podNets {
×
2132
                vipStr := pod.Annotations[fmt.Sprintf(util.PortVipAnnotationTemplate, podNet.ProviderName)]
×
2133
                if vipStr == "" {
×
2134
                        continue
×
UNCOV
2135
                }
×
2136
                key := fmt.Sprintf("%s.%s", podNet.Subnet.Name, podNet.ProviderName)
2137
                vipsList := vipsListMap[key]
2138
                if vipsList == nil {
×
2139
                        vipsList = []string{}
2140
                }
UNCOV
2141

×
2142
                for _, vip := range strings.Split(vipStr, ",") {
×
2143
                        if util.IsValidIP(vip) && !slices.Contains(vipsList, vip) {
×
2144
                                vipsList = append(vipsList, vip)
×
2145
                        }
UNCOV
2146
                }
×
UNCOV
2147

×
2148
                vipsListMap[key] = vipsList
×
UNCOV
2149
        }
×
2150

2151
        vipsMap := make(map[string]string)
2152
        for key, vipsList := range vipsListMap {
×
2153
                vipsMap[key] = strings.Join(vipsList, ",")
×
2154
        }
×
2155
        return vipsMap
×
UNCOV
2156
}
×
UNCOV
2157

×
2158
func setPodRoutesAnnotation(annotations map[string]string, provider string, routes []request.Route) error {
2159
        key := fmt.Sprintf(util.RoutesAnnotationTemplate, provider)
×
2160
        if len(routes) == 0 {
×
2161
                delete(annotations, key)
×
2162
                return nil
×
2163
        }
UNCOV
2164

×
2165
        buf, err := json.Marshal(routes)
×
2166
        if err != nil {
×
2167
                err = fmt.Errorf("failed to marshal routes %+v: %w", routes, err)
×
2168
                klog.Error(err)
2169
                return err
×
2170
        }
×
2171
        annotations[key] = string(buf)
2172

×
2173
        return nil
×
UNCOV
2174
}
×
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